src/event/modules/ngx_kqueue_module.c - nginx

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. /* NetBSD up to 10.0 incompatibly defines kevent.udata as "intptr_t" */

  9. #if (__NetBSD__ && __NetBSD_Version__ < 1000000000)
  10. #define NGX_KQUEUE_UDATA_T
  11. #else
  12. #define NGX_KQUEUE_UDATA_T  (void *)
  13. #endif


  14. typedef struct {
  15.     ngx_uint_t  changes;
  16.     ngx_uint_t  events;
  17. } ngx_kqueue_conf_t;


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

  36. static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
  37. static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);


  38. int                    ngx_kqueue = -1;

  39. static struct kevent  *change_list;
  40. static struct kevent  *event_list;
  41. static ngx_uint_t      max_changes, nchanges, nevents;

  42. #ifdef EVFILT_USER
  43. static ngx_event_t     notify_event;
  44. static struct kevent   notify_kev;
  45. #endif


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

  47. static ngx_command_t  ngx_kqueue_commands[] = {

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

  54.     { ngx_string("kqueue_events"),
  55.       NGX_EVENT_CONF|NGX_CONF_TAKE1,
  56.       ngx_conf_set_num_slot,
  57.       0,
  58.       offsetof(ngx_kqueue_conf_t, events),
  59.       NULL },

  60.       ngx_null_command
  61. };


  62. static ngx_event_module_t  ngx_kqueue_module_ctx = {
  63.     &kqueue_name,
  64.     ngx_kqueue_create_conf,                /* create configuration */
  65.     ngx_kqueue_init_conf,                  /* init configuration */

  66.     {
  67.         ngx_kqueue_add_event,              /* add an event */
  68.         ngx_kqueue_del_event,              /* delete an event */
  69.         ngx_kqueue_add_event,              /* enable an event */
  70.         ngx_kqueue_del_event,              /* disable an event */
  71.         NULL,                              /* add an connection */
  72.         NULL,                              /* delete an connection */
  73. #ifdef EVFILT_USER
  74.         ngx_kqueue_notify,                 /* trigger a notify */
  75. #else
  76.         NULL,                              /* trigger a notify */
  77. #endif
  78.         ngx_kqueue_process_events,         /* process the events */
  79.         ngx_kqueue_init,                   /* init the events */
  80.         ngx_kqueue_done                    /* done the events */
  81.     }

  82. };

  83. ngx_module_t  ngx_kqueue_module = {
  84.     NGX_MODULE_V1,
  85.     &ngx_kqueue_module_ctx,                /* module context */
  86.     ngx_kqueue_commands,                   /* module directives */
  87.     NGX_EVENT_MODULE,                      /* module type */
  88.     NULL,                                  /* init master */
  89.     NULL,                                  /* init module */
  90.     NULL,                                  /* init process */
  91.     NULL,                                  /* init thread */
  92.     NULL,                                  /* exit thread */
  93.     NULL,                                  /* exit process */
  94.     NULL,                                  /* exit master */
  95.     NGX_MODULE_V1_PADDING
  96. };


  97. static ngx_int_t
  98. ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
  99. {
  100.     ngx_kqueue_conf_t  *kcf;
  101.     struct timespec     ts;
  102. #if (NGX_HAVE_TIMER_EVENT)
  103.     struct kevent       kev;
  104. #endif

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

  106.     if (ngx_kqueue == -1) {
  107.         ngx_kqueue = kqueue();

  108.         if (ngx_kqueue == -1) {
  109.             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
  110.                           "kqueue() failed");
  111.             return NGX_ERROR;
  112.         }

  113. #ifdef EVFILT_USER
  114.         if (ngx_kqueue_notify_init(cycle->log) != NGX_OK) {
  115.             return NGX_ERROR;
  116.         }
  117. #endif
  118.     }

  119.     if (max_changes < kcf->changes) {
  120.         if (nchanges) {
  121.             ts.tv_sec = 0;
  122.             ts.tv_nsec = 0;

  123.             if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
  124.                 == -1)
  125.             {
  126.                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  127.                               "kevent() failed");
  128.                 return NGX_ERROR;
  129.             }
  130.             nchanges = 0;
  131.         }

  132.         if (change_list) {
  133.             ngx_free(change_list);
  134.         }

  135.         change_list = ngx_alloc(kcf->changes * sizeof(struct kevent),
  136.                                 cycle->log);
  137.         if (change_list == NULL) {
  138.             return NGX_ERROR;
  139.         }
  140.     }

  141.     max_changes = kcf->changes;

  142.     if (nevents < kcf->events) {
  143.         if (event_list) {
  144.             ngx_free(event_list);
  145.         }

  146.         event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log);
  147.         if (event_list == NULL) {
  148.             return NGX_ERROR;
  149.         }
  150.     }

  151.     ngx_event_flags = NGX_USE_ONESHOT_EVENT
  152.                       |NGX_USE_KQUEUE_EVENT
  153.                       |NGX_USE_VNODE_EVENT;

  154. #if (NGX_HAVE_TIMER_EVENT)

  155.     if (timer) {
  156.         kev.ident = 0;
  157.         kev.filter = EVFILT_TIMER;
  158.         kev.flags = EV_ADD|EV_ENABLE;
  159.         kev.fflags = 0;
  160.         kev.data = timer;
  161.         kev.udata = NGX_KQUEUE_UDATA_T (uintptr_t) 0;

  162.         ts.tv_sec = 0;
  163.         ts.tv_nsec = 0;

  164.         if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) {
  165.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  166.                           "kevent(EVFILT_TIMER) failed");
  167.             return NGX_ERROR;
  168.         }

  169.         ngx_event_flags |= NGX_USE_TIMER_EVENT;
  170.     }

  171. #endif

  172. #if (NGX_HAVE_CLEAR_EVENT)
  173.     ngx_event_flags |= NGX_USE_CLEAR_EVENT;
  174. #else
  175.     ngx_event_flags |= NGX_USE_LEVEL_EVENT;
  176. #endif

  177. #if (NGX_HAVE_LOWAT_EVENT)
  178.     ngx_event_flags |= NGX_USE_LOWAT_EVENT;
  179. #endif

  180.     nevents = kcf->events;

  181.     ngx_io = ngx_os_io;

  182.     ngx_event_actions = ngx_kqueue_module_ctx.actions;

  183.     return NGX_OK;
  184. }


  185. #ifdef EVFILT_USER

  186. static ngx_int_t
  187. ngx_kqueue_notify_init(ngx_log_t *log)
  188. {
  189.     notify_kev.ident = 0;
  190.     notify_kev.filter = EVFILT_USER;
  191.     notify_kev.data = 0;
  192.     notify_kev.flags = EV_ADD|EV_CLEAR;
  193.     notify_kev.fflags = 0;
  194.     notify_kev.udata = NGX_KQUEUE_UDATA_T (uintptr_t) 0;

  195.     if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
  196.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  197.                       "kevent(EVFILT_USER, EV_ADD) failed");
  198.         return NGX_ERROR;
  199.     }

  200.     notify_event.active = 1;
  201.     notify_event.log = log;

  202.     notify_kev.flags = 0;
  203.     notify_kev.fflags = NOTE_TRIGGER;
  204.     notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) &notify_event);

  205.     return NGX_OK;
  206. }

  207. #endif


  208. static void
  209. ngx_kqueue_done(ngx_cycle_t *cycle)
  210. {
  211.     if (close(ngx_kqueue) == -1) {
  212.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  213.                       "kqueue close() failed");
  214.     }

  215.     ngx_kqueue = -1;

  216.     ngx_free(change_list);
  217.     ngx_free(event_list);

  218.     change_list = NULL;
  219.     event_list = NULL;
  220.     max_changes = 0;
  221.     nchanges = 0;
  222.     nevents = 0;
  223. }


  224. static ngx_int_t
  225. ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  226. {
  227.     ngx_int_t          rc;
  228. #if 0
  229.     ngx_event_t       *e;
  230.     ngx_connection_t  *c;
  231. #endif

  232.     ev->active = 1;
  233.     ev->disabled = 0;
  234.     ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;

  235. #if 0

  236.     if (ev->index < nchanges
  237.         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
  238.             == (uintptr_t) ev)
  239.     {
  240.         if (change_list[ev->index].flags == EV_DISABLE) {

  241.             /*
  242.              * if the EV_DISABLE is still not passed to a kernel
  243.              * we will not pass it
  244.              */

  245.             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  246.                            "kevent activated: %d: ft:%i",
  247.                            ngx_event_ident(ev->data), event);

  248.             if (ev->index < --nchanges) {
  249.                 e = (ngx_event_t *)
  250.                     ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
  251.                 change_list[ev->index] = change_list[nchanges];
  252.                 e->index = ev->index;
  253.             }

  254.             return NGX_OK;
  255.         }

  256.         c = ev->data;

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

  259.         return NGX_ERROR;
  260.     }

  261. #endif

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

  263.     return rc;
  264. }


  265. static ngx_int_t
  266. ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
  267. {
  268.     ngx_int_t     rc;
  269.     ngx_event_t  *e;

  270.     ev->active = 0;
  271.     ev->disabled = 0;

  272.     if (ev->index < nchanges
  273.         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
  274.             == (uintptr_t) ev)
  275.     {
  276.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  277.                        "kevent deleted: %d: ft:%i",
  278.                        ngx_event_ident(ev->data), event);

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

  280.         nchanges--;

  281.         if (ev->index < nchanges) {
  282.             e = (ngx_event_t *)
  283.                     ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
  284.             change_list[ev->index] = change_list[nchanges];
  285.             e->index = ev->index;
  286.         }

  287.         return NGX_OK;
  288.     }

  289.     /*
  290.      * when the file descriptor is closed the kqueue automatically deletes
  291.      * its filters so we do not need to delete explicitly the event
  292.      * before the closing the file descriptor.
  293.      */

  294.     if (flags & NGX_CLOSE_EVENT) {
  295.         return NGX_OK;
  296.     }

  297.     if (flags & NGX_DISABLE_EVENT) {
  298.         ev->disabled = 1;

  299.     } else {
  300.         flags |= EV_DELETE;
  301.     }

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

  303.     return rc;
  304. }


  305. static ngx_int_t
  306. ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
  307. {
  308.     struct kevent     *kev;
  309.     struct timespec    ts;
  310.     ngx_connection_t  *c;

  311.     c = ev->data;

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

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

  318.         ts.tv_sec = 0;
  319.         ts.tv_nsec = 0;

  320.         if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
  321.             == -1)
  322.         {
  323.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
  324.             return NGX_ERROR;
  325.         }

  326.         nchanges = 0;
  327.     }

  328.     kev = &change_list[nchanges];

  329.     kev->ident = c->fd;
  330.     kev->filter = (short) filter;
  331.     kev->flags = (u_short) flags;
  332.     kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);

  333.     if (filter == EVFILT_VNODE) {
  334.         kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
  335.                                  |NOTE_ATTRIB|NOTE_RENAME
  336. #if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
  337.     || __FreeBSD_version >= 500018
  338.                                  |NOTE_REVOKE
  339. #endif
  340.                       ;
  341.         kev->data = 0;

  342.     } else {
  343. #if (NGX_HAVE_LOWAT_EVENT)
  344.         if (flags & NGX_LOWAT_EVENT) {
  345.             kev->fflags = NOTE_LOWAT;
  346.             kev->data = ev->available;

  347.         } else {
  348.             kev->fflags = 0;
  349.             kev->data = 0;
  350.         }
  351. #else
  352.         kev->fflags = 0;
  353.         kev->data = 0;
  354. #endif
  355.     }

  356.     ev->index = nchanges;
  357.     nchanges++;

  358.     if (flags & NGX_FLUSH_EVENT) {
  359.         ts.tv_sec = 0;
  360.         ts.tv_nsec = 0;

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

  362.         if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
  363.             == -1)
  364.         {
  365.             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
  366.             return NGX_ERROR;
  367.         }

  368.         nchanges = 0;
  369.     }

  370.     return NGX_OK;
  371. }


  372. #ifdef EVFILT_USER

  373. static ngx_int_t
  374. ngx_kqueue_notify(ngx_event_handler_pt handler)
  375. {
  376.     notify_event.handler = handler;

  377.     if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
  378.         ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
  379.                       "kevent(EVFILT_USER, NOTE_TRIGGER) failed");
  380.         return NGX_ERROR;
  381.     }

  382.     return NGX_OK;
  383. }

  384. #endif


  385. static ngx_int_t
  386. ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
  387.     ngx_uint_t flags)
  388. {
  389.     int               events, n;
  390.     ngx_int_t         i, instance;
  391.     ngx_uint_t        level;
  392.     ngx_err_t         err;
  393.     ngx_event_t      *ev;
  394.     ngx_queue_t      *queue;
  395.     struct timespec   ts, *tp;

  396.     n = (int) nchanges;
  397.     nchanges = 0;

  398.     if (timer == NGX_TIMER_INFINITE) {
  399.         tp = NULL;

  400.     } else {

  401.         ts.tv_sec = timer / 1000;
  402.         ts.tv_nsec = (timer % 1000) * 1000000;

  403.         /*
  404.          * 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
  405.          * the int32_t while user level ts.tv_nsec is the long (64-bit),
  406.          * so on the big endian PowerPC all nanoseconds are lost.
  407.          */

  408. #if (NGX_DARWIN_KEVENT_BUG)
  409.         ts.tv_nsec <<= 32;
  410. #endif

  411.         tp = &ts;
  412.     }

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

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

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

  417.     if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
  418.         ngx_time_update();
  419.     }

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

  422.     if (err) {
  423.         if (err == NGX_EINTR) {

  424.             if (ngx_event_timer_alarm) {
  425.                 ngx_event_timer_alarm = 0;
  426.                 return NGX_OK;
  427.             }

  428.             level = NGX_LOG_INFO;

  429.         } else {
  430.             level = NGX_LOG_ALERT;
  431.         }

  432.         ngx_log_error(level, cycle->log, err, "kevent() failed");
  433.         return NGX_ERROR;
  434.     }

  435.     if (events == 0) {
  436.         if (timer != NGX_TIMER_INFINITE) {
  437.             return NGX_OK;
  438.         }

  439.         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  440.                       "kevent() returned no events without timeout");
  441.         return NGX_ERROR;
  442.     }

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

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

  445.         if (event_list[i].flags & EV_ERROR) {
  446.             ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
  447.                           "kevent() error on %d filter:%d flags:%04Xd",
  448.                           (int) event_list[i].ident, event_list[i].filter,
  449.                           event_list[i].flags);
  450.             continue;
  451.         }

  452. #if (NGX_HAVE_TIMER_EVENT)

  453.         if (event_list[i].filter == EVFILT_TIMER) {
  454.             ngx_time_update();
  455.             continue;
  456.         }

  457. #endif

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

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

  460.         case EVFILT_READ:
  461.         case EVFILT_WRITE:

  462.             instance = (uintptr_t) ev & 1;
  463.             ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);

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

  465.                 /*
  466.                  * the stale event from a file descriptor
  467.                  * that was just closed in this iteration
  468.                  */

  469.                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  470.                                "kevent: stale event %p", ev);
  471.                 continue;
  472.             }

  473.             if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
  474.                 ngx_kqueue_dump_event(ev->log, &event_list[i]);
  475.             }

  476.             if (ev->oneshot) {
  477.                 ev->active = 0;
  478.             }

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

  480.             if (event_list[i].flags & EV_EOF) {
  481.                 ev->pending_eof = 1;
  482.                 ev->kq_errno = event_list[i].fflags;
  483.             }

  484.             ev->ready = 1;

  485.             break;

  486.         case EVFILT_VNODE:
  487.             ev->kq_vnode = 1;

  488.             break;

  489.         case EVFILT_AIO:
  490.             ev->complete = 1;
  491.             ev->ready = 1;

  492.             break;

  493. #ifdef EVFILT_USER
  494.         case EVFILT_USER:
  495.             break;
  496. #endif

  497.         default:
  498.             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  499.                           "unexpected kevent() filter %d",
  500.                           event_list[i].filter);
  501.             continue;
  502.         }

  503.         if (flags & NGX_POST_EVENTS) {
  504.             queue = ev->accept ? &ngx_posted_accept_events
  505.                                : &ngx_posted_events;

  506.             ngx_post_event(ev, queue);

  507.             continue;
  508.         }

  509.         ev->handler(ev);
  510.     }

  511.     return NGX_OK;
  512. }


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

  522.     } else {
  523.         ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
  524.                        "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
  525.                        (int) kev->ident, kev->filter,
  526.                        kev->flags, kev->fflags,
  527.                        (int) kev->data, kev->udata);
  528.     }
  529. }


  530. static void *
  531. ngx_kqueue_create_conf(ngx_cycle_t *cycle)
  532. {
  533.     ngx_kqueue_conf_t  *kcf;

  534.     kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
  535.     if (kcf == NULL) {
  536.         return NULL;
  537.     }

  538.     kcf->changes = NGX_CONF_UNSET;
  539.     kcf->events = NGX_CONF_UNSET;

  540.     return kcf;
  541. }


  542. static char *
  543. ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
  544. {
  545.     ngx_kqueue_conf_t *kcf = conf;

  546.     ngx_conf_init_uint_value(kcf->changes, 512);
  547.     ngx_conf_init_uint_value(kcf->events, 512);

  548.     return NGX_CONF_OK;
  549. }