Mercurial > hg > nginx-vendor-0-8
comparison src/os/unix/ngx_file_aio_read.c @ 518:86dad910eeb6 NGINX_0_8_11
nginx 0.8.11
*) Change: directive "gzip_disable msie6" enables gzipping for
MSIE 6.0 SV1.
*) Feature: file AIO support on FreeBSD and Linux.
*) Feature: the "directio_alignment" directive.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Fri, 28 Aug 2009 00:00:00 +0400 |
parents | |
children | d41628eb4d0a |
comparison
equal
deleted
inserted
replaced
517:15b5cddc5190 | 518:86dad910eeb6 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 | |
11 | |
12 /* | |
13 * FreeBSD file AIO features and quirks: | |
14 * | |
15 * if an asked data are already in VM cache, then aio_error() returns 0, | |
16 * and the data are already copied in buffer; | |
17 * | |
18 * aio_read() preread in VM cache as minimum 32K; | |
19 * | |
20 * aio_read/aio_error() may return EINPROGRESS for just written data; | |
21 * | |
22 * kqueue EVFILT_AIO filter is level triggered only: an event repeats | |
23 * until aio_return() will be called; | |
24 * | |
25 * aio_cancel() can not cancel file AIO: it returns AIO_NOTCANCELED always. | |
26 */ | |
27 | |
28 | |
29 extern int ngx_kqueue; | |
30 | |
31 | |
32 static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, | |
33 ngx_event_t *ev); | |
34 static void ngx_file_aio_event_handler(ngx_event_t *ev); | |
35 | |
36 | |
37 ssize_t | |
38 ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, | |
39 ngx_pool_t *pool) | |
40 { | |
41 int n; | |
42 ngx_event_t *ev; | |
43 ngx_event_aio_t *aio; | |
44 static ngx_uint_t enosys = 0; | |
45 | |
46 if (enosys) { | |
47 return ngx_read_file(file, buf, size, offset); | |
48 } | |
49 | |
50 aio = file->aio; | |
51 | |
52 if (aio == NULL) { | |
53 aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t)); | |
54 if (aio == NULL) { | |
55 return NGX_ERROR; | |
56 } | |
57 | |
58 aio->file = file; | |
59 aio->fd = file->fd; | |
60 aio->event.data = aio; | |
61 aio->event.ready = 1; | |
62 aio->event.log = file->log; | |
63 file->aio = aio; | |
64 } | |
65 | |
66 ev = &aio->event; | |
67 | |
68 if (!ev->ready) { | |
69 ngx_log_error(NGX_LOG_ALERT, file->log, 0, | |
70 "second aio post for \"%V\"", &file->name); | |
71 return NGX_AGAIN; | |
72 } | |
73 | |
74 ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, | |
75 "aio complete:%d @%O:%z %V", | |
76 ev->complete, offset, size, &file->name); | |
77 | |
78 if (ev->complete) { | |
79 ev->complete = 0; | |
80 ngx_set_errno(aio->err); | |
81 | |
82 if (aio->err == 0) { | |
83 return aio->nbytes; | |
84 } | |
85 | |
86 return NGX_ERROR; | |
87 } | |
88 | |
89 ngx_memzero(&aio->aiocb, sizeof(struct aiocb)); | |
90 | |
91 aio->aiocb.aio_fildes = file->fd; | |
92 aio->aiocb.aio_offset = offset; | |
93 aio->aiocb.aio_buf = buf; | |
94 aio->aiocb.aio_nbytes = size; | |
95 #if (NGX_HAVE_KQUEUE) | |
96 aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; | |
97 aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; | |
98 aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev; | |
99 #endif | |
100 ev->handler = ngx_file_aio_event_handler; | |
101 | |
102 n = aio_read(&aio->aiocb); | |
103 | |
104 if (n == -1) { | |
105 n = ngx_errno; | |
106 | |
107 if (n == NGX_EAGAIN) { | |
108 return ngx_read_file(file, buf, size, offset); | |
109 } | |
110 | |
111 ngx_log_error(NGX_LOG_CRIT, file->log, n, | |
112 "aio_read(\"%V\") failed", &file->name); | |
113 | |
114 if (n == NGX_ENOSYS) { | |
115 enosys = 1; | |
116 return ngx_read_file(file, buf, size, offset); | |
117 } | |
118 | |
119 return NGX_ERROR; | |
120 } | |
121 | |
122 ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, | |
123 "aio_read: fd:%d %d", file->fd, n); | |
124 | |
125 ev->active = 1; | |
126 ev->ready = 0; | |
127 ev->complete = 0; | |
128 | |
129 return ngx_file_aio_result(aio->file, aio, ev); | |
130 } | |
131 | |
132 | |
133 static ssize_t | |
134 ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev) | |
135 { | |
136 int n; | |
137 ngx_err_t err; | |
138 | |
139 n = aio_error(&aio->aiocb); | |
140 | |
141 ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, | |
142 "aio_error: fd:%d %d", file->fd, n); | |
143 | |
144 if (n == -1) { | |
145 err = ngx_errno; | |
146 aio->err = err; | |
147 | |
148 ngx_log_error(NGX_LOG_ALERT, file->log, err, | |
149 "aio_error(\"%V\") failed", &file->name); | |
150 return NGX_ERROR; | |
151 } | |
152 | |
153 if (n != 0) { | |
154 if (n == NGX_EINPROGRESS) { | |
155 if (ev->ready) { | |
156 ev->ready = 0; | |
157 ngx_log_error(NGX_LOG_ALERT, file->log, n, | |
158 "aio_read(\"%V\") still in progress", | |
159 &file->name); | |
160 } | |
161 | |
162 return NGX_AGAIN; | |
163 } | |
164 | |
165 aio->err = n; | |
166 ev->ready = 0; | |
167 | |
168 ngx_log_error(NGX_LOG_CRIT, file->log, n, | |
169 "aio_read(\"%V\") failed", &file->name); | |
170 return NGX_ERROR; | |
171 } | |
172 | |
173 n = aio_return(&aio->aiocb); | |
174 | |
175 if (n == -1) { | |
176 err = ngx_errno; | |
177 aio->err = err; | |
178 ev->ready = 0; | |
179 | |
180 ngx_log_error(NGX_LOG_ALERT, file->log, err, | |
181 "aio_return(\"%V\") failed", &file->name); | |
182 return NGX_ERROR; | |
183 } | |
184 | |
185 aio->err = 0; | |
186 aio->nbytes = n; | |
187 ev->ready = 1; | |
188 ev->active = 0; | |
189 | |
190 ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, | |
191 "aio_return: fd:%d %d", file->fd, n); | |
192 | |
193 return n; | |
194 } | |
195 | |
196 | |
197 static void | |
198 ngx_file_aio_event_handler(ngx_event_t *ev) | |
199 { | |
200 ngx_event_aio_t *aio; | |
201 | |
202 aio = ev->data; | |
203 | |
204 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0, | |
205 "aio event handler fd:%d %V", aio->fd, &aio->file->name); | |
206 | |
207 if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) { | |
208 aio->handler(ev); | |
209 } | |
210 } |