src/event/modules/ngx_devpoll_module.c - nginx-1.7.10

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. #define POLLREMOVE   0x0800
  11. #define DP_POLL      0xD001
  12. #define DP_ISPOLLED  0xD002

  13. struct dvpoll {
  14.     struct pollfd  *dp_fds;
  15.     int             dp_nfds;
  16.     int             dp_timeout;
  17. };

  18. #endif


  19. typedef struct {
  20.     ngx_uint_t      changes;
  21.     ngx_uint_t      events;
  22. } ngx_devpoll_conf_t;


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

  33. static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
  34. static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);

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

  38. static ngx_event_t    **change_index;


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

  40. static ngx_command_t  ngx_devpoll_commands[] = {

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

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

  53.       ngx_null_command
  54. };


  55. ngx_event_module_t  ngx_devpoll_module_ctx = {
  56.     &devpoll_name,
  57.     ngx_devpoll_create_conf,               /* create configuration */
  58.     ngx_devpoll_init_conf,                 /* init configuration */

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

  71. };

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


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

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

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

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

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

  108.             nchanges = 0;
  109.         }

  110.         if (change_list) {
  111.             ngx_free(change_list);
  112.         }

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

  118.         if (change_index) {
  119.             ngx_free(change_index);
  120.         }

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

  127.     max_changes = dpcf->changes;

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

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

  138.     nevents = dpcf->events;

  139.     ngx_io = ngx_os_io;

  140.     ngx_event_actions = ngx_devpoll_module_ctx.actions;

  141.     ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;

  142.     return NGX_OK;
  143. }


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

  151.     dp = -1;

  152.     ngx_free(change_list);
  153.     ngx_free(event_list);
  154.     ngx_free(change_index);

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


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

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

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

  176.     ev->active = 1;

  177.     return ngx_devpoll_set_event(ev, event, 0);
  178. }


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

  184.     c = ev->data;

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

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

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

  193.     ev->active = 0;

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

  196.         if (e) {
  197.             e->active = 0;
  198.         }

  199.         return NGX_OK;
  200.     }

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

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

  205.     } else {
  206.         e = c->read;
  207.         event = POLLIN;
  208.     }

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

  212.     return NGX_OK;
  213. }


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

  219.     c = ev->data;

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

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

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

  231.         nchanges = 0;
  232.     }

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

  236.     change_index[nchanges] = ev;
  237.     ev->index = nchanges;

  238.     nchanges++;

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

  246.         nchanges = 0;
  247.     }

  248.     return NGX_OK;
  249. }


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

  265.     /* NGX_TIMER_INFINITE == INFTIM */

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

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

  275.         nchanges = 0;
  276.     }

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

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

  282.     if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
  283.         ngx_time_update();
  284.     }

  285.     if (err) {
  286.         if (err == NGX_EINTR) {

  287.             if (ngx_event_timer_alarm) {
  288.                 ngx_event_timer_alarm = 0;
  289.                 return NGX_OK;
  290.             }

  291.             level = NGX_LOG_INFO;

  292.         } else {
  293.             level = NGX_LOG_ALERT;
  294.         }

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

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

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

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

  307.         fd = event_list[i].fd;
  308.         revents = event_list[i].revents;

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

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

  311.             pfd.fd = fd;
  312.             pfd.events = 0;
  313.             pfd.revents = 0;

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

  315.             switch (rc) {

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

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

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

  331.                 pfd.fd = fd;
  332.                 pfd.events = POLLREMOVE;
  333.                 pfd.revents = 0;

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

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

  344.                 break;
  345.             }

  346.             continue;
  347.         }

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

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

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

  362.         if ((revents & (POLLERR|POLLHUP|POLLNVAL))
  363.              && (revents & (POLLIN|POLLOUT)) == 0)
  364.         {
  365.             /*
  366.              * if the error events were returned without POLLIN or POLLOUT,
  367.              * then add these flags to handle the events at least in one
  368.              * active handler
  369.              */

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

  372.         rev = c->read;

  373.         if ((revents & POLLIN) && rev->active) {
  374.             rev->ready = 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. }