upstream nginx-0.7.31
[nginx.git] / nginx / src / event / modules / ngx_devpoll_module.c
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 #if (NGX_TEST_BUILD_DEVPOLL)
13
14 /* Solaris declarations */
15
16 #define POLLREMOVE   0x0800
17 #define DP_POLL      0xD001
18 #define DP_ISPOLLED  0xD002
19
20 struct dvpoll {
21     struct pollfd  *dp_fds;
22     int             dp_nfds;
23     int             dp_timeout;
24 };
25
26 #endif
27
28
29 typedef struct {
30     ngx_uint_t      changes;
31     ngx_uint_t      events;
32 } ngx_devpoll_conf_t;
33
34
35 static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
36 static void ngx_devpoll_done(ngx_cycle_t *cycle);
37 static ngx_int_t ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event,
38     ngx_uint_t flags);
39 static ngx_int_t ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event,
40     ngx_uint_t flags);
41 static ngx_int_t ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event,
42     ngx_uint_t flags);
43 static ngx_int_t ngx_devpoll_process_events(ngx_cycle_t *cycle,
44     ngx_msec_t timer, ngx_uint_t flags);
45
46 static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
47 static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);
48
49 static int              dp = -1;
50 static struct pollfd   *change_list, *event_list;
51 static ngx_uint_t       nchanges, max_changes, nevents;
52
53 static ngx_event_t    **change_index;
54
55
56 static ngx_str_t      devpoll_name = ngx_string("/dev/poll");
57
58 static ngx_command_t  ngx_devpoll_commands[] = {
59
60     { ngx_string("devpoll_changes"),
61       NGX_EVENT_CONF|NGX_CONF_TAKE1,
62       ngx_conf_set_num_slot,
63       0,
64       offsetof(ngx_devpoll_conf_t, changes),
65       NULL },
66
67     { ngx_string("devpoll_events"),
68       NGX_EVENT_CONF|NGX_CONF_TAKE1,
69       ngx_conf_set_num_slot,
70       0,
71       offsetof(ngx_devpoll_conf_t, events),
72       NULL },
73
74       ngx_null_command
75 };
76
77
78 ngx_event_module_t  ngx_devpoll_module_ctx = {
79     &devpoll_name,
80     ngx_devpoll_create_conf,               /* create configuration */
81     ngx_devpoll_init_conf,                 /* init configuration */
82
83     {
84         ngx_devpoll_add_event,             /* add an event */
85         ngx_devpoll_del_event,             /* delete an event */
86         ngx_devpoll_add_event,             /* enable an event */
87         ngx_devpoll_del_event,             /* disable an event */
88         NULL,                              /* add an connection */
89         NULL,                              /* delete an connection */
90         NULL,                              /* process the changes */
91         ngx_devpoll_process_events,        /* process the events */
92         ngx_devpoll_init,                  /* init the events */
93         ngx_devpoll_done,                  /* done the events */
94     }
95
96 };
97
98 ngx_module_t  ngx_devpoll_module = {
99     NGX_MODULE_V1,
100     &ngx_devpoll_module_ctx,               /* module context */
101     ngx_devpoll_commands,                  /* module directives */
102     NGX_EVENT_MODULE,                      /* module type */
103     NULL,                                  /* init master */
104     NULL,                                  /* init module */
105     NULL,                                  /* init process */
106     NULL,                                  /* init thread */
107     NULL,                                  /* exit thread */
108     NULL,                                  /* exit process */
109     NULL,                                  /* exit master */
110     NGX_MODULE_V1_PADDING
111 };
112
113
114 static ngx_int_t
115 ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
116 {
117     size_t               n;
118     ngx_devpoll_conf_t  *dpcf;
119
120     dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module);
121
122     if (dp == -1) {
123         dp = open("/dev/poll", O_RDWR);
124
125         if (dp == -1) {
126             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
127                           "open(/dev/poll) failed");
128             return NGX_ERROR;
129         }
130     }
131
132     if (max_changes < dpcf->changes) {
133         if (nchanges) {
134             n = nchanges * sizeof(struct pollfd);
135             if (write(dp, change_list, n) != (ssize_t) n) {
136                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
137                               "write(/dev/poll) failed");
138                 return NGX_ERROR;
139             }
140
141             nchanges = 0;
142         }
143
144         if (change_list) {
145             ngx_free(change_list);
146         }
147
148         change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes,
149                                 cycle->log);
150         if (change_list == NULL) {
151             return NGX_ERROR;
152         }
153
154         if (change_index) {
155             ngx_free(change_index);
156         }
157
158         change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes,
159                                  cycle->log);
160         if (change_index == NULL) {
161             return NGX_ERROR;
162         }
163     }
164
165     max_changes = dpcf->changes;
166
167     if (nevents < dpcf->events) {
168         if (event_list) {
169             ngx_free(event_list);
170         }
171
172         event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events,
173                                cycle->log);
174         if (event_list == NULL) {
175             return NGX_ERROR;
176         }
177     }
178
179     nevents = dpcf->events;
180
181     ngx_io = ngx_os_io;
182
183     ngx_event_actions = ngx_devpoll_module_ctx.actions;
184
185     ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
186
187     return NGX_OK;
188 }
189
190
191 static void
192 ngx_devpoll_done(ngx_cycle_t *cycle)
193 {
194     if (close(dp) == -1) {
195         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
196                       "close(/dev/poll) failed");
197     }
198
199     dp = -1;
200
201     ngx_free(change_list);
202     ngx_free(event_list);
203     ngx_free(change_index);
204
205     change_list = NULL;
206     event_list = NULL;
207     change_index = NULL;
208     max_changes = 0;
209     nchanges = 0;
210     nevents = 0;
211 }
212
213
214 static ngx_int_t
215 ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
216 {
217 #if (NGX_DEBUG)
218     ngx_connection_t *c;
219 #endif
220
221 #if (NGX_READ_EVENT != POLLIN)
222     event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
223 #endif
224
225 #if (NGX_DEBUG)
226     c = ev->data;
227     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
228                    "devpoll add event: fd:%d ev:%04Xi", c->fd, event);
229 #endif
230
231     ev->active = 1;
232
233     return ngx_devpoll_set_event(ev, event, 0);
234 }
235
236
237 static ngx_int_t
238 ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
239 {
240     ngx_event_t       *e;
241     ngx_connection_t  *c;
242
243     c = ev->data;
244
245 #if (NGX_READ_EVENT != POLLIN)
246     event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
247 #endif
248
249     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
250                    "devpoll del event: fd:%d ev:%04Xi", c->fd, event);
251
252     if (ngx_devpoll_set_event(ev, POLLREMOVE, flags) == NGX_ERROR) {
253         return NGX_ERROR;
254     }
255
256     ev->active = 0;
257
258     if (flags & NGX_CLOSE_EVENT) {
259         e = (event == POLLIN) ? c->write : c->read;
260
261         if (e) {
262             e->active = 0;
263         }
264
265         return NGX_OK;
266     }
267
268     /* restore the pair event if it exists */
269
270     if (event == POLLIN) {
271         e = c->write;
272         event = POLLOUT;
273
274     } else {
275         e = c->read;
276         event = POLLIN;
277     }
278
279     if (e && e->active) {
280         return ngx_devpoll_set_event(e, event, 0);
281     }
282
283     return NGX_OK;
284 }
285
286
287 static ngx_int_t
288 ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
289 {
290     size_t             n;
291     ngx_connection_t  *c;
292
293     c = ev->data;
294
295     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
296                    "devpoll fd:%d ev:%04Xi fl:%04Xi", c->fd, event, flags);
297
298     if (nchanges >= max_changes) {
299         ngx_log_error(NGX_LOG_WARN, ev->log, 0,
300                       "/dev/pool change list is filled up");
301
302         n = nchanges * sizeof(struct pollfd);
303         if (write(dp, change_list, n) != (ssize_t) n) {
304             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
305                           "write(/dev/poll) failed");
306             return NGX_ERROR;
307         }
308
309         nchanges = 0;
310     }
311
312     change_list[nchanges].fd = c->fd;
313     change_list[nchanges].events = (short) event;
314     change_list[nchanges].revents = 0;
315
316     change_index[nchanges] = ev;
317     ev->index = nchanges;
318
319     nchanges++;
320
321     if (flags & NGX_CLOSE_EVENT) {
322         n = nchanges * sizeof(struct pollfd);
323         if (write(dp, change_list, n) != (ssize_t) n) {
324             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
325                           "write(/dev/poll) failed");
326             return NGX_ERROR;
327         }
328
329         nchanges = 0;
330     }
331
332     return NGX_OK;
333 }
334
335
336 ngx_int_t
337 ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
338     ngx_uint_t flags)
339 {
340     int                 events, revents, rc;
341     size_t              n;
342     ngx_fd_t            fd;
343     ngx_err_t           err;
344     ngx_int_t           i;
345     ngx_uint_t          level;
346     ngx_event_t        *rev, *wev, **queue;
347     ngx_connection_t   *c;
348     struct pollfd       pfd;
349     struct dvpoll       dvp;
350
351     /* NGX_TIMER_INFINITE == INFTIM */
352
353     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
354                    "devpoll timer: %M", timer);
355
356     if (nchanges) {
357         n = nchanges * sizeof(struct pollfd);
358         if (write(dp, change_list, n) != (ssize_t) n) {
359             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
360                           "write(/dev/poll) failed");
361             return NGX_ERROR;
362         }
363
364         nchanges = 0;
365     }
366
367     dvp.dp_fds = event_list;
368     dvp.dp_nfds = (int) nevents;
369     dvp.dp_timeout = timer;
370     events = ioctl(dp, DP_POLL, &dvp);
371
372     if (events == -1) {
373         err = ngx_errno;
374     } else {
375         err = 0;
376     }
377
378     if (flags & NGX_UPDATE_TIME) {
379         ngx_time_update(0, 0);
380     }
381
382     if (err) {
383         if (err == NGX_EINTR) {
384
385             if (ngx_event_timer_alarm) {
386                 ngx_event_timer_alarm = 0;
387                 return NGX_OK;
388             }
389
390             level = NGX_LOG_INFO;
391
392         } else {
393             level = NGX_LOG_ALERT;
394         }
395
396         ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
397         return NGX_ERROR;
398     }
399
400     if (events == 0) {
401         if (timer != NGX_TIMER_INFINITE) {
402             return NGX_OK;
403         }
404
405         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
406                       "ioctl(DP_POLL) returned no events without timeout");
407         return NGX_ERROR;
408     }
409
410     ngx_mutex_lock(ngx_posted_events_mutex);
411
412     for (i = 0; i < events; i++) {
413
414         fd = event_list[i].fd;
415         revents = event_list[i].revents;
416
417         c = ngx_cycle->files[fd];
418
419         if (c == NULL || c->fd == -1) {
420
421             pfd.fd = fd;
422             pfd.events = 0;
423             pfd.revents = 0;
424
425             rc = ioctl(dp, DP_ISPOLLED, &pfd);
426
427             switch (rc) {
428
429             case -1:
430                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
431                     "ioctl(DP_ISPOLLED) failed for socket %d, event",
432                     fd, revents);
433                 break;
434
435             case 0:
436                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
437                     "phantom event %04Xd for closed and removed socket %d",
438                     revents, fd);
439                 break;
440
441             default:
442                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
443                     "unexpected event %04Xd for closed and removed socket %d, ",
444                     "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
445                     revents, fd, rc, pfd.fd, pfd.revents);
446
447                 pfd.fd = fd;
448                 pfd.events = POLLREMOVE;
449                 pfd.revents = 0;
450
451                 if (write(dp, &pfd, sizeof(struct pollfd))
452                     != (ssize_t) sizeof(struct pollfd))
453                 {
454                     ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
455                                   "write(/dev/poll) for %d failed, fd");
456                 }
457
458                 if (close(fd) == -1) {
459                     ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
460                                   "close(%d) failed", fd);
461                 }
462
463                 break;
464             }
465
466             continue;
467         }
468
469         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
470                        "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
471                        fd, event_list[i].events, revents);
472
473         if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
474             ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
475                           "ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
476                           fd, event_list[i].events, revents);
477         }
478
479         if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
480             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
481                           "strange ioctl(DP_POLL) events "
482                           "fd:%d ev:%04Xd rev:%04Xd",
483                           fd, event_list[i].events, revents);
484         }
485
486         if ((revents & (POLLERR|POLLHUP|POLLNVAL))
487              && (revents & (POLLIN|POLLOUT)) == 0)
488         {
489             /*
490              * if the error events were returned without POLLIN or POLLOUT,
491              * then add these flags to handle the events at least in one
492              * active handler
493              */
494
495             revents |= POLLIN|POLLOUT;
496         }
497
498         rev = c->read;
499
500         if ((revents & POLLIN) && rev->active) {
501
502             if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
503                 rev->posted_ready = 1;
504
505             } else {
506                 rev->ready = 1;
507             }
508
509             if (flags & NGX_POST_EVENTS) {
510                 queue = (ngx_event_t **) (rev->accept ?
511                                &ngx_posted_accept_events : &ngx_posted_events);
512
513                 ngx_locked_post_event(rev, queue);
514
515             } else {
516                 rev->handler(rev);
517             }
518         }
519
520         wev = c->write;
521
522         if ((revents & POLLOUT) && wev->active) {
523
524             if (flags & NGX_POST_THREAD_EVENTS) {
525                 wev->posted_ready = 1;
526
527             } else {
528                 wev->ready = 1;
529             }
530
531             if (flags & NGX_POST_EVENTS) {
532                 ngx_locked_post_event(wev, &ngx_posted_events);
533
534             } else {
535                 wev->handler(wev);
536             }
537         }
538     }
539
540     ngx_mutex_unlock(ngx_posted_events_mutex);
541
542     return NGX_OK;
543 }
544
545
546 static void *
547 ngx_devpoll_create_conf(ngx_cycle_t *cycle)
548 {
549     ngx_devpoll_conf_t  *dpcf;
550
551     dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
552     if (dpcf == NULL) {
553         return NGX_CONF_ERROR;
554     }
555
556     dpcf->changes = NGX_CONF_UNSET;
557     dpcf->events = NGX_CONF_UNSET;
558
559     return dpcf;
560 }
561
562
563 static char *
564 ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf)
565 {
566     ngx_devpoll_conf_t *dpcf = conf;
567
568     ngx_conf_init_uint_value(dpcf->changes, 32);
569     ngx_conf_init_uint_value(dpcf->events, 32);
570
571     return NGX_CONF_OK;
572 }