blob: 3b65f8063b8a6c59152c506180a006f6a438dca2 [file] [log] [blame]
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001/*
2 * Copyright (C) 2002 Igor Sysoev, http://sysoev.ru
3 */
4
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00005
6#include <ngx_config.h>
Igor Sysoev016b8522002-08-29 16:59:54 +00007#include <ngx_core.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00008#include <ngx_types.h>
9#include <ngx_log.h>
10#include <ngx_connection.h>
11#include <ngx_event.h>
12#include <ngx_kqueue_module.h>
13
14#if (USE_KQUEUE) && !(HAVE_KQUEUE)
15#error "kqueue is not supported on this platform"
16#endif
17
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000018
19
20static int kq;
21static struct kevent *change_list, *event_list;
22static int nchanges, nevents;
23
24static ngx_event_t timer_queue;
25
Igor Sysoev31f88182002-09-27 15:05:29 +000026int ngx_kqueue_init(int max_connections, ngx_log_t *log)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000027{
28 int size = sizeof(struct kevent) * 512;
29
30 nchanges = 0;
31 nevents = 512;
32
Igor Sysoev1af7c822002-09-13 14:47:42 +000033 kq = kqueue();
34
35 if (kq == -1) {
36 ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "kqueue() failed");
Igor Sysoev31f88182002-09-27 15:05:29 +000037 return NGX_ERROR;
Igor Sysoev0ad17c02002-08-26 15:18:19 +000038 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000039
Igor Sysoev31f88182002-09-27 15:05:29 +000040 ngx_test_null(change_list, ngx_alloc(size, log), NGX_ERROR);
41 ngx_test_null(event_list, ngx_alloc(size, log), NGX_ERROR);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000042
43 timer_queue.timer_prev = &timer_queue;
44 timer_queue.timer_next = &timer_queue;
45
46#if !(USE_KQUEUE)
47 ngx_event_actions.add = ngx_kqueue_add_event;
48 ngx_event_actions.del = ngx_kqueue_del_event;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +000049 ngx_event_actions.timer = ngx_kqueue_add_timer;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000050 ngx_event_actions.process = ngx_kqueue_process_events;
51#endif
Igor Sysoev31f88182002-09-27 15:05:29 +000052
53 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000054}
55
56int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
57{
Igor Sysoev3a40d482002-09-12 14:42:29 +000058 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1: 0;
59
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000060 return ngx_kqueue_set_event(ev, event, EV_ADD | flags);
61}
62
63int ngx_kqueue_del_event(ngx_event_t *ev, int event)
64{
Igor Sysoev2ba1ee02002-10-04 17:58:04 +000065 ngx_event_t *e;
66
67 if (ev->index <= nchanges && change_list[ev->index].udata == ev) {
68 change_list[ev->index] = change_list[nchanges];
69 e = (ngx_event_t *) change_list[ev->index].udata;
70 e->index = ev->index;
71 nchanges--;
72
73 return NGX_OK;
74 }
75
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000076 return ngx_kqueue_set_event(ev, event, EV_DELETE);
77}
78
79int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
80{
81 struct timespec ts = { 0, 0 };
82 ngx_connection_t *cn = (ngx_connection_t *) ev->data;
83
Igor Sysoev1af7c822002-09-13 14:47:42 +000084 ngx_log_debug(ev->log, "kqueue set event: %d: ft:%d f:%08x" _
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000085 cn->fd _ filter _ flags);
86
87 if (nchanges >= nevents) {
88 ngx_log_error(NGX_LOG_WARN, ev->log, 0,
Igor Sysoev31f88182002-09-27 15:05:29 +000089 "kqueue change list is filled up");
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000090
91 if (kevent(kq, change_list, nchanges, NULL, 0, &ts) == -1) {
Igor Sysoev1af7c822002-09-13 14:47:42 +000092 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent failed");
93 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000094 }
95 nchanges = 0;
96 }
97
98 change_list[nchanges].ident = cn->fd;
99 change_list[nchanges].filter = filter;
100 change_list[nchanges].flags = flags;
101 change_list[nchanges].fflags = 0;
102 change_list[nchanges].data = 0;
103 change_list[nchanges].udata = ev;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000104
105 if (flags == EV_ADD)
106 ev->index = nchanges;
107
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000108 nchanges++;
109
Igor Sysoev1af7c822002-09-13 14:47:42 +0000110 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000111}
112
113int ngx_kqueue_process_events(ngx_log_t *log)
114{
115 int events, i;
116 u_int timer = 0, delta = 0;
Igor Sysoevd4324e62002-09-17 17:49:32 +0000117 ngx_event_t *ev;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000118 struct timeval tv;
119 struct timespec ts, *tp = NULL;
120
121 if (timer_queue.timer_next != &timer_queue) {
122 timer = timer_queue.timer_next->timer_delta;
123 ts.tv_sec = timer / 1000;
124 ts.tv_nsec = (timer % 1000) * 1000000;
125 tp = &ts;
126 gettimeofday(&tv, NULL);
127 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000;
128 }
129
Igor Sysoev1af7c822002-09-13 14:47:42 +0000130 ngx_log_debug(log, "kevent timer: %d" _ timer);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000131
Igor Sysoev1af7c822002-09-13 14:47:42 +0000132 events = kevent(kq, change_list, nchanges, event_list, nevents, tp);
133 if (events == -1) {
134 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "kevent failed");
135 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000136 }
137
138 nchanges = 0;
139
140 if (timer) {
141 gettimeofday(&tv, NULL);
142 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
143
144 } else {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000145 ngx_assert((events != 0), return NGX_ERROR, log,
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000146 "kevent returns no events without timeout");
147 }
148
Igor Sysoev1af7c822002-09-13 14:47:42 +0000149 ngx_log_debug(log, "kevent timer: %d, delta: %d" _ timer _ delta);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000150
151 if (timer) {
152 if (delta >= timer) {
Igor Sysoevd4324e62002-09-17 17:49:32 +0000153 for ( ;; ) {
154 ev = timer_queue.timer_next;
155
156 if (ev == &timer_queue || delta < ev->timer_delta)
157 break;
158
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000159 delta -= ev->timer_delta;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000160 ngx_del_timer(ev);
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000161 ev->timedout = 1;
Igor Sysoev016b8522002-08-29 16:59:54 +0000162 if (ev->event_handler(ev) == NGX_ERROR)
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000163 ev->close_handler(ev);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000164 }
165
166 } else {
167 timer_queue.timer_next->timer_delta -= delta;
168 }
169 }
170
171 for (i = 0; i < events; i++) {
172
Igor Sysoev1af7c822002-09-13 14:47:42 +0000173 ngx_log_debug(log, "kevent: %d: ft:%d f:%08x ff:%08x d:%d ud:%08x" _
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000174 event_list[i].ident _ event_list[i].filter _
175 event_list[i].flags _ event_list[i].fflags _
176 event_list[i].data _ event_list[i].udata);
177
178 if (event_list[i].flags & EV_ERROR) {
179 ngx_log_error(NGX_LOG_ALERT, log, event_list[i].data,
Igor Sysoev1af7c822002-09-13 14:47:42 +0000180 "kevent error on %d", event_list[i].ident);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000181 continue;
182 }
183
184 ev = (ngx_event_t *) event_list[i].udata;
185
186 switch (event_list[i].filter) {
187
188 case EVFILT_READ:
189 case EVFILT_WRITE:
190 ev->ready = 1;
191 ev->available = event_list[i].data;
192
193 if (event_list[i].flags & EV_EOF) {
194 ev->eof = 1;
195 ev->error = event_list[i].fflags;
196 }
197
Igor Sysoev3a40d482002-09-12 14:42:29 +0000198 if (ev->oneshot)
199 ngx_del_timer(ev);
200
Igor Sysoev016b8522002-08-29 16:59:54 +0000201 if (ev->event_handler(ev) == NGX_ERROR)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000202 ev->close_handler(ev);
203
204 break;
205
206 default:
207 ngx_assert(0, /* void */, log,
Igor Sysoev1af7c822002-09-13 14:47:42 +0000208 "unknown kevent filter %d" _ event_list[i].filter);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000209 }
210 }
211
Igor Sysoev1af7c822002-09-13 14:47:42 +0000212 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000213}
214
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000215void ngx_kqueue_add_timer(ngx_event_t *ev, ngx_msec_t timer)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000216{
217 ngx_event_t *e;
218
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000219 ngx_log_debug(ev->log, "set timer: %d" _ timer);
220
Igor Sysoev3a40d482002-09-12 14:42:29 +0000221 ngx_assert((!ev->timer_next && !ev->timer_prev), return, ev->log,
222 "timer already set");
223
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000224 for (e = timer_queue.timer_next;
225 e != &timer_queue && timer > e->timer_delta;
226 e = e->timer_next)
227 timer -= e->timer_delta;
228
229 ev->timer_delta = timer;
230
231 ev->timer_next = e;
232 ev->timer_prev = e->timer_prev;
233
234 e->timer_prev->timer_next = ev;
235 e->timer_prev = ev;
236}