Mercurial > hg > nginx
comparison src/event/modules/ngx_epoll_module.c @ 3052:6060225e9261
FreeBSD and Linux AIO support
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Fri, 28 Aug 2009 08:12:35 +0000 |
parents | a1d54c705f38 |
children | 0299cf5856fc |
comparison
equal
deleted
inserted
replaced
3051:26dfc0fa22c8 | 3052:6060225e9261 |
---|---|
56 int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout) | 56 int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout) |
57 { | 57 { |
58 return -1; | 58 return -1; |
59 } | 59 } |
60 | 60 |
61 #if (NGX_HAVE_FILE_AIO) | |
62 | |
63 #define SYS_io_setup 245 | |
64 #define SYS_io_destroy 246 | |
65 #define SYS_io_getevents 247 | |
66 #define SYS_eventfd 323 | |
67 | |
68 typedef u_int aio_context_t; | |
69 | |
70 struct io_event { | |
71 uint64_t data; /* the data field from the iocb */ | |
72 uint64_t obj; /* what iocb this event came from */ | |
73 int64_t res; /* result code for this event */ | |
74 int64_t res2; /* secondary result */ | |
75 }; | |
76 | |
77 | |
78 int eventfd(u_int initval) | |
79 { | |
80 return -1; | |
81 } | |
82 | |
83 #endif | |
61 #endif | 84 #endif |
62 | 85 |
63 | 86 |
64 typedef struct { | 87 typedef struct { |
65 ngx_uint_t events; | 88 ngx_uint_t events; |
76 static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c, | 99 static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c, |
77 ngx_uint_t flags); | 100 ngx_uint_t flags); |
78 static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, | 101 static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, |
79 ngx_uint_t flags); | 102 ngx_uint_t flags); |
80 | 103 |
104 #if (NGX_HAVE_FILE_AIO) | |
105 static void ngx_epoll_eventfd_handler(ngx_event_t *ev); | |
106 #endif | |
107 | |
81 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle); | 108 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle); |
82 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf); | 109 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf); |
83 | 110 |
84 static int ep = -1; | 111 static int ep = -1; |
85 static struct epoll_event *event_list; | 112 static struct epoll_event *event_list; |
86 static ngx_uint_t nevents; | 113 static ngx_uint_t nevents; |
87 | 114 |
115 #if (NGX_HAVE_FILE_AIO) | |
116 | |
117 int ngx_eventfd = -1; | |
118 aio_context_t ngx_aio_ctx = 0; | |
119 | |
120 static ngx_event_t ngx_eventfd_event; | |
121 static ngx_connection_t ngx_eventfd_conn; | |
122 | |
123 #endif | |
88 | 124 |
89 static ngx_str_t epoll_name = ngx_string("epoll"); | 125 static ngx_str_t epoll_name = ngx_string("epoll"); |
90 | 126 |
91 static ngx_command_t ngx_epoll_commands[] = { | 127 static ngx_command_t ngx_epoll_commands[] = { |
92 | 128 |
134 NULL, /* exit master */ | 170 NULL, /* exit master */ |
135 NGX_MODULE_V1_PADDING | 171 NGX_MODULE_V1_PADDING |
136 }; | 172 }; |
137 | 173 |
138 | 174 |
175 #if (NGX_HAVE_FILE_AIO) | |
176 | |
177 /* | |
178 * We call io_setup(), io_destroy() io_submit(), and io_getevents() directly | |
179 * as syscalls instead of libaio usage, because the library header file | |
180 * supports eventfd() since 0.3.107 version only. | |
181 * | |
182 * Also we do not use eventfd() in glibc, because glibc supports it | |
183 * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2() | |
184 * into single eventfd() function with different number of parameters. | |
185 */ | |
186 | |
187 static long | |
188 io_setup(u_int nr_reqs, aio_context_t *ctx) | |
189 { | |
190 return syscall(SYS_io_setup, nr_reqs, ctx); | |
191 } | |
192 | |
193 | |
194 static int | |
195 io_destroy(aio_context_t ctx) | |
196 { | |
197 return syscall(SYS_io_destroy, ctx); | |
198 } | |
199 | |
200 | |
201 static long | |
202 io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events, | |
203 struct timespec *tmo) | |
204 { | |
205 return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo); | |
206 } | |
207 | |
208 #endif | |
209 | |
210 | |
139 static ngx_int_t | 211 static ngx_int_t |
140 ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) | 212 ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) |
141 { | 213 { |
142 ngx_epoll_conf_t *epcf; | 214 ngx_epoll_conf_t *epcf; |
143 | 215 |
149 if (ep == -1) { | 221 if (ep == -1) { |
150 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, | 222 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, |
151 "epoll_create() failed"); | 223 "epoll_create() failed"); |
152 return NGX_ERROR; | 224 return NGX_ERROR; |
153 } | 225 } |
226 | |
227 #if (NGX_HAVE_FILE_AIO) | |
228 { | |
229 int n; | |
230 struct epoll_event ee; | |
231 | |
232 ngx_eventfd = syscall(SYS_eventfd, 0); | |
233 | |
234 if (ngx_eventfd == -1) { | |
235 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, | |
236 "eventfd() failed"); | |
237 return NGX_ERROR; | |
238 } | |
239 | |
240 n = 1; | |
241 | |
242 if (ioctl(ngx_eventfd, FIONBIO, &n) == -1) { | |
243 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, | |
244 "ioctl(eventfd, FIONBIO) failed"); | |
245 } | |
246 | |
247 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
248 "eventfd: %d", ngx_eventfd); | |
249 | |
250 n = io_setup(1024, &ngx_aio_ctx); | |
251 | |
252 if (n != 0) { | |
253 ngx_log_error(NGX_LOG_EMERG, cycle->log, -n, "io_setup() failed"); | |
254 return NGX_ERROR; | |
255 } | |
256 | |
257 ngx_eventfd_event.data = &ngx_eventfd_conn; | |
258 ngx_eventfd_event.handler = ngx_epoll_eventfd_handler; | |
259 ngx_eventfd_event.log = cycle->log; | |
260 ngx_eventfd_event.active = 1; | |
261 ngx_eventfd_conn.fd = ngx_eventfd; | |
262 ngx_eventfd_conn.read = &ngx_eventfd_event; | |
263 ngx_eventfd_conn.log = cycle->log; | |
264 | |
265 ee.events = EPOLLIN|EPOLLET; | |
266 ee.data.ptr = &ngx_eventfd_conn; | |
267 | |
268 if (epoll_ctl(ep, EPOLL_CTL_ADD, ngx_eventfd, &ee) == -1) { | |
269 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, | |
270 "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed"); | |
271 return NGX_ERROR; | |
272 } | |
273 } | |
274 #endif | |
154 } | 275 } |
155 | 276 |
156 if (nevents < epcf->events) { | 277 if (nevents < epcf->events) { |
157 if (event_list) { | 278 if (event_list) { |
158 ngx_free(event_list); | 279 ngx_free(event_list); |
190 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 311 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, |
191 "epoll close() failed"); | 312 "epoll close() failed"); |
192 } | 313 } |
193 | 314 |
194 ep = -1; | 315 ep = -1; |
316 | |
317 #if (NGX_HAVE_FILE_AIO) | |
318 | |
319 if (io_destroy(ngx_aio_ctx) != 0) { | |
320 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
321 "io_destroy() failed"); | |
322 } | |
323 | |
324 ngx_aio_ctx = 0; | |
325 | |
326 #endif | |
195 | 327 |
196 ngx_free(event_list); | 328 ngx_free(event_list); |
197 | 329 |
198 event_list = NULL; | 330 event_list = NULL; |
199 nevents = 0; | 331 nevents = 0; |
535 | 667 |
536 return NGX_OK; | 668 return NGX_OK; |
537 } | 669 } |
538 | 670 |
539 | 671 |
672 #if (NGX_HAVE_FILE_AIO) | |
673 | |
674 static void | |
675 ngx_epoll_eventfd_handler(ngx_event_t *ev) | |
676 { | |
677 int n; | |
678 long i, events; | |
679 uint64_t ready; | |
680 ngx_err_t err; | |
681 ngx_event_t *e; | |
682 ngx_event_aio_t *aio; | |
683 struct io_event event[64]; | |
684 struct timespec ts; | |
685 | |
686 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd handler"); | |
687 | |
688 n = read(ngx_eventfd, &ready, 8); | |
689 | |
690 err = ngx_errno; | |
691 | |
692 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd: %d", n); | |
693 | |
694 if (n != 8) { | |
695 if (n == -1) { | |
696 if (err == NGX_EAGAIN) { | |
697 return; | |
698 } | |
699 | |
700 ngx_log_error(NGX_LOG_ALERT, ev->log, err, "read(eventfd) failed"); | |
701 return; | |
702 } | |
703 | |
704 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
705 "read(eventfd) returned only %d bytes", n); | |
706 return; | |
707 } | |
708 | |
709 ts.tv_sec = 0; | |
710 ts.tv_nsec = 0; | |
711 | |
712 while (ready) { | |
713 | |
714 events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts); | |
715 | |
716 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
717 "io_getevents: %l", events); | |
718 | |
719 if (events > 0) { | |
720 ready -= events; | |
721 | |
722 for (i = 0; i < events; i++) { | |
723 | |
724 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
725 "io_event: %uXL %uXL %L %L", | |
726 event[i].data, event[i].obj, | |
727 event[i].res, event[i].res2); | |
728 | |
729 e = (ngx_event_t *) (uintptr_t) event[i].data; | |
730 | |
731 e->complete = 1; | |
732 e->active = 0; | |
733 e->ready = 1; | |
734 | |
735 aio = e->data; | |
736 aio->res = event[i].res; | |
737 | |
738 ngx_post_event(e, &ngx_posted_events); | |
739 } | |
740 | |
741 continue; | |
742 } | |
743 | |
744 if (events == 0) { | |
745 return; | |
746 } | |
747 | |
748 /* events < 0 */ | |
749 ngx_log_error(NGX_LOG_ALERT, ev->log, -events, "io_getevents() failed"); | |
750 return; | |
751 } | |
752 } | |
753 | |
754 #endif | |
755 | |
756 | |
540 static void * | 757 static void * |
541 ngx_epoll_create_conf(ngx_cycle_t *cycle) | 758 ngx_epoll_create_conf(ngx_cycle_t *cycle) |
542 { | 759 { |
543 ngx_epoll_conf_t *epcf; | 760 ngx_epoll_conf_t *epcf; |
544 | 761 |