upstream nginx-0.7.35
[nginx.git] / nginx / src / event / modules / ngx_kqueue_module.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10 #include <ngx_kqueue_module.h>
11
12
13 typedef struct {
14     ngx_uint_t  changes;
15     ngx_uint_t  events;
16 } ngx_kqueue_conf_t;
17
18
19 static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer);
20 static void ngx_kqueue_done(ngx_cycle_t *cycle);
21 static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event,
22     ngx_uint_t flags);
23 static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event,
24     ngx_uint_t flags);
25 static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter,
26     ngx_uint_t flags);
27 static ngx_int_t ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try);
28 static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
29     ngx_uint_t flags);
30 static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
31     struct kevent *kev);
32
33 static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
34 static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
35
36
37 int                    ngx_kqueue = -1;
38
39 /*
40  * The "change_list" should be declared as ngx_thread_volatile.
41  * However, the use of the change_list is localized in kqueue functions and
42  * is protected by the mutex so even the "icc -ipo" should not build the code
43  * with the race condition.  Thus we avoid the declaration to make a more
44  * readable code.
45  */
46
47 static struct kevent  *change_list, *change_list0, *change_list1;
48 static struct kevent  *event_list;
49 static ngx_uint_t      max_changes, nchanges, nevents;
50
51 #if (NGX_THREADS)
52 static ngx_mutex_t    *list_mutex;
53 static ngx_mutex_t    *kevent_mutex;
54 #endif
55
56
57
58 static ngx_str_t      kqueue_name = ngx_string("kqueue");
59
60 static ngx_command_t  ngx_kqueue_commands[] = {
61
62     { ngx_string("kqueue_changes"),
63       NGX_EVENT_CONF|NGX_CONF_TAKE1,
64       ngx_conf_set_num_slot,
65       0,
66       offsetof(ngx_kqueue_conf_t, changes),
67       NULL },
68
69     { ngx_string("kqueue_events"),
70       NGX_EVENT_CONF|NGX_CONF_TAKE1,
71       ngx_conf_set_num_slot,
72       0,
73       offsetof(ngx_kqueue_conf_t, events),
74       NULL },
75
76       ngx_null_command
77 };
78
79
80 ngx_event_module_t  ngx_kqueue_module_ctx = {
81     &kqueue_name,
82     ngx_kqueue_create_conf,                /* create configuration */
83     ngx_kqueue_init_conf,                  /* init configuration */
84
85     {
86         ngx_kqueue_add_event,              /* add an event */
87         ngx_kqueue_del_event,              /* delete an event */
88         ngx_kqueue_add_event,              /* enable an event */
89         ngx_kqueue_del_event,              /* disable an event */
90         NULL,                              /* add an connection */
91         NULL,                              /* delete an connection */
92         ngx_kqueue_process_changes,        /* process the changes */
93         ngx_kqueue_process_events,         /* process the events */
94         ngx_kqueue_init,                   /* init the events */
95         ngx_kqueue_done                    /* done the events */
96     }
97
98 };
99
100 ngx_module_t  ngx_kqueue_module = {
101     NGX_MODULE_V1,
102     &ngx_kqueue_module_ctx,                /* module context */
103     ngx_kqueue_commands,                   /* module directives */
104     NGX_EVENT_MODULE,                      /* module type */
105     NULL,                                  /* init master */
106     NULL,                                  /* init module */
107     NULL,                                  /* init process */
108     NULL,                                  /* init thread */
109     NULL,                                  /* exit thread */
110     NULL,                                  /* exit process */
111     NULL,                                  /* exit master */
112     NGX_MODULE_V1_PADDING
113 };
114
115
116
117 static ngx_int_t
118 ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
119 {
120     ngx_kqueue_conf_t  *kcf;
121     struct timespec     ts;
122 #if (NGX_HAVE_TIMER_EVENT)
123     struct kevent       kev;
124 #endif
125
126     kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module);
127
128     if (ngx_kqueue == -1) {
129         ngx_kqueue = kqueue();
130
131         if (ngx_kqueue == -1) {
132             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
133                           "kqueue() failed");
134             return NGX_ERROR;
135         }
136
137 #if (NGX_THREADS)
138
139         list_mutex = ngx_mutex_init(cycle->log, 0);
140         if (list_mutex == NULL) {
141             return NGX_ERROR;
142         }
143
144         kevent_mutex = ngx_mutex_init(cycle->log, 0);
145         if (kevent_mutex == NULL) {
146             return NGX_ERROR;
147         }
148
149 #endif
150     }
151
152     if (max_changes < kcf->changes) {
153         if (nchanges) {
154             ts.tv_sec = 0;
155             ts.tv_nsec = 0;
156
157             if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
158                 == -1)
159             {
160                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
161                               "kevent() failed");
162                 return NGX_ERROR;
163             }
164             nchanges = 0;
165         }
166
167         if (change_list0) {
168             ngx_free(change_list0);
169         }
170
171         change_list0 = ngx_alloc(kcf->changes * sizeof(struct kevent),
172                                  cycle->log);
173         if (change_list0 == NULL) {
174             return NGX_ERROR;
175         }
176
177         if (change_list1) {
178             ngx_free(change_list1);
179         }
180
181         change_list1 = ngx_alloc(kcf->changes * sizeof(struct kevent),
182                                  cycle->log);
183         if (change_list1 == NULL) {
184             return NGX_ERROR;
185         }
186
187         change_list = change_list0;
188     }
189
190     max_changes = kcf->changes;
191
192     if (nevents < kcf->events) {
193         if (event_list) {
194             ngx_free(event_list);
195         }
196
197         event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log);
198         if (event_list == NULL) {
199             return NGX_ERROR;
200         }
201     }
202
203     ngx_event_flags = NGX_USE_ONESHOT_EVENT
204                       |NGX_USE_KQUEUE_EVENT
205                       |NGX_USE_VNODE_EVENT;
206
207 #if (NGX_HAVE_TIMER_EVENT)
208
209     if (timer) {
210         kev.ident = 0;
211         kev.filter = EVFILT_TIMER;
212         kev.flags = EV_ADD|EV_ENABLE;
213         kev.fflags = 0;
214         kev.data = timer;
215         kev.udata = 0;
216
217         ts.tv_sec = 0;
218         ts.tv_nsec = 0;
219
220         if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) {
221             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
222                           "kevent(EVFILT_TIMER) failed");
223             return NGX_ERROR;
224         }
225
226         ngx_event_flags |= NGX_USE_TIMER_EVENT;
227     }
228
229 #endif
230
231 #if (NGX_HAVE_CLEAR_EVENT)
232     ngx_event_flags |= NGX_USE_CLEAR_EVENT;
233 #else
234     ngx_event_flags |= NGX_USE_LEVEL_EVENT;
235 #endif
236
237 #if (NGX_HAVE_LOWAT_EVENT)
238     ngx_event_flags |= NGX_USE_LOWAT_EVENT;
239 #endif
240
241     nevents = kcf->events;
242
243     ngx_io = ngx_os_io;
244
245     ngx_event_actions = ngx_kqueue_module_ctx.actions;
246
247     return NGX_OK;
248 }
249
250
251 static void
252 ngx_kqueue_done(ngx_cycle_t *cycle)
253 {
254     if (close(ngx_kqueue) == -1) {
255         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
256                       "kqueue close() failed");
257     }
258
259     ngx_kqueue = -1;
260
261 #if (NGX_THREADS)
262     ngx_mutex_destroy(kevent_mutex);
263     ngx_mutex_destroy(list_mutex);
264 #endif
265
266     ngx_free(change_list1);
267     ngx_free(change_list0);
268     ngx_free(event_list);
269
270     change_list1 = NULL;
271     change_list0 = NULL;
272     change_list = NULL;
273     event_list = NULL;
274     max_changes = 0;
275     nchanges = 0;
276     nevents = 0;
277 }
278
279
280 static ngx_int_t
281 ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
282 {
283     ngx_int_t          rc;
284 #if 0
285     ngx_event_t       *e;
286     ngx_connection_t  *c;
287 #endif
288
289     ev->active = 1;
290     ev->disabled = 0;
291     ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
292
293     ngx_mutex_lock(list_mutex);
294
295 #if 0
296
297     if (ev->index < nchanges
298         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
299             == (uintptr_t) ev)
300     {
301         if (change_list[ev->index].flags == EV_DISABLE) {
302
303             /*
304              * if the EV_DISABLE is still not passed to a kernel
305              * we will not pass it
306              */
307
308             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
309                            "kevent activated: %d: ft:%i",
310                            ngx_event_ident(ev->data), event);
311
312             if (ev->index < --nchanges) {
313                 e = (ngx_event_t *)
314                     ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
315                 change_list[ev->index] = change_list[nchanges];
316                 e->index = ev->index;
317             }
318
319             ngx_mutex_unlock(list_mutex);
320
321             return NGX_OK;
322         }
323
324         c = ev->data;
325
326         ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
327                       "previous event on #%d were not passed in kernel", c->fd);
328
329         ngx_mutex_unlock(list_mutex);
330
331         return NGX_ERROR;
332     }
333
334 #endif
335
336     rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
337
338     ngx_mutex_unlock(list_mutex);
339
340     return rc;
341 }
342
343
344 static ngx_int_t
345 ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
346 {
347     ngx_int_t     rc;
348     ngx_event_t  *e;
349
350     ev->active = 0;
351     ev->disabled = 0;
352
353     ngx_mutex_lock(list_mutex);
354
355     if (ev->index < nchanges
356         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
357             == (uintptr_t) ev)
358     {
359         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
360                        "kevent deleted: %d: ft:%i",
361                        ngx_event_ident(ev->data), event);
362
363         /* if the event is still not passed to a kernel we will not pass it */
364
365         nchanges--;
366
367         if (ev->index < nchanges) {
368             e = (ngx_event_t *)
369                     ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
370             change_list[ev->index] = change_list[nchanges];
371             e->index = ev->index;
372         }
373
374         ngx_mutex_unlock(list_mutex);
375
376         return NGX_OK;
377     }
378
379     /*
380      * when the file descriptor is closed the kqueue automatically deletes
381      * its filters so we do not need to delete explicity the event
382      * before the closing the file descriptor.
383      */
384
385     if (flags & NGX_CLOSE_EVENT) {
386         ngx_mutex_unlock(list_mutex);
387         return NGX_OK;
388     }
389
390     if (flags & NGX_DISABLE_EVENT) {
391         ev->disabled = 1;
392
393     } else {
394         flags |= EV_DELETE;
395     }
396
397     rc = ngx_kqueue_set_event(ev, event, flags);
398
399     ngx_mutex_unlock(list_mutex);
400
401     return rc;
402 }
403
404
405 static ngx_int_t
406 ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
407 {
408     struct kevent     *kev;
409     struct timespec    ts;
410     ngx_connection_t  *c;
411
412     c = ev->data;
413
414     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
415                    "kevent set event: %d: ft:%i fl:%04Xi",
416                    c->fd, filter, flags);
417
418     if (nchanges >= max_changes) {
419         ngx_log_error(NGX_LOG_WARN, ev->log, 0,
420                       "kqueue change list is filled up");
421
422         ts.tv_sec = 0;
423         ts.tv_nsec = 0;
424
425         if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
426             == -1)
427         {
428             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
429             return NGX_ERROR;
430         }
431
432         nchanges = 0;
433     }
434
435     kev = &change_list[nchanges];
436
437     kev->ident = c->fd;
438     kev->filter = (short) filter;
439     kev->flags = (u_short) flags;
440     kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ev | ev->instance);
441
442     if (filter == EVFILT_VNODE) {
443         kev->fflags = NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND
444                                  |NOTE_ATTRIB|NOTE_RENAME
445 #if (__FreeBSD__ == 4 && __FreeBSD_version >= 430000) \
446     || __FreeBSD_version >= 500018
447                                  |NOTE_REVOKE
448 #endif
449                       ;
450         kev->data = 0;
451
452     } else {
453 #if (NGX_HAVE_LOWAT_EVENT)
454         if (flags & NGX_LOWAT_EVENT) {
455             kev->fflags = NOTE_LOWAT;
456             kev->data = ev->available;
457
458         } else {
459             kev->fflags = 0;
460             kev->data = 0;
461         }
462 #else
463         kev->fflags = 0;
464         kev->data = 0;
465 #endif
466     }
467
468     ev->index = nchanges;
469     nchanges++;
470
471     if (flags & NGX_FLUSH_EVENT) {
472         ts.tv_sec = 0;
473         ts.tv_nsec = 0;
474
475         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");
476
477         if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
478             == -1)
479         {
480             ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
481             return NGX_ERROR;
482         }
483
484         nchanges = 0;
485     }
486
487     return NGX_OK;
488 }
489
490
491 static ngx_int_t
492 ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
493     ngx_uint_t flags)
494 {
495     int               events, n;
496     ngx_int_t         i, instance;
497     ngx_uint_t        level;
498     ngx_err_t         err;
499     ngx_event_t      *ev, **queue;
500     struct timespec   ts, *tp;
501
502     if (ngx_threaded) {
503         if (ngx_kqueue_process_changes(cycle, 0) == NGX_ERROR) {
504             return NGX_ERROR;
505         }
506
507         n = 0;
508
509     } else {
510         n = (int) nchanges;
511         nchanges = 0;
512     }
513
514     if (timer == NGX_TIMER_INFINITE) {
515         tp = NULL;
516
517     } else {
518
519         ts.tv_sec = timer / 1000;
520         ts.tv_nsec = (timer % 1000) * 1000000;
521
522         /*
523          * 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
524          * the int32_t while user level ts.tv_nsec is the long (64-bit),
525          * so on the big endian PowerPC all nanoseconds are lost.
526          */
527
528 #if (NGX_DARWIN_KEVENT_BUG)
529         ts.tv_nsec <<= 32;
530 #endif
531
532         tp = &ts;
533     }
534
535     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
536                    "kevent timer: %M, changes: %d", timer, n);
537
538     events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);
539
540     if (events == -1) {
541         err = ngx_errno;
542     } else {
543         err = 0;
544     }
545
546     if (flags & NGX_UPDATE_TIME) {
547         ngx_time_update(0, 0);
548     }
549
550     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
551                    "kevent events: %d", events);
552
553     if (err) {
554         if (err == NGX_EINTR) {
555
556             if (ngx_event_timer_alarm) {
557                 ngx_event_timer_alarm = 0;
558                 return NGX_OK;
559             }
560
561             level = NGX_LOG_INFO;
562
563         } else {
564             level = NGX_LOG_ALERT;
565         }
566
567         ngx_log_error(level, cycle->log, err, "kevent() failed");
568         return NGX_ERROR;
569     }
570
571     if (events == 0) {
572         if (timer != NGX_TIMER_INFINITE) {
573             return NGX_OK;
574         }
575
576         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
577                       "kevent() returned no events without timeout");
578         return NGX_ERROR;
579     }
580
581     ngx_mutex_lock(ngx_posted_events_mutex);
582
583     for (i = 0; i < events; i++) {
584
585         ngx_kqueue_dump_event(cycle->log, &event_list[i]);
586
587         if (event_list[i].flags & EV_ERROR) {
588             ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
589                           "kevent() error on %d filter:%d flags:%04Xd",
590                           event_list[i].ident, event_list[i].filter,
591                           event_list[i].flags);
592             continue;
593         }
594
595 #if (NGX_HAVE_TIMER_EVENT)
596
597         if (event_list[i].filter == EVFILT_TIMER) {
598             ngx_time_update(0, 0);
599             continue;
600         }
601
602 #endif
603
604         ev = (ngx_event_t *) event_list[i].udata;
605
606         switch (event_list[i].filter) {
607
608         case EVFILT_READ:
609         case EVFILT_WRITE:
610
611             instance = (uintptr_t) ev & 1;
612             ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
613
614             if (ev->closed || ev->instance != instance) {
615
616                 /*
617                  * the stale event from a file descriptor
618                  * that was just closed in this iteration
619                  */
620
621                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
622                                "kevent: stale event %p", ev);
623                 continue;
624             }
625
626             if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
627                 ngx_kqueue_dump_event(ev->log, &event_list[i]);
628             }
629
630             if (ev->oneshot) {
631                 ev->active = 0;
632             }
633
634 #if (NGX_THREADS)
635
636             if ((flags & NGX_POST_THREAD_EVENTS) && !ev->accept) {
637                 ev->posted_ready = 1;
638                 ev->posted_available = event_list[i].data;
639
640                 if (event_list[i].flags & EV_EOF) {
641                     ev->posted_eof = 1;
642                     ev->posted_errno = event_list[i].fflags;
643                 }
644
645                 ngx_locked_post_event(ev, &ngx_posted_events);
646
647                 continue;
648             }
649
650 #endif
651
652             ev->available = event_list[i].data;
653
654             if (event_list[i].flags & EV_EOF) {
655                 ev->pending_eof = 1;
656                 ev->kq_errno = event_list[i].fflags;
657             }
658
659             ev->ready = 1;
660
661             break;
662
663         case EVFILT_VNODE:
664             ev->kq_vnode = 1;
665
666             break;
667
668         case EVFILT_AIO:
669             ev->complete = 1;
670             ev->ready = 1;
671
672             break;
673
674         default:
675             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
676                           "unexpected kevent() filter %d",
677                           event_list[i].filter);
678             continue;
679         }
680
681         if (flags & NGX_POST_EVENTS) {
682             queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
683                                                    &ngx_posted_events);
684             ngx_locked_post_event(ev, queue);
685
686             continue;
687         }
688
689         ev->handler(ev);
690     }
691
692     ngx_mutex_unlock(ngx_posted_events_mutex);
693
694     return NGX_OK;
695 }
696
697
698 static ngx_int_t
699 ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try)
700 {
701     int               n;
702     ngx_int_t         rc;
703     ngx_err_t         err;
704     struct timespec   ts;
705     struct kevent    *changes;
706
707     ngx_mutex_lock(kevent_mutex);
708
709     ngx_mutex_lock(list_mutex);
710
711     if (nchanges == 0) {
712         ngx_mutex_unlock(list_mutex);
713         ngx_mutex_unlock(kevent_mutex);
714         return NGX_OK;
715     }
716
717     changes = change_list;
718     if (change_list == change_list0) {
719         change_list = change_list1;
720     } else {
721         change_list = change_list0;
722     }
723
724     n = (int) nchanges;
725     nchanges = 0;
726
727     ngx_mutex_unlock(list_mutex);
728
729     ts.tv_sec = 0;
730     ts.tv_nsec = 0;
731
732     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
733                    "kevent changes: %d", n);
734
735     if (kevent(ngx_kqueue, changes, n, NULL, 0, &ts) == -1) {
736         err = ngx_errno;
737         ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
738                       cycle->log, err, "kevent() failed");
739         rc = NGX_ERROR;
740
741     } else {
742         rc = NGX_OK;
743     }
744
745     ngx_mutex_unlock(kevent_mutex);
746
747     return rc;
748 }
749
750
751 static ngx_inline void
752 ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
753 {
754     ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,
755                    (kev->ident > 0x8000000 && kev->ident != (unsigned) -1) ?
756                     "kevent: %p: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p":
757                     "kevent: %d: ft:%d fl:%04Xd ff:%08Xd d:%d ud:%p",
758                     kev->ident, kev->filter,
759                     kev->flags, kev->fflags,
760                     kev->data, kev->udata);
761 }
762
763
764 static void *
765 ngx_kqueue_create_conf(ngx_cycle_t *cycle)
766 {
767     ngx_kqueue_conf_t  *kcf;
768
769     kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t));
770     if (kcf == NULL) {
771         return NGX_CONF_ERROR;
772     }
773
774     kcf->changes = NGX_CONF_UNSET;
775     kcf->events = NGX_CONF_UNSET;
776
777     return kcf;
778 }
779
780
781 static char *
782 ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf)
783 {
784     ngx_kqueue_conf_t *kcf = conf;
785
786     ngx_conf_init_uint_value(kcf->changes, 512);
787     ngx_conf_init_uint_value(kcf->events, 512);
788
789     return NGX_CONF_OK;
790 }