1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_event.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevextern int            ngx_eventfd;
14e18a033bSKonstantin Ananyevextern aio_context_t  ngx_aio_ctx;
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyev
17e18a033bSKonstantin Ananyevstatic void ngx_file_aio_event_handler(ngx_event_t *ev);
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyev
20e18a033bSKonstantin Ananyevstatic int
21e18a033bSKonstantin Ananyevio_submit(aio_context_t ctx, long n, struct iocb **paiocb)
22e18a033bSKonstantin Ananyev{
23e18a033bSKonstantin Ananyev    return syscall(SYS_io_submit, ctx, n, paiocb);
24e18a033bSKonstantin Ananyev}
25e18a033bSKonstantin Ananyev
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyevngx_int_t
28e18a033bSKonstantin Ananyevngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool)
29e18a033bSKonstantin Ananyev{
30e18a033bSKonstantin Ananyev    ngx_event_aio_t  *aio;
31e18a033bSKonstantin Ananyev
32e18a033bSKonstantin Ananyev    aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
33e18a033bSKonstantin Ananyev    if (aio == NULL) {
34e18a033bSKonstantin Ananyev        return NGX_ERROR;
35e18a033bSKonstantin Ananyev    }
36e18a033bSKonstantin Ananyev
37e18a033bSKonstantin Ananyev    aio->file = file;
38e18a033bSKonstantin Ananyev    aio->fd = file->fd;
39e18a033bSKonstantin Ananyev    aio->event.data = aio;
40e18a033bSKonstantin Ananyev    aio->event.ready = 1;
41e18a033bSKonstantin Ananyev    aio->event.log = file->log;
42e18a033bSKonstantin Ananyev
43e18a033bSKonstantin Ananyev    file->aio = aio;
44e18a033bSKonstantin Ananyev
45e18a033bSKonstantin Ananyev    return NGX_OK;
46e18a033bSKonstantin Ananyev}
47e18a033bSKonstantin Ananyev
48e18a033bSKonstantin Ananyev
49e18a033bSKonstantin Ananyevssize_t
50e18a033bSKonstantin Ananyevngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
51e18a033bSKonstantin Ananyev    ngx_pool_t *pool)
52e18a033bSKonstantin Ananyev{
53e18a033bSKonstantin Ananyev    ngx_err_t         err;
54e18a033bSKonstantin Ananyev    struct iocb      *piocb[1];
55e18a033bSKonstantin Ananyev    ngx_event_t      *ev;
56e18a033bSKonstantin Ananyev    ngx_event_aio_t  *aio;
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyev    if (!ngx_file_aio) {
59e18a033bSKonstantin Ananyev        return ngx_read_file(file, buf, size, offset);
60e18a033bSKonstantin Ananyev    }
61e18a033bSKonstantin Ananyev
62e18a033bSKonstantin Ananyev    if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) {
63e18a033bSKonstantin Ananyev        return NGX_ERROR;
64e18a033bSKonstantin Ananyev    }
65e18a033bSKonstantin Ananyev
66e18a033bSKonstantin Ananyev    aio = file->aio;
67e18a033bSKonstantin Ananyev    ev = &aio->event;
68e18a033bSKonstantin Ananyev
69e18a033bSKonstantin Ananyev    if (!ev->ready) {
70e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ALERT, file->log, 0,
71e18a033bSKonstantin Ananyev                      "second aio post for \"%V\"", &file->name);
72e18a033bSKonstantin Ananyev        return NGX_AGAIN;
73e18a033bSKonstantin Ananyev    }
74e18a033bSKonstantin Ananyev
75e18a033bSKonstantin Ananyev    ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
76e18a033bSKonstantin Ananyev                   "aio complete:%d @%O:%uz %V",
77e18a033bSKonstantin Ananyev                   ev->complete, offset, size, &file->name);
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyev    if (ev->complete) {
80e18a033bSKonstantin Ananyev        ev->active = 0;
81e18a033bSKonstantin Ananyev        ev->complete = 0;
82e18a033bSKonstantin Ananyev
83e18a033bSKonstantin Ananyev        if (aio->res >= 0) {
84e18a033bSKonstantin Ananyev            ngx_set_errno(0);
85e18a033bSKonstantin Ananyev            return aio->res;
86e18a033bSKonstantin Ananyev        }
87e18a033bSKonstantin Ananyev
88e18a033bSKonstantin Ananyev        ngx_set_errno(-aio->res);
89e18a033bSKonstantin Ananyev
90e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
91e18a033bSKonstantin Ananyev                      "aio read \"%s\" failed", file->name.data);
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyev        return NGX_ERROR;
94e18a033bSKonstantin Ananyev    }
95e18a033bSKonstantin Ananyev
96e18a033bSKonstantin Ananyev    ngx_memzero(&aio->aiocb, sizeof(struct iocb));
97e18a033bSKonstantin Ananyev
98e18a033bSKonstantin Ananyev    aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev;
99e18a033bSKonstantin Ananyev    aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD;
100e18a033bSKonstantin Ananyev    aio->aiocb.aio_fildes = file->fd;
101e18a033bSKonstantin Ananyev    aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf;
102e18a033bSKonstantin Ananyev    aio->aiocb.aio_nbytes = size;
103e18a033bSKonstantin Ananyev    aio->aiocb.aio_offset = offset;
104e18a033bSKonstantin Ananyev    aio->aiocb.aio_flags = IOCB_FLAG_RESFD;
105e18a033bSKonstantin Ananyev    aio->aiocb.aio_resfd = ngx_eventfd;
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev    ev->handler = ngx_file_aio_event_handler;
108e18a033bSKonstantin Ananyev
109e18a033bSKonstantin Ananyev    piocb[0] = &aio->aiocb;
110e18a033bSKonstantin Ananyev
111e18a033bSKonstantin Ananyev    if (io_submit(ngx_aio_ctx, 1, piocb) == 1) {
112e18a033bSKonstantin Ananyev        ev->active = 1;
113e18a033bSKonstantin Ananyev        ev->ready = 0;
114e18a033bSKonstantin Ananyev        ev->complete = 0;
115e18a033bSKonstantin Ananyev
116e18a033bSKonstantin Ananyev        return NGX_AGAIN;
117e18a033bSKonstantin Ananyev    }
118e18a033bSKonstantin Ananyev
119e18a033bSKonstantin Ananyev    err = ngx_errno;
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyev    if (err == NGX_EAGAIN) {
122e18a033bSKonstantin Ananyev        return ngx_read_file(file, buf, size, offset);
123e18a033bSKonstantin Ananyev    }
124e18a033bSKonstantin Ananyev
125e18a033bSKonstantin Ananyev    ngx_log_error(NGX_LOG_CRIT, file->log, err,
126e18a033bSKonstantin Ananyev                  "io_submit(\"%V\") failed", &file->name);
127e18a033bSKonstantin Ananyev
128e18a033bSKonstantin Ananyev    if (err == NGX_ENOSYS) {
129e18a033bSKonstantin Ananyev        ngx_file_aio = 0;
130e18a033bSKonstantin Ananyev        return ngx_read_file(file, buf, size, offset);
131e18a033bSKonstantin Ananyev    }
132e18a033bSKonstantin Ananyev
133e18a033bSKonstantin Ananyev    return NGX_ERROR;
134e18a033bSKonstantin Ananyev}
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyev
137e18a033bSKonstantin Ananyevstatic void
138e18a033bSKonstantin Ananyevngx_file_aio_event_handler(ngx_event_t *ev)
139e18a033bSKonstantin Ananyev{
140e18a033bSKonstantin Ananyev    ngx_event_aio_t  *aio;
141e18a033bSKonstantin Ananyev
142e18a033bSKonstantin Ananyev    aio = ev->data;
143e18a033bSKonstantin Ananyev
144e18a033bSKonstantin Ananyev    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
145e18a033bSKonstantin Ananyev                   "aio event handler fd:%d %V", aio->fd, &aio->file->name);
146e18a033bSKonstantin Ananyev
147e18a033bSKonstantin Ananyev    aio->handler(ev);
148e18a033bSKonstantin Ananyev}
149