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

Global variables defined

Data types defined

Functions 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. typedef struct {
  9.     ngx_uint_t  changes;
  10.     ngx_uint_t  events;
  11. } ngx_kqueue_conf_t;


  12. static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer);
  13. #ifdef EVFILT_USER
  14. static ngx_int_t ngx_kqueue_notify_init(ngx_log_t *log);
  15. #endif
  16. static void ngx_kqueue_done(ngx_cycle_t *cycle);
  17. static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event,
  18.     ngx_uint_t flags);
  19. static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event,
  20.     ngx_uint_t flags);
  21. static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter,
  22.     ngx_uint_t flags);
  23. #ifdef EVFILT_USER
  24. static ngx_int_t ngx_kqueue_notify(ngx_event_handler_pt handler);
  25. #endif
  26. static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
  27.     ngx_uint_t flags);
  28. static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
  29.     struct kevent *kev);

  30. static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
  31. static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);


  32. int                    ngx_kqueue = -1;

  33. static struct kevent  *change_list;
  34. static struct kevent  *event_list;
  35. static ngx_uint_t      max_changes, nchanges, nevents;

  36. #ifdef EVFILT_USER
  37. static ngx_event_t     notify_event;
  38. static struct kevent   notify_kev;
  39. #endif


  40. static ngx_str_t      kqueue_name = ngx_string("kqueue");

  41. static ngx_command_t  ngx_kqueue_commands[] = {

  42.     { ngx_string("kqueue_changes"),
  43.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  44.       ngx_conf_set_num_slot,
  45.       0,
  46.       offsetof(ngx_kqueue_conf_t, changes),
  47.       NULL },

  48.     { ngx_string("kqueue_events"),
  49.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  50.       ngx_conf_set_num_slot,
  51.       0,
  52.       offsetof(ngx_kqueue_conf_t, events),
  53.       NULL },

  54.       ngx_null_command
  55. };


  56. static ngx_event_module_t  ngx_kqueue_module_ctx = {
  57.     &kqueue_name,
  58.     ngx_kqueue_create_conf,                /* create configuration */
  59.     ngx_kqueue_init_conf,                  /* init configuration */

  60.     {
  61.         ngx_kqueue_add_event,              /* add an event */
  62.         ngx_kqueue_del_event,              /* delete an event */
  63.         ngx_kqueue_add_event,              /* enable an event */
  64.         ngx_kqueue_del_event,              /* disable an event */
  65.         NULL,                              /* add an connection */
  66.         NULL,                              /* delete an connection */
  67. #ifdef EVFILT_USER
  68.         ngx_kqueue_notify,                 /* trigger a notify */
  69. #else
  70.         NULL,                              /* trigger a notify */
  71. #endif
  72.         ngx_kqueue_process_events,         /* process the events */
  73.         ngx_kqueue_init,                   /* init the events */
  74.         ngx_kqueue_done                    /* done the events */
  75.     }

  76. };

  77. ngx_module_t  ngx_kqueue_module = {
  78.     NGX_MODULE_V1,
  79.     &ngx_kqueue_module_ctx,                /* module context */
  80.     ngx_kqueue_commands,                   /* module directives */
  81.     NGX_EVENT_MODULE,                      /* module type */
  82.     NULL,                                  /* init master */
  83.     NULL,                                  /* init module */
  84.     NULL,                                  /* init process */
  85.     NULL,                                  /* init thread */
  86.     NULL,                                  /* exit thread */
  87.     NULL,                                  /* exit process */
  88.     NULL,                                  /* exit master */
  89.     NGX_MODULE_V1_PADDING
  90. };


  91. static ngx_int_t
  92. ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
  93. {
  94.     ngx_kqueue_conf_t  *kcf;
  95.     struct timespec     ts;
  96. #if (NGX_HAVE_TIMER_EVENT)
  97.     struct kevent       kev;
  98. #endif

  99.     kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module);

  100.     if (ngx_kqueue == -1) {
  101.         ngx_kqueue = kqueue();

  102.         if (ngx_kqueue == -1) {
  103.             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
  104.                           "kqueue() failed");
  105.             return NGX_ERROR;
  106.         }

  107. #ifdef EVFILT_USER
  108.         if (ngx_kqueue_notify_init(cycle->log) != NGX_OK) {
  109.             return NGX_ERROR;
  110.         }
  111. #endif
  112.     }

  113.     if (max_changes < kcf->changes) {
  114.         if (nchanges) {
  115.             ts.tv_sec = 0;
  116.             ts.tv_nsec = 0;

  117.             if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
  118.                 == -1)
  119.             {
  120.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  121.                               "kevent() failed");
  122.                 return NGX_ERROR;
  123.             }
  124.             nchanges = 0;
  125.         }

  126.         if (change_list) {
  127.             ngx_free(change_list);
  128.         }

  129.         change_list = ngx_alloc(kcf->changes * sizeof(struct kevent),
  130.                                 cycle->log);
  131.         if (change_list == NULL) {
  132.             return NGX_ERROR;
  133.         }
  134.     }

  135.     max_changes = kcf->changes;

  136.     if (nevents < kcf->events) {
  137.         if (event_list) {
  138.             ngx_free(event_list);
  139.         }

  140.         event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log);
  141.         if (event_list == NULL) {
  142.             return NGX_ERROR;
  143.         }
  144.     }

  145.     ngx_event_flags = NGX_USE_ONESHOT_EVENT
  146.                       |NGX_USE_KQUEUE_EVENT
  147.                       |NGX_USE_VNODE_EVENT;

  148. #if (NGX_HAVE_TIMER_EVENT)

  149.     if (timer) {
  150.         kev.ident = 0;
  151.         kev.filter = EVFILT_TIMER;
  152.         kev.flags = EV_ADD|EV_ENABLE;
  153.         kev.fflags = 0;
  154.         kev.data = timer;
  155.         kev.udata = 0;

  156.         ts.tv_sec = 0;
  157.         ts.tv_nsec = 0;

  158.         if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) {
  159.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  160.                           "kevent(EVFILT_TIMER) failed");
  161.             return NGX_ERROR;
  162.         }

  163.         ngx_event_flags |= NGX_USE_TIMER_EVENT;
  164.     }

  165. #endif

  166. #if (NGX_HAVE_CLEAR_EVENT)
  167.     ngx_event_flags |= NGX_USE_CLEAR_EVENT;
  168. #else
  169.     ngx_event_flags |= NGX_USE_LEVEL_EVENT;
  170. #endif

  171. #if (NGX_HAVE_LOWAT_EVENT)
  172.     ngx_event_flags |= NGX_USE_LOWAT_EVENT;
  173. #endif

  174.     nevents = kcf->events;

  175.     ngx_io = ngx_os_io;

  176.     ngx_event_actions = ngx_kqueue_module_ctx.actions;

  177.     return NGX_OK;
  178. }


  179. #ifdef EVFILT_USER

  180. static ngx_int_t
  181. ngx_kqueue_notify_init(ngx_log_t *log)
  182. {
  183.     notify_kev.ident = 0;
  184.     notify_kev.filter = EVFILT_USER;
  185.     notify_kev.data = 0;
  186.     notify_kev.flags = EV_ADD|EV_CLEAR;
  187.     notify_kev.fflags = 0;
  188.     notify_kev.udata = 0;

  189.     if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
  190.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  191.                       "kevent(EVFILT_USER, EV_ADD) failed");
  192.         return NGX_ERROR;
  193.     }

  194.     notify_event.active = 1;
  195.     notify_event.log = log;

  196.     notify_kev.flags = 0;
  197.     notify_kev.fflags = NOTE_TRIGGER;
  198.     notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) &notify_event);

  199.     return NGX_OK;
  200. }

  201. #endif


  202. static void
  203. ngx_kqueue_done(ngx_cycle_t *cycle)
  204. {
  205.     if (close(ngx_kqueue) == -1) {
  206.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  207.                       "kqueue close() failed");
  208.     }

  209.     ngx_kqueue = -1;

  210.     ngx_free(change_list);
  211.     ngx_free(event_list);

  212.     change_list = NULL;
  213.     event_list = NULL;
  214.     max_changes = 0;
  215.     nchanges = 0;
  216.     nevents = 0;
  217. }


  218. static ngx_int_t
  219. ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  220. {
  221.     ngx_int_t          rc;
  222. #if 0
  223.     ngx_event_t       *e;
  224.     ngx_connection_t  *c;
  225. #endif

  226.     ev->active = 1;
  227.     ev->disabled = 0;
  228.     ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;

  229. #if 0

  230.     if (ev->index < nchanges
  231.         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
  232.             == (uintptr_t) ev)
  233.     {
  234.         if (change_list[ev->index].flags == EV_DISABLE) {

  235.             /*
  236.              * if the EV_DISABLE is still not passed to a kernel
  237.              * we will not pass it
  238.              */

  239.             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  240.                            "kevent activated: %d: ft:%i",
  241.                            ngx_event_ident(ev->data), event);

  242.             if (ev->index < --nchanges) {
  243.                 e = (ngx_event_t *)
  244.                     ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
  245.                 change_list[ev->index] = change_list[nchanges];
  246.                 e->index = ev->index;
  247.             }

  248.             return NGX_OK;
  249.         }

  250.         c = ev->data;

  251.         ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
  252.                       "previous event on #%d were not passed in kernel", c->fd);

  253.         return NGX_ERROR;
  254.     }

  255. #endif

  256.     rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);

  257.     return rc;
  258. }


  259. static ngx_int_t
  260. ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  261. {
  262.     ngx_int_t     rc;
  263.     ngx_event_t  *e;

  264.     ev->active = 0;
  265.     ev->disabled = 0;

  266.     if (ev->index < nchanges
  267.         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
  268.             == (uintptr_t) ev)
  269.     {
  270.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  271.                        "kevent deleted: %d: ft:%i",
  272.                        ngx_event_ident(ev->data), event);

  273.         /* if the event is still not passed to a kernel we will not pass it */

  274.         nchanges--;

  275.         if (ev->index < nchanges) {
  276.             e = (ngx_event_t *)
  277.                     ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
  278.             change_list[ev->index] = change_list[nchanges];
  279.             e->index = ev->index;
  280.         }

  281.         return NGX_OK;
  282.     }

  283.     /*
  284.      * when the file descriptor is closed the kqueue automatically deletes
  285.      * its filters so we do not need to delete explicitly the event
  286.      * before the closing the file descriptor.
  287.      */

  288.     if (flags & NGX_CLOSE_EVENT) {
  289.         return NGX_OK;
  290.     }

  291.     if (flags & NGX_DISABLE_EVENT) {
  292.         ev->disabled = 1;

  293.     } else {
  294.         flags |= EV_DELETE;
  295.     }

  296.     rc = ngx_kqueue_set_event(ev, event, flags);

  297.     return rc;
  298. }


  299. static ngx_int_t
  300. ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
  301. {
  302.     struct kevent     *kev;
  303.     struct timespec    ts;
  304.     ngx_connection_t  *c;

  305.     c = ev->data;

  306.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  307.                    "kevent set event: %d: ft:%i fl:%04Xi",
  308.                    c->fd, filter, flags);

  309.     if (nchanges >= max_changes) {
  310.         ngx_log_error(NGX_LOG_WARN, ev->log, 0,
  311.                       "kqueue change list is filled up");

  312.         ts.tv_sec = 0;
  313.         ts.tv_nsec = 0;

  314.         if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
  315.             == -1)
  316.         {
  317.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
  318.             return NGX_ERROR;
  319.         }

  320.         nchanges = 0;
  321.     }

  322.     kev = &change_list[nchanges];

  323.     kev->ident = c->fd;
  324.     kev->filter = (short) filter;
  325.     kev->flags = (u_short) flags;
  326.     kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);

  327.     if (filter == EVFILT_VNODE) {
  328.         kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
  329.                                  |NOTE_ATTRIB|NOTE_RENAME
  330. #if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
  331.     || __FreeBSD_version >= 500018
  332.                                  |NOTE_REVOKE
  333. #endif
  334.                       ;
  335.         kev->data = 0;

  336.     } else {
  337. #if (NGX_HAVE_LOWAT_EVENT)
  338.         if (flags & NGX_LOWAT_EVENT) {
  339.             kev->fflags = NOTE_LOWAT;
  340.             kev->data = ev->available;

  341.         } else {
  342.             kev->fflags = 0;
  343.             kev->data = 0;
  344.         }
  345. #else
  346.         kev->fflags = 0;
  347.         kev->data = 0;
  348. #endif
  349.     }

  350.     ev->index = nchanges;
  351.     nchanges++;

  352.     if (flags & NGX_FLUSH_EVENT) {
  353.         ts.tv_sec = 0;
  354.         ts.tv_nsec = 0;

  355.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");

  356.         if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
  357.             == -1)
  358.         {
  359.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
  360.             return NGX_ERROR;
  361.         }

  362.         nchanges = 0;
  363.     }

  364.     return NGX_OK;
  365. }


  366. #ifdef EVFILT_USER

  367. static ngx_int_t
  368. ngx_kqueue_notify(ngx_event_handler_pt handler)
  369. {
  370.     notify_event.handler = handler;

  371.     if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
  372.         ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
  373.                       "kevent(EVFILT_USER, NOTE_TRIGGER) failed");
  374.         return NGX_ERROR;
  375.     }

  376.     return NGX_OK;
  377. }

  378. #endif


  379. static ngx_int_t
  380. ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
  381.     ngx_uint_t flags)
  382. {
  383.     int               events, n;
  384.     ngx_int_t         i, instance;
  385.     ngx_uint_t        level;
  386.     ngx_err_t         err;
  387.     ngx_event_t      *ev;
  388.     ngx_queue_t      *queue;
  389.     struct timespec   ts, *tp;

  390.     n = (int) nchanges;
  391.     nchanges = 0;

  392.     if (timer == NGX_TIMER_INFINITE) {
  393.         tp = NULL;

  394.     } else {

  395.         ts.tv_sec = timer / 1000;
  396.         ts.tv_nsec = (timer % 1000) * 1000000;

  397.         /*
  398.          * 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
  399.          * the int32_t while user level ts.tv_nsec is the long (64-bit),
  400.          * so on the big endian PowerPC all nanoseconds are lost.
  401.          */

  402. #if (NGX_DARWIN_KEVENT_BUG)
  403.         ts.tv_nsec <<= 32;
  404. #endif

  405.         tp = &ts;
  406.     }

  407.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  408.                    "kevent timer: %M, changes: %d", timer, n);

  409.     events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);

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

  411.     if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
  412.         ngx_time_update();
  413.     }

  414.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  415.                    "kevent events: %d", events);

  416.     if (err) {
  417.         if (err == NGX_EINTR) {

  418.             if (ngx_event_timer_alarm) {
  419.                 ngx_event_timer_alarm = 0;
  420.                 return NGX_OK;
  421.             }

  422.             level = NGX_LOG_INFO;

  423.         } else {
  424.             level = NGX_LOG_ALERT;
  425.         }

  426.         ngx_log_error(level, cycle->log, err, "kevent() failed");
  427.         return NGX_ERROR;
  428.     }

  429.     if (events == 0) {
  430.         if (timer != NGX_TIMER_INFINITE) {
  431.             return NGX_OK;
  432.         }

  433.         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  434.                       "kevent() returned no events without timeout");
  435.         return NGX_ERROR;
  436.     }

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

  438.         ngx_kqueue_dump_event(cycle->log, &event_list[i]);

  439.         if (event_list[i].flags & EV_ERROR) {
  440.             ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
  441.                           "kevent() error on %d filter:%d flags:%04Xd",
  442.                           (int) event_list[i].ident, event_list[i].filter,
  443.                           event_list[i].flags);
  444.             continue;
  445.         }

  446. #if (NGX_HAVE_TIMER_EVENT)

  447.         if (event_list[i].filter == EVFILT_TIMER) {
  448.             ngx_time_update();
  449.             continue;
  450.         }

  451. #endif

  452.         ev = (ngx_event_t *) event_list[i].udata;

  453.         switch (event_list[i].filter) {

  454.         case EVFILT_READ:
  455.         case EVFILT_WRITE:

  456.             instance = (uintptr_t) ev & 1;
  457.             ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);

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

  459.                 /*
  460.                  * the stale event from a file descriptor
  461.                  * that was just closed in this iteration
  462.                  */

  463.                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  464.                                "kevent: stale event %p", ev);
  465.                 continue;
  466.             }

  467.             if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
  468.                 ngx_kqueue_dump_event(ev->log, &event_list[i]);
  469.             }

  470.             if (ev->oneshot) {
  471.                 ev->active = 0;
  472.             }

  473.             ev->available = event_list[i].data;

  474.             if (event_list[i].flags & EV_EOF) {
  475.                 ev->pending_eof = 1;
  476.                 ev->kq_errno = event_list[i].fflags;
  477.             }

  478.             ev->ready = 1;

  479.             break;

  480.         case EVFILT_VNODE:
  481.             ev->kq_vnode = 1;

  482.             break;

  483.         case EVFILT_AIO:
  484.             ev->complete = 1;
  485.             ev->ready = 1;

  486.             break;

  487. #ifdef EVFILT_USER
  488.         case EVFILT_USER:
  489.             break;
  490. #endif

  491.         default:
  492.             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  493.                           "unexpected kevent() filter %d",
  494.                           event_list[i].filter);
  495.             continue;
  496.         }

  497.         if (flags & NGX_POST_EVENTS) {
  498.             queue = ev->accept ? &ngx_posted_accept_events
  499.                                : &ngx_posted_events;

  500.             ngx_post_event(ev, queue);

  501.             continue;
  502.         }

  503.         ev->handler(ev);
  504.     }

  505.     return NGX_OK;
  506. }


  507. static ngx_inline void
  508. ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
  509. {
  510.     if (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) {
  511.         ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
  512.                        "kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
  513.                        (void *) kev->ident, kev->filter,
  514.                        kev->flags, kev->fflags,
  515.                        (int) kev->data, kev->udata);

  516.     } else {
  517.         ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
  518.                        "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
  519.                        (int) kev->ident, kev->filter,
  520.                        kev->flags, kev->fflags,
  521.                        (int) kev->data, kev->udata);
  522.     }
  523. }


  524. static void *
  525. ngx_kqueue_create_conf(ngx_cycle_t *cycle)
  526. {
  527.     ngx_kqueue_conf_t  *kcf;

  528.     kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
  529.     if (kcf == NULL) {
  530.         return NULL;
  531.     }

  532.     kcf->changes = NGX_CONF_UNSET;
  533.     kcf->events = NGX_CONF_UNSET;

  534.     return kcf;
  535. }


  536. static char *
  537. ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
  538. {
  539.     ngx_kqueue_conf_t *kcf = conf;

  540.     ngx_conf_init_uint_value(kcf->changes, 512);
  541.     ngx_conf_init_uint_value(kcf->events, 512);

  542.     return NGX_CONF_OK;
  543. }