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