src/event/modules/ngx_devpoll_module.c - nginx source code

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>


  8. #if (NGX_TEST_BUILD_DEVPOLL)

  9. /* Solaris declarations */

  10. #ifndef POLLREMOVE
  11. #define POLLREMOVE   0x0800
  12. #endif
  13. #define DP_POLL      0xD001
  14. #define DP_ISPOLLED  0xD002

  15. struct dvpoll {
  16.     struct pollfd  *dp_fds;
  17.     int             dp_nfds;
  18.     int             dp_timeout;
  19. };

  20. #endif


  21. typedef struct {
  22.     ngx_uint_t      changes;
  23.     ngx_uint_t      events;
  24. } ngx_devpoll_conf_t;


  25. static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
  26. static void ngx_devpoll_done(ngx_cycle_t *cycle);
  27. static ngx_int_t ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event,
  28.     ngx_uint_t flags);
  29. static ngx_int_t ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event,
  30.     ngx_uint_t flags);
  31. static ngx_int_t ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event,
  32.     ngx_uint_t flags);
  33. static ngx_int_t ngx_devpoll_process_events(ngx_cycle_t *cycle,
  34.     ngx_msec_t timer, ngx_uint_t flags);

  35. static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
  36. static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);

  37. static int              dp = -1;
  38. static struct pollfd   *change_list, *event_list;
  39. static ngx_uint_t       nchanges, max_changes, nevents;

  40. static ngx_event_t    **change_index;


  41. static ngx_str_t      devpoll_name = ngx_string("/dev/poll");

  42. static ngx_command_t  ngx_devpoll_commands[] = {

  43.     { ngx_string("devpoll_changes"),
  44.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  45.       ngx_conf_set_num_slot,
  46.       0,
  47.       offsetof(ngx_devpoll_conf_t, changes),
  48.       NULL },

  49.     { ngx_string("devpoll_events"),
  50.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  51.       ngx_conf_set_num_slot,
  52.       0,
  53.       offsetof(ngx_devpoll_conf_t, events),
  54.       NULL },

  55.       ngx_null_command
  56. };


  57. static ngx_event_module_t  ngx_devpoll_module_ctx = {
  58.     &devpoll_name,
  59.     ngx_devpoll_create_conf,               /* create configuration */
  60.     ngx_devpoll_init_conf,                 /* init configuration */

  61.     {
  62.         ngx_devpoll_add_event,             /* add an event */
  63.         ngx_devpoll_del_event,             /* delete an event */
  64.         ngx_devpoll_add_event,             /* enable an event */
  65.         ngx_devpoll_del_event,             /* disable an event */
  66.         NULL,                              /* add an connection */
  67.         NULL,                              /* delete an connection */
  68.         NULL,                              /* trigger a notify */
  69.         ngx_devpoll_process_events,        /* process the events */
  70.         ngx_devpoll_init,                  /* init the events */
  71.         ngx_devpoll_done,                  /* done the events */
  72.     }

  73. };

  74. ngx_module_t  ngx_devpoll_module = {
  75.     NGX_MODULE_V1,
  76.     &ngx_devpoll_module_ctx,               /* module context */
  77.     ngx_devpoll_commands,                  /* module directives */
  78.     NGX_EVENT_MODULE,                      /* module type */
  79.     NULL,                                  /* init master */
  80.     NULL,                                  /* init module */
  81.     NULL,                                  /* init process */
  82.     NULL,                                  /* init thread */
  83.     NULL,                                  /* exit thread */
  84.     NULL,                                  /* exit process */
  85.     NULL,                                  /* exit master */
  86.     NGX_MODULE_V1_PADDING
  87. };


  88. static ngx_int_t
  89. ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
  90. {
  91.     size_t               n;
  92.     ngx_devpoll_conf_t  *dpcf;

  93.     dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module);

  94.     if (dp == -1) {
  95.         dp = open("/dev/poll", O_RDWR);

  96.         if (dp == -1) {
  97.             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
  98.                           "open(/dev/poll) failed");
  99.             return NGX_ERROR;
  100.         }
  101.     }

  102.     if (max_changes < dpcf->changes) {
  103.         if (nchanges) {
  104.             n = nchanges * sizeof(struct pollfd);
  105.             if (write(dp, change_list, n) != (ssize_t) n) {
  106.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  107.                               "write(/dev/poll) failed");
  108.                 return NGX_ERROR;
  109.             }

  110.             nchanges = 0;
  111.         }

  112.         if (change_list) {
  113.             ngx_free(change_list);
  114.         }

  115.         change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes,
  116.                                 cycle->log);
  117.         if (change_list == NULL) {
  118.             return NGX_ERROR;
  119.         }

  120.         if (change_index) {
  121.             ngx_free(change_index);
  122.         }

  123.         change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes,
  124.                                  cycle->log);
  125.         if (change_index == NULL) {
  126.             return NGX_ERROR;
  127.         }
  128.     }

  129.     max_changes = dpcf->changes;

  130.     if (nevents < dpcf->events) {
  131.         if (event_list) {
  132.             ngx_free(event_list);
  133.         }

  134.         event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events,
  135.                                cycle->log);
  136.         if (event_list == NULL) {
  137.             return NGX_ERROR;
  138.         }
  139.     }

  140.     nevents = dpcf->events;

  141.     ngx_io = ngx_os_io;

  142.     ngx_event_actions = ngx_devpoll_module_ctx.actions;

  143.     ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;

  144.     return NGX_OK;
  145. }


  146. static void
  147. ngx_devpoll_done(ngx_cycle_t *cycle)
  148. {
  149.     if (close(dp) == -1) {
  150.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  151.                       "close(/dev/poll) failed");
  152.     }

  153.     dp = -1;

  154.     ngx_free(change_list);
  155.     ngx_free(event_list);
  156.     ngx_free(change_index);

  157.     change_list = NULL;
  158.     event_list = NULL;
  159.     change_index = NULL;
  160.     max_changes = 0;
  161.     nchanges = 0;
  162.     nevents = 0;
  163. }


  164. static ngx_int_t
  165. ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  166. {
  167. #if (NGX_DEBUG)
  168.     ngx_connection_t *c;
  169. #endif

  170. #if (NGX_READ_EVENT != POLLIN)
  171.     event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
  172. #endif

  173. #if (NGX_DEBUG)
  174.     c = ev->data;
  175.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  176.                    "devpoll add event: fd:%d ev:%04Xi", c->fd, event);
  177. #endif

  178.     ev->active = 1;

  179.     return ngx_devpoll_set_event(ev, event, 0);
  180. }


  181. static ngx_int_t
  182. ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  183. {
  184.     ngx_event_t       *e;
  185.     ngx_connection_t  *c;

  186.     c = ev->data;

  187. #if (NGX_READ_EVENT != POLLIN)
  188.     event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
  189. #endif

  190.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  191.                    "devpoll del event: fd:%d ev:%04Xi", c->fd, event);

  192.     if (ngx_devpoll_set_event(ev, POLLREMOVE, flags) == NGX_ERROR) {
  193.         return NGX_ERROR;
  194.     }

  195.     ev->active = 0;

  196.     if (flags & NGX_CLOSE_EVENT) {
  197.         e = (event == POLLIN) ? c->write : c->read;

  198.         if (e) {
  199.             e->active = 0;
  200.         }

  201.         return NGX_OK;
  202.     }

  203.     /* restore the pair event if it exists */

  204.     if (event == POLLIN) {
  205.         e = c->write;
  206.         event = POLLOUT;

  207.     } else {
  208.         e = c->read;
  209.         event = POLLIN;
  210.     }

  211.     if (e && e->active) {
  212.         return ngx_devpoll_set_event(e, event, 0);
  213.     }

  214.     return NGX_OK;
  215. }


  216. static ngx_int_t
  217. ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  218. {
  219.     size_t             n;
  220.     ngx_connection_t  *c;

  221.     c = ev->data;

  222.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  223.                    "devpoll fd:%d ev:%04Xi fl:%04Xi", c->fd, event, flags);

  224.     if (nchanges >= max_changes) {
  225.         ngx_log_error(NGX_LOG_WARN, ev->log, 0,
  226.                       "/dev/pool change list is filled up");

  227.         n = nchanges * sizeof(struct pollfd);
  228.         if (write(dp, change_list, n) != (ssize_t) n) {
  229.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
  230.                           "write(/dev/poll) failed");
  231.             return NGX_ERROR;
  232.         }

  233.         nchanges = 0;
  234.     }

  235.     change_list[nchanges].fd = c->fd;
  236.     change_list[nchanges].events = (short) event;
  237.     change_list[nchanges].revents = 0;

  238.     change_index[nchanges] = ev;
  239.     ev->index = nchanges;

  240.     nchanges++;

  241.     if (flags & NGX_CLOSE_EVENT) {
  242.         n = nchanges * sizeof(struct pollfd);
  243.         if (write(dp, change_list, n) != (ssize_t) n) {
  244.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
  245.                           "write(/dev/poll) failed");
  246.             return NGX_ERROR;
  247.         }

  248.         nchanges = 0;
  249.     }

  250.     return NGX_OK;
  251. }


  252. static ngx_int_t
  253. ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
  254.     ngx_uint_t flags)
  255. {
  256.     int                 events, revents, rc;
  257.     size_t              n;
  258.     ngx_fd_t            fd;
  259.     ngx_err_t           err;
  260.     ngx_int_t           i;
  261.     ngx_uint_t          level, instance;
  262.     ngx_event_t        *rev, *wev;
  263.     ngx_queue_t        *queue;
  264.     ngx_connection_t   *c;
  265.     struct pollfd       pfd;
  266.     struct dvpoll       dvp;

  267.     /* NGX_TIMER_INFINITE == INFTIM */

  268.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  269.                    "devpoll timer: %M", timer);

  270.     if (nchanges) {
  271.         n = nchanges * sizeof(struct pollfd);
  272.         if (write(dp, change_list, n) != (ssize_t) n) {
  273.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  274.                           "write(/dev/poll) failed");
  275.             return NGX_ERROR;
  276.         }

  277.         nchanges = 0;
  278.     }

  279.     dvp.dp_fds = event_list;
  280.     dvp.dp_nfds = (int) nevents;
  281.     dvp.dp_timeout = timer;
  282.     events = ioctl(dp, DP_POLL, &dvp);

  283.     err = (events == -1) ? ngx_errno : 0;

  284.     if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
  285.         ngx_time_update();
  286.     }

  287.     if (err) {
  288.         if (err == NGX_EINTR) {

  289.             if (ngx_event_timer_alarm) {
  290.                 ngx_event_timer_alarm = 0;
  291.                 return NGX_OK;
  292.             }

  293.             level = NGX_LOG_INFO;

  294.         } else {
  295.             level = NGX_LOG_ALERT;
  296.         }

  297.         ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
  298.         return NGX_ERROR;
  299.     }

  300.     if (events == 0) {
  301.         if (timer != NGX_TIMER_INFINITE) {
  302.             return NGX_OK;
  303.         }

  304.         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  305.                       "ioctl(DP_POLL) returned no events without timeout");
  306.         return NGX_ERROR;
  307.     }

  308.     for (i = 0; i < events; i++) {

  309.         fd = event_list[i].fd;
  310.         revents = event_list[i].revents;

  311.         c = ngx_cycle->files[fd];

  312.         if (c == NULL || c->fd == -1) {

  313.             pfd.fd = fd;
  314.             pfd.events = 0;
  315.             pfd.revents = 0;

  316.             rc = ioctl(dp, DP_ISPOLLED, &pfd);

  317.             switch (rc) {

  318.             case -1:
  319.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  320.                     "ioctl(DP_ISPOLLED) failed for socket %d, event %04Xd",
  321.                     fd, revents);
  322.                 break;

  323.             case 0:
  324.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  325.                     "phantom event %04Xd for closed and removed socket %d",
  326.                     revents, fd);
  327.                 break;

  328.             default:
  329.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  330.                     "unexpected event %04Xd for closed and removed socket %d, "
  331.                     "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
  332.                     revents, fd, rc, pfd.fd, pfd.revents);

  333.                 pfd.fd = fd;
  334.                 pfd.events = POLLREMOVE;
  335.                 pfd.revents = 0;

  336.                 if (write(dp, &pfd, sizeof(struct pollfd))
  337.                     != (ssize_t) sizeof(struct pollfd))
  338.                 {
  339.                     ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  340.                                   "write(/dev/poll) for %d failed", fd);
  341.                 }

  342.                 if (close(fd) == -1) {
  343.                     ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  344.                                   "close(%d) failed", fd);
  345.                 }

  346.                 break;
  347.             }

  348.             continue;
  349.         }

  350.         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  351.                        "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
  352.                        fd, event_list[i].events, revents);

  353.         if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
  354.             ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  355.                           "ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
  356.                           fd, event_list[i].events, revents);
  357.         }

  358.         if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
  359.             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  360.                           "strange ioctl(DP_POLL) events "
  361.                           "fd:%d ev:%04Xd rev:%04Xd",
  362.                           fd, event_list[i].events, revents);
  363.         }

  364.         if (revents & (POLLERR|POLLHUP|POLLNVAL)) {

  365.             /*
  366.              * if the error events were returned, add POLLIN and POLLOUT
  367.              * to handle the events at least in one active handler
  368.              */

  369.             revents |= POLLIN|POLLOUT;
  370.         }

  371.         rev = c->read;

  372.         if ((revents & POLLIN) && rev->active) {
  373.             rev->ready = 1;
  374.             rev->available = -1;

  375.             if (flags & NGX_POST_EVENTS) {
  376.                 queue = rev->accept ? &ngx_posted_accept_events
  377.                                     : &ngx_posted_events;

  378.                 ngx_post_event(rev, queue);

  379.             } else {
  380.                 instance = rev->instance;

  381.                 rev->handler(rev);

  382.                 if (c->fd == -1 || rev->instance != instance) {
  383.                     continue;
  384.                 }
  385.             }
  386.         }

  387.         wev = c->write;

  388.         if ((revents & POLLOUT) && wev->active) {
  389.             wev->ready = 1;

  390.             if (flags & NGX_POST_EVENTS) {
  391.                 ngx_post_event(wev, &ngx_posted_events);

  392.             } else {
  393.                 wev->handler(wev);
  394.             }
  395.         }
  396.     }

  397.     return NGX_OK;
  398. }


  399. static void *
  400. ngx_devpoll_create_conf(ngx_cycle_t *cycle)
  401. {
  402.     ngx_devpoll_conf_t  *dpcf;

  403.     dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
  404.     if (dpcf == NULL) {
  405.         return NULL;
  406.     }

  407.     dpcf->changes = NGX_CONF_UNSET;
  408.     dpcf->events = NGX_CONF_UNSET;

  409.     return dpcf;
  410. }


  411. static char *
  412. ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf)
  413. {
  414.     ngx_devpoll_conf_t *dpcf = conf;

  415.     ngx_conf_init_uint_value(dpcf->changes, 32);
  416.     ngx_conf_init_uint_value(dpcf->events, 32);

  417.     return NGX_CONF_OK;
  418. }