src/event/modules/ngx_eventport_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_EVENTPORT)

  9. #define ushort_t  u_short
  10. #define uint_t    u_int

  11. #ifndef CLOCK_REALTIME
  12. #define CLOCK_REALTIME          0
  13. typedef int     clockid_t;
  14. typedef voidtimer_t;
  15. #endif

  16. /* Solaris declarations */

  17. #define PORT_SOURCE_AIO         1
  18. #define PORT_SOURCE_TIMER       2
  19. #define PORT_SOURCE_USER        3
  20. #define PORT_SOURCE_FD          4
  21. #define PORT_SOURCE_ALERT       5
  22. #define PORT_SOURCE_MQ          6

  23. #ifndef ETIME
  24. #define ETIME                   64
  25. #endif

  26. #define SIGEV_PORT              4

  27. typedef struct {
  28.     int         portev_events;  /* event data is source specific */
  29.     ushort_t    portev_source;  /* event source */
  30.     ushort_t    portev_pad;     /* port internal use */
  31.     uintptr_t   portev_object;  /* source specific object */
  32.     void       *portev_user;    /* user cookie */
  33. } port_event_t;

  34. typedef struct  port_notify {
  35.     int         portnfy_port;   /* bind request(s) to port */
  36.     void       *portnfy_user;   /* user defined */
  37. } port_notify_t;

  38. #if (__FreeBSD_version < 700005)

  39. typedef struct itimerspec {     /* definition per POSIX.4 */
  40.     struct timespec it_interval;/* timer period */
  41.     struct timespec it_value;   /* timer expiration */
  42. } itimerspec_t;

  43. #endif

  44. int port_create(void);

  45. int port_create(void)
  46. {
  47.     return -1;
  48. }


  49. int port_associate(int port, int source, uintptr_t object, int events,
  50.     void *user);

  51. int port_associate(int port, int source, uintptr_t object, int events,
  52.     void *user)
  53. {
  54.     return -1;
  55. }


  56. int port_dissociate(int port, int source, uintptr_t object);

  57. int port_dissociate(int port, int source, uintptr_t object)
  58. {
  59.     return -1;
  60. }


  61. int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
  62.     struct timespec *timeout);

  63. int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
  64.     struct timespec *timeout)
  65. {
  66.     return -1;
  67. }


  68. int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);

  69. int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
  70. {
  71.     return -1;
  72. }


  73. int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
  74.     struct itimerspec *ovalue);

  75. int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
  76.     struct itimerspec *ovalue)
  77. {
  78.     return -1;
  79. }


  80. int timer_delete(timer_t timerid);

  81. int timer_delete(timer_t timerid)
  82. {
  83.     return -1;
  84. }

  85. #endif


  86. typedef struct {
  87.     ngx_uint_t  events;
  88. } ngx_eventport_conf_t;


  89. static ngx_int_t ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer);
  90. static void ngx_eventport_done(ngx_cycle_t *cycle);
  91. static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event,
  92.     ngx_uint_t flags);
  93. static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event,
  94.     ngx_uint_t flags);
  95. static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle,
  96.     ngx_msec_t timer, ngx_uint_t flags);

  97. static void *ngx_eventport_create_conf(ngx_cycle_t *cycle);
  98. static char *ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf);

  99. static int            ep = -1;
  100. static port_event_t  *event_list;
  101. static ngx_uint_t     nevents;
  102. static timer_t        event_timer = (timer_t) -1;

  103. static ngx_str_t      eventport_name = ngx_string("eventport");


  104. static ngx_command_t  ngx_eventport_commands[] = {

  105.     { ngx_string("eventport_events"),
  106.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  107.       ngx_conf_set_num_slot,
  108.       0,
  109.       offsetof(ngx_eventport_conf_t, events),
  110.       NULL },

  111.       ngx_null_command
  112. };


  113. ngx_event_module_t  ngx_eventport_module_ctx = {
  114.     &eventport_name,
  115.     ngx_eventport_create_conf,             /* create configuration */
  116.     ngx_eventport_init_conf,               /* init configuration */

  117.     {
  118.         ngx_eventport_add_event,           /* add an event */
  119.         ngx_eventport_del_event,           /* delete an event */
  120.         ngx_eventport_add_event,           /* enable an event */
  121.         ngx_eventport_del_event,           /* disable an event */
  122.         NULL,                              /* add an connection */
  123.         NULL,                              /* delete an connection */
  124.         NULL,                              /* process the changes */
  125.         ngx_eventport_process_events,      /* process the events */
  126.         ngx_eventport_init,                /* init the events */
  127.         ngx_eventport_done,                /* done the events */
  128.     }

  129. };

  130. ngx_module_t  ngx_eventport_module = {
  131.     NGX_MODULE_V1,
  132.     &ngx_eventport_module_ctx,             /* module context */
  133.     ngx_eventport_commands,                /* module directives */
  134.     NGX_EVENT_MODULE,                      /* module type */
  135.     NULL,                                  /* init master */
  136.     NULL,                                  /* init module */
  137.     NULL,                                  /* init process */
  138.     NULL,                                  /* init thread */
  139.     NULL,                                  /* exit thread */
  140.     NULL,                                  /* exit process */
  141.     NULL,                                  /* exit master */
  142.     NGX_MODULE_V1_PADDING
  143. };


  144. static ngx_int_t
  145. ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer)
  146. {
  147.     port_notify_t          pn;
  148.     struct itimerspec      its;
  149.     struct sigevent        sev;
  150.     ngx_eventport_conf_t  *epcf;

  151.     epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_eventport_module);

  152.     if (ep == -1) {
  153.         ep = port_create();

  154.         if (ep == -1) {
  155.             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
  156.                           "port_create() failed");
  157.             return NGX_ERROR;
  158.         }
  159.     }

  160.     if (nevents < epcf->events) {
  161.         if (event_list) {
  162.             ngx_free(event_list);
  163.         }

  164.         event_list = ngx_alloc(sizeof(port_event_t) * epcf->events,
  165.                                cycle->log);
  166.         if (event_list == NULL) {
  167.             return NGX_ERROR;
  168.         }
  169.     }

  170.     ngx_event_flags = NGX_USE_EVENTPORT_EVENT;

  171.     if (timer) {
  172.         ngx_memzero(&pn, sizeof(port_notify_t));
  173.         pn.portnfy_port = ep;

  174.         ngx_memzero(&sev, sizeof(struct sigevent));
  175.         sev.sigev_notify = SIGEV_PORT;
  176. #if !(NGX_TEST_BUILD_EVENTPORT)
  177.         sev.sigev_value.sival_ptr = &pn;
  178. #endif

  179.         if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) {
  180.             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
  181.                           "timer_create() failed");
  182.             return NGX_ERROR;
  183.         }

  184.         its.it_interval.tv_sec = timer / 1000;
  185.         its.it_interval.tv_nsec = (timer % 1000) * 1000000;
  186.         its.it_value.tv_sec = timer / 1000;
  187.         its.it_value.tv_nsec = (timer % 1000) * 1000000;

  188.         if (timer_settime(event_timer, 0, &its, NULL) == -1) {
  189.             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
  190.                           "timer_settime() failed");
  191.             return NGX_ERROR;
  192.         }

  193.         ngx_event_flags |= NGX_USE_TIMER_EVENT;
  194.     }

  195.     nevents = epcf->events;

  196.     ngx_io = ngx_os_io;

  197.     ngx_event_actions = ngx_eventport_module_ctx.actions;

  198.     return NGX_OK;
  199. }


  200. static void
  201. ngx_eventport_done(ngx_cycle_t *cycle)
  202. {
  203.     if (event_timer != (timer_t) -1) {
  204.         if (timer_delete(event_timer) == -1) {
  205.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  206.                           "timer_delete() failed");
  207.         }

  208.         event_timer = (timer_t) -1;
  209.     }

  210.     if (close(ep) == -1) {
  211.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  212.                       "close() event port failed");
  213.     }

  214.     ep = -1;

  215.     ngx_free(event_list);

  216.     event_list = NULL;
  217.     nevents = 0;
  218. }


  219. static ngx_int_t
  220. ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  221. {
  222.     ngx_int_t          events, prev;
  223.     ngx_event_t       *e;
  224.     ngx_connection_t  *c;

  225.     c = ev->data;

  226.     events = event;

  227.     if (event == NGX_READ_EVENT) {
  228.         e = c->write;
  229.         prev = POLLOUT;
  230. #if (NGX_READ_EVENT != POLLIN)
  231.         events = POLLIN;
  232. #endif

  233.     } else {
  234.         e = c->read;
  235.         prev = POLLIN;
  236. #if (NGX_WRITE_EVENT != POLLOUT)
  237.         events = POLLOUT;
  238. #endif
  239.     }

  240.     if (e->oneshot) {
  241.         events |= prev;
  242.     }

  243.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  244.                    "eventport add event: fd:%d ev:%04Xi", c->fd, events);

  245.     if (port_associate(ep, PORT_SOURCE_FD, c->fd, events,
  246.                        (void *) ((uintptr_t) ev | ev->instance))
  247.         == -1)
  248.     {
  249.         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
  250.                       "port_associate() failed");
  251.         return NGX_ERROR;
  252.     }

  253.     ev->active = 1;
  254.     ev->oneshot = 1;

  255.     return NGX_OK;
  256. }


  257. static ngx_int_t
  258. ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  259. {
  260.     ngx_event_t       *e;
  261.     ngx_connection_t  *c;

  262.     /*
  263.      * when the file descriptor is closed, the event port automatically
  264.      * dissociates it from the port, so we do not need to dissociate explicitly
  265.      * the event before the closing the file descriptor
  266.      */

  267.     if (flags & NGX_CLOSE_EVENT) {
  268.         ev->active = 0;
  269.         ev->oneshot = 0;
  270.         return NGX_OK;
  271.     }

  272.     c = ev->data;

  273.     if (event == NGX_READ_EVENT) {
  274.         e = c->write;
  275.         event = POLLOUT;

  276.     } else {
  277.         e = c->read;
  278.         event = POLLIN;
  279.     }

  280.     if (e->oneshot) {
  281.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  282.                        "eventport change event: fd:%d ev:%04Xi", c->fd, event);

  283.         if (port_associate(ep, PORT_SOURCE_FD, c->fd, event,
  284.                            (void *) ((uintptr_t) ev | ev->instance))
  285.             == -1)
  286.         {
  287.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
  288.                           "port_associate() failed");
  289.             return NGX_ERROR;
  290.         }

  291.     } else {
  292.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  293.                        "eventport del event: fd:%d", c->fd);

  294.         if (port_dissociate(ep, PORT_SOURCE_FD, c->fd) == -1) {
  295.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
  296.                           "port_dissociate() failed");
  297.             return NGX_ERROR;
  298.         }
  299.     }

  300.     ev->active = 0;
  301.     ev->oneshot = 0;

  302.     return NGX_OK;
  303. }


  304. ngx_int_t
  305. ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
  306.     ngx_uint_t flags)
  307. {
  308.     int                 n, revents;
  309.     u_int               events;
  310.     ngx_err_t           err;
  311.     ngx_int_t           instance;
  312.     ngx_uint_t          i, level;
  313.     ngx_event_t        *ev, *rev, *wev;
  314.     ngx_queue_t        *queue;
  315.     ngx_connection_t   *c;
  316.     struct timespec     ts, *tp;

  317.     if (timer == NGX_TIMER_INFINITE) {
  318.         tp = NULL;

  319.     } else {
  320.         ts.tv_sec = timer / 1000;
  321.         ts.tv_nsec = (timer % 1000) * 1000000;
  322.         tp = &ts;
  323.     }

  324.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  325.                    "eventport timer: %M", timer);

  326.     events = 1;

  327.     n = port_getn(ep, event_list, (u_int) nevents, &events, tp);

  328.     err = ngx_errno;

  329.     if (flags & NGX_UPDATE_TIME) {
  330.         ngx_time_update();
  331.     }

  332.     if (n == -1) {
  333.         if (err == ETIME) {
  334.             if (timer != NGX_TIMER_INFINITE) {
  335.                 return NGX_OK;
  336.             }

  337.             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  338.                           "port_getn() returned no events without timeout");
  339.             return NGX_ERROR;
  340.         }

  341.         level = (err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT;
  342.         ngx_log_error(level, cycle->log, err, "port_getn() failed");
  343.         return NGX_ERROR;
  344.     }

  345.     if (events == 0) {
  346.         if (timer != NGX_TIMER_INFINITE) {
  347.             return NGX_OK;
  348.         }

  349.         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  350.                       "port_getn() returned no events without timeout");
  351.         return NGX_ERROR;
  352.     }

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

  354.         if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
  355.             ngx_time_update();
  356.             continue;
  357.         }

  358.         ev = event_list[i].portev_user;

  359.         switch (event_list[i].portev_source) {

  360.         case PORT_SOURCE_FD:

  361.             instance = (uintptr_t) ev & 1;
  362.             ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);

  363.             if (ev->closed || ev->instance != instance) {

  364.                 /*
  365.                  * the stale event from a file descriptor
  366.                  * that was just closed in this iteration
  367.                  */

  368.                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  369.                                "eventport: stale event %p", ev);
  370.                 continue;
  371.             }

  372.             revents = event_list[i].portev_events;

  373.             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  374.                            "eventport: fd:%d, ev:%04Xd",
  375.                            event_list[i].portev_object, revents);

  376.             if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
  377.                 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  378.                                "port_getn() error fd:%d ev:%04Xd",
  379.                                event_list[i].portev_object, revents);
  380.             }

  381.             if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
  382.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  383.                               "strange port_getn() events fd:%d ev:%04Xd",
  384.                               event_list[i].portev_object, revents);
  385.             }

  386.             if ((revents & (POLLERR|POLLHUP|POLLNVAL))
  387.                  && (revents & (POLLIN|POLLOUT)) == 0)
  388.             {
  389.                 /*
  390.                  * if the error events were returned without POLLIN or POLLOUT,
  391.                  * then add these flags to handle the events at least in one
  392.                  * active handler
  393.                  */

  394.                 revents |= POLLIN|POLLOUT;
  395.             }

  396.             c = ev->data;
  397.             rev = c->read;
  398.             wev = c->write;

  399.             rev->active = 0;
  400.             wev->active = 0;

  401.             if (revents & POLLIN) {
  402.                 rev->ready = 1;

  403.                 if (flags & NGX_POST_EVENTS) {
  404.                     queue = rev->accept ? &ngx_posted_accept_events
  405.                                         : &ngx_posted_events;

  406.                     ngx_post_event(rev, queue);

  407.                 } else {
  408.                     rev->handler(rev);

  409.                     if (ev->closed || ev->instance != instance) {
  410.                         continue;
  411.                     }
  412.                 }

  413.                 if (rev->accept) {
  414.                     if (ngx_use_accept_mutex) {
  415.                         ngx_accept_events = 1;
  416.                         continue;
  417.                     }

  418.                     if (port_associate(ep, PORT_SOURCE_FD, c->fd, POLLIN,
  419.                                        (void *) ((uintptr_t) ev | ev->instance))
  420.                         == -1)
  421.                     {
  422.                         ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
  423.                                       "port_associate() failed");
  424.                         return NGX_ERROR;
  425.                     }
  426.                 }
  427.             }

  428.             if (revents & POLLOUT) {
  429.                 wev->ready = 1;

  430.                 if (flags & NGX_POST_EVENTS) {
  431.                     ngx_post_event(wev, &ngx_posted_events);

  432.                 } else {
  433.                     wev->handler(wev);
  434.                 }
  435.             }

  436.             continue;

  437.         default:
  438.             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  439.                           "unexpected even_port object %d",
  440.                           event_list[i].portev_object);
  441.             continue;
  442.         }
  443.     }

  444.     return NGX_OK;
  445. }


  446. static void *
  447. ngx_eventport_create_conf(ngx_cycle_t *cycle)
  448. {
  449.     ngx_eventport_conf_t  *epcf;

  450.     epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
  451.     if (epcf == NULL) {
  452.         return NULL;
  453.     }

  454.     epcf->events = NGX_CONF_UNSET;

  455.     return epcf;
  456. }


  457. static char *
  458. ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf)
  459. {
  460.     ngx_eventport_conf_t *epcf = conf;

  461.     ngx_conf_init_uint_value(epcf->events, 32);

  462.     return NGX_CONF_OK;
  463. }