blob: 4e82162a4d6367b53b1f15125fb1af5fb55a5a96 [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
Igor Sysoev42feecb2002-12-15 06:25:09 +000019/* should be per-thread */
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000020static int kq;
21static struct kevent *change_list, *event_list;
22static int nchanges, nevents;
23
24static ngx_event_t timer_queue;
Igor Sysoev42feecb2002-12-15 06:25:09 +000025/* */
26
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000027
Igor Sysoev31f88182002-09-27 15:05:29 +000028int ngx_kqueue_init(int max_connections, ngx_log_t *log)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000029{
30 int size = sizeof(struct kevent) * 512;
31
32 nchanges = 0;
33 nevents = 512;
34
Igor Sysoev1af7c822002-09-13 14:47:42 +000035 kq = kqueue();
36
37 if (kq == -1) {
38 ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "kqueue() failed");
Igor Sysoev31f88182002-09-27 15:05:29 +000039 return NGX_ERROR;
Igor Sysoev0ad17c02002-08-26 15:18:19 +000040 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000041
Igor Sysoev31f88182002-09-27 15:05:29 +000042 ngx_test_null(change_list, ngx_alloc(size, log), NGX_ERROR);
43 ngx_test_null(event_list, ngx_alloc(size, log), NGX_ERROR);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000044
45 timer_queue.timer_prev = &timer_queue;
46 timer_queue.timer_next = &timer_queue;
47
48#if !(USE_KQUEUE)
49 ngx_event_actions.add = ngx_kqueue_add_event;
50 ngx_event_actions.del = ngx_kqueue_del_event;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +000051 ngx_event_actions.timer = ngx_kqueue_add_timer;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000052 ngx_event_actions.process = ngx_kqueue_process_events;
53#endif
Igor Sysoev31f88182002-09-27 15:05:29 +000054
55 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000056}
57
Igor Sysoev42feecb2002-12-15 06:25:09 +000058
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000059int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
60{
Igor Sysoev3a40d482002-09-12 14:42:29 +000061 ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1: 0;
62
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000063 return ngx_kqueue_set_event(ev, event, EV_ADD | flags);
64}
65
Igor Sysoev42feecb2002-12-15 06:25:09 +000066
67int ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000068{
Igor Sysoev2ba1ee02002-10-04 17:58:04 +000069 ngx_event_t *e;
70
Igor Sysoev42feecb2002-12-15 06:25:09 +000071 if (ev->index < nchanges && change_list[ev->index].udata == ev) {
72
73 ngx_connection_t *cn = (ngx_connection_t *) ev->data;
74 ngx_log_debug(ev->log, "kqueue del event: %d: ft:%d" _
75 cn->fd _ event);
76
77 if (ev->index < --nchanges) {
78 e = (ngx_event_t *) change_list[nchanges].udata;
79 change_list[ev->index] = change_list[nchanges];
80 e->index = ev->index;
81 }
Igor Sysoev2ba1ee02002-10-04 17:58:04 +000082
83 return NGX_OK;
84 }
85
Igor Sysoev42feecb2002-12-15 06:25:09 +000086 if (flags & NGX_CLOSE_EVENT)
87 return NGX_OK;
88
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000089 return ngx_kqueue_set_event(ev, event, EV_DELETE);
90}
91
Igor Sysoev42feecb2002-12-15 06:25:09 +000092
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000093int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags)
94{
95 struct timespec ts = { 0, 0 };
96 ngx_connection_t *cn = (ngx_connection_t *) ev->data;
97
Igor Sysoev1af7c822002-09-13 14:47:42 +000098 ngx_log_debug(ev->log, "kqueue set event: %d: ft:%d f:%08x" _
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000099 cn->fd _ filter _ flags);
100
101 if (nchanges >= nevents) {
102 ngx_log_error(NGX_LOG_WARN, ev->log, 0,
Igor Sysoev31f88182002-09-27 15:05:29 +0000103 "kqueue change list is filled up");
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000104
105 if (kevent(kq, change_list, nchanges, NULL, 0, &ts) == -1) {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000106 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent failed");
107 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000108 }
109 nchanges = 0;
110 }
111
112 change_list[nchanges].ident = cn->fd;
113 change_list[nchanges].filter = filter;
114 change_list[nchanges].flags = flags;
115 change_list[nchanges].fflags = 0;
116 change_list[nchanges].data = 0;
117 change_list[nchanges].udata = ev;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000118
119 if (flags == EV_ADD)
120 ev->index = nchanges;
121
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000122 nchanges++;
123
Igor Sysoev1af7c822002-09-13 14:47:42 +0000124 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000125}
126
Igor Sysoev42feecb2002-12-15 06:25:09 +0000127
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000128int ngx_kqueue_process_events(ngx_log_t *log)
129{
130 int events, i;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000131 u_int timer, delta;
Igor Sysoevd4324e62002-09-17 17:49:32 +0000132 ngx_event_t *ev;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000133 struct timeval tv;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000134 struct timespec ts, *tp;
135
136 timer = 0;
137 delta = 0;
138 tp = NULL;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000139
140 if (timer_queue.timer_next != &timer_queue) {
141 timer = timer_queue.timer_next->timer_delta;
142 ts.tv_sec = timer / 1000;
143 ts.tv_nsec = (timer % 1000) * 1000000;
144 tp = &ts;
145 gettimeofday(&tv, NULL);
146 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000;
147 }
148
Igor Sysoev1af7c822002-09-13 14:47:42 +0000149 ngx_log_debug(log, "kevent timer: %d" _ timer);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000150
Igor Sysoev1af7c822002-09-13 14:47:42 +0000151 events = kevent(kq, change_list, nchanges, event_list, nevents, tp);
152 if (events == -1) {
153 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "kevent failed");
154 return NGX_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000155 }
156
157 nchanges = 0;
158
159 if (timer) {
160 gettimeofday(&tv, NULL);
161 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
162
163 } else {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000164 ngx_assert((events != 0), return NGX_ERROR, log,
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000165 "kevent returns no events without timeout");
166 }
167
Igor Sysoev1af7c822002-09-13 14:47:42 +0000168 ngx_log_debug(log, "kevent timer: %d, delta: %d" _ timer _ delta);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000169
170 if (timer) {
171 if (delta >= timer) {
Igor Sysoevd4324e62002-09-17 17:49:32 +0000172 for ( ;; ) {
173 ev = timer_queue.timer_next;
174
175 if (ev == &timer_queue || delta < ev->timer_delta)
176 break;
177
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000178 delta -= ev->timer_delta;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000179 ngx_del_timer(ev);
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000180 ev->timedout = 1;
Igor Sysoev016b8522002-08-29 16:59:54 +0000181 if (ev->event_handler(ev) == NGX_ERROR)
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000182 ev->close_handler(ev);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000183 }
184
185 } else {
186 timer_queue.timer_next->timer_delta -= delta;
187 }
188 }
189
190 for (i = 0; i < events; i++) {
191
Igor Sysoev1af7c822002-09-13 14:47:42 +0000192 ngx_log_debug(log, "kevent: %d: ft:%d f:%08x ff:%08x d:%d ud:%08x" _
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000193 event_list[i].ident _ event_list[i].filter _
194 event_list[i].flags _ event_list[i].fflags _
195 event_list[i].data _ event_list[i].udata);
196
197 if (event_list[i].flags & EV_ERROR) {
198 ngx_log_error(NGX_LOG_ALERT, log, event_list[i].data,
Igor Sysoev1af7c822002-09-13 14:47:42 +0000199 "kevent error on %d", event_list[i].ident);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000200 continue;
201 }
202
203 ev = (ngx_event_t *) event_list[i].udata;
204
205 switch (event_list[i].filter) {
206
207 case EVFILT_READ:
208 case EVFILT_WRITE:
209 ev->ready = 1;
210 ev->available = event_list[i].data;
211
212 if (event_list[i].flags & EV_EOF) {
213 ev->eof = 1;
214 ev->error = event_list[i].fflags;
215 }
216
Igor Sysoev3a40d482002-09-12 14:42:29 +0000217 if (ev->oneshot)
218 ngx_del_timer(ev);
219
Igor Sysoev016b8522002-08-29 16:59:54 +0000220 if (ev->event_handler(ev) == NGX_ERROR)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000221 ev->close_handler(ev);
222
223 break;
224
225 default:
226 ngx_assert(0, /* void */, log,
Igor Sysoev1af7c822002-09-13 14:47:42 +0000227 "unknown kevent filter %d" _ event_list[i].filter);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000228 }
229 }
230
Igor Sysoev1af7c822002-09-13 14:47:42 +0000231 return NGX_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000232}
233
Igor Sysoev42feecb2002-12-15 06:25:09 +0000234
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000235void ngx_kqueue_add_timer(ngx_event_t *ev, ngx_msec_t timer)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000236{
237 ngx_event_t *e;
238
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000239 ngx_log_debug(ev->log, "set timer: %d" _ timer);
240
Igor Sysoev3a40d482002-09-12 14:42:29 +0000241 ngx_assert((!ev->timer_next && !ev->timer_prev), return, ev->log,
242 "timer already set");
243
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000244 for (e = timer_queue.timer_next;
245 e != &timer_queue && timer > e->timer_delta;
246 e = e->timer_next)
247 timer -= e->timer_delta;
248
249 ev->timer_delta = timer;
250
251 ev->timer_next = e;
252 ev->timer_prev = e->timer_prev;
253
254 e->timer_prev->timer_next = ev;
255 e->timer_prev = ev;
256}