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