Mercurial > hg > nginx
comparison src/event/modules/ngx_epoll_module.c @ 245:e6c005b66b3a
nginx-0.0.1-2004-01-30-00:45:01 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Thu, 29 Jan 2004 21:45:01 +0000 |
parents | |
children | 6753e8cdaa2c |
comparison
equal
deleted
inserted
replaced
244:187dc0a3197d | 245:e6c005b66b3a |
---|---|
1 | |
2 /* | |
3 * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/ | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 | |
11 | |
12 #if (TEST_BUILD_EPOLL) | |
13 | |
14 /* epoll declarations */ | |
15 | |
16 #define EPOLLIN 0x001 | |
17 #define EPOLLPRI 0x002 | |
18 #define EPOLLOUT 0x004 | |
19 #define EPOLLRDNORM 0x040 | |
20 #define EPOLLRDBAND 0x080 | |
21 #define EPOLLWRNORM 0x100 | |
22 #define EPOLLWRBAND 0x200 | |
23 #define EPOLLMSG 0x400 | |
24 #define EPOLLERR 0x008 | |
25 #define EPOLLHUP 0x010 | |
26 | |
27 #define EPOLL_CTL_ADD 1 | |
28 #define EPOLL_CTL_DEL 2 | |
29 #define EPOLL_CTL_MOD 3 | |
30 | |
31 typedef union epoll_data { | |
32 void *ptr; | |
33 int fd; | |
34 uint32_t u32; | |
35 uint64_t u64; | |
36 } epoll_data_t; | |
37 | |
38 struct epoll_event { | |
39 uint32_t events; | |
40 epoll_data_t data; | |
41 }; | |
42 | |
43 int epoll_create(int size); | |
44 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); | |
45 int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout); | |
46 | |
47 int epoll_create(int size) | |
48 { | |
49 return -1; | |
50 } | |
51 | |
52 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) | |
53 { | |
54 return -1; | |
55 } | |
56 | |
57 int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout) | |
58 { | |
59 return -1; | |
60 } | |
61 | |
62 #endif | |
63 | |
64 | |
65 typedef struct { | |
66 u_int events; | |
67 } ngx_epoll_conf_t; | |
68 | |
69 | |
70 static int ngx_epoll_init(ngx_cycle_t *cycle); | |
71 static void ngx_epoll_done(ngx_cycle_t *cycle); | |
72 static int ngx_epoll_add_connection(ngx_connection_t *c); | |
73 static int ngx_epoll_del_connection(ngx_connection_t *c); | |
74 static int ngx_epoll_process_events(ngx_log_t *log); | |
75 | |
76 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle); | |
77 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf); | |
78 | |
79 static int ep = -1; | |
80 static struct epoll_event *event_list; | |
81 static u_int nevents; | |
82 | |
83 | |
84 static ngx_str_t epoll_name = ngx_string("epoll"); | |
85 | |
86 static ngx_command_t ngx_epoll_commands[] = { | |
87 | |
88 {ngx_string("epoll_events"), | |
89 NGX_EVENT_CONF|NGX_CONF_TAKE1, | |
90 ngx_conf_set_num_slot, | |
91 0, | |
92 offsetof(ngx_epoll_conf_t, events), | |
93 NULL}, | |
94 | |
95 ngx_null_command | |
96 }; | |
97 | |
98 | |
99 ngx_event_module_t ngx_epoll_module_ctx = { | |
100 &epoll_name, | |
101 ngx_epoll_create_conf, /* create configuration */ | |
102 ngx_epoll_init_conf, /* init configuration */ | |
103 | |
104 { | |
105 NULL, /* add an event */ | |
106 NULL, /* delete an event */ | |
107 NULL, /* enable an event */ | |
108 NULL, /* disable an event */ | |
109 ngx_epoll_add_connection, /* add an connection */ | |
110 ngx_epoll_del_connection, /* delete an connection */ | |
111 ngx_epoll_process_events, /* process the events */ | |
112 ngx_epoll_init, /* init the events */ | |
113 ngx_epoll_done, /* done the events */ | |
114 } | |
115 | |
116 }; | |
117 | |
118 ngx_module_t ngx_epoll_module = { | |
119 NGX_MODULE, | |
120 &ngx_epoll_module_ctx, /* module context */ | |
121 ngx_epoll_commands, /* module directives */ | |
122 NGX_EVENT_MODULE, /* module type */ | |
123 NULL, /* init module */ | |
124 NULL /* init child */ | |
125 }; | |
126 | |
127 | |
128 static int ngx_epoll_init(ngx_cycle_t *cycle) | |
129 { | |
130 size_t n; | |
131 ngx_epoll_conf_t *epcf; | |
132 | |
133 epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module); | |
134 | |
135 if (ep == -1) { | |
136 ep = epoll_create(/* STUB: open_files / 2 */ 512); | |
137 | |
138 if (ep == -1) { | |
139 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, | |
140 "epoll_create() failed"); | |
141 return NGX_ERROR; | |
142 } | |
143 } | |
144 | |
145 if (nevents < epcf->events) { | |
146 if (event_list) { | |
147 ngx_free(event_list); | |
148 } | |
149 | |
150 event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events, | |
151 cycle->log); | |
152 if (event_list == NULL) { | |
153 return NGX_ERROR; | |
154 } | |
155 } | |
156 | |
157 nevents = epcf->events; | |
158 | |
159 ngx_io = ngx_os_io; | |
160 | |
161 ngx_event_actions = ngx_epoll_module_ctx.actions; | |
162 | |
163 ngx_event_flags = NGX_USE_EDGE_EVENT; | |
164 | |
165 return NGX_OK; | |
166 } | |
167 | |
168 | |
169 static void ngx_epoll_done(ngx_cycle_t *cycle) | |
170 { | |
171 if (close(ep) == -1) { | |
172 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
173 "epoll close() failed"); | |
174 } | |
175 | |
176 ep = -1; | |
177 | |
178 ngx_free(event_list); | |
179 | |
180 event_list = NULL; | |
181 nevents = 0; | |
182 } | |
183 | |
184 | |
185 static int ngx_epoll_add_connection(ngx_connection_t *c) | |
186 { | |
187 struct epoll_event ev; | |
188 | |
189 ev.events = EPOLLIN|EPOLLOUT; | |
190 ev.data.ptr = (void *) ((uintptr_t) c | c->read->instance); | |
191 | |
192 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
193 "epoll add connection: fd:%d ev:%04X", c->fd, ev.events); | |
194 | |
195 if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd, &ev) == -1) { | |
196 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, | |
197 "epoll_ctl(#%d) failed", c->fd); | |
198 return NGX_ERROR; | |
199 } | |
200 | |
201 return NGX_OK; | |
202 } | |
203 | |
204 | |
205 static int ngx_epoll_del_connection(ngx_connection_t *c) | |
206 { | |
207 c->read->active = 0; | |
208 c->write->active = 0; | |
209 | |
210 return NGX_OK; | |
211 } | |
212 | |
213 | |
214 int ngx_epoll_process_events(ngx_log_t *log) | |
215 { | |
216 int events; | |
217 ngx_int_t instance, i; | |
218 size_t n; | |
219 ngx_msec_t timer; | |
220 ngx_err_t err; | |
221 ngx_cycle_t **cycle; | |
222 struct timeval tv; | |
223 ngx_connection_t *c; | |
224 ngx_epoch_msec_t delta; | |
225 | |
226 | |
227 timer = ngx_event_find_timer(); | |
228 ngx_old_elapsed_msec = ngx_elapsed_msec; | |
229 | |
230 if (timer == 0) { | |
231 timer = (ngx_msec_t) -1; | |
232 } | |
233 | |
234 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "epoll timer: %d", timer); | |
235 | |
236 events = epoll_wait(ep, event_list, nevents, timer); | |
237 | |
238 if (events == -1) { | |
239 err = ngx_errno; | |
240 } else { | |
241 err = 0; | |
242 } | |
243 | |
244 ngx_gettimeofday(&tv); | |
245 ngx_time_update(tv.tv_sec); | |
246 | |
247 delta = ngx_elapsed_msec; | |
248 ngx_elapsed_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000 - ngx_start_msec; | |
249 | |
250 if ((int) timer != INFTIM) { | |
251 delta = ngx_elapsed_msec - delta; | |
252 | |
253 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, | |
254 "epoll timer: %d, delta: %d", timer, (int) delta); | |
255 } else { | |
256 if (events == 0) { | |
257 ngx_log_error(NGX_LOG_ALERT, log, 0, | |
258 "epoll_wait() returned no events without timeout"); | |
259 return NGX_ERROR; | |
260 } | |
261 } | |
262 | |
263 if (err) { | |
264 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, | |
265 log, err, "epoll_wait() failed"); | |
266 return NGX_ERROR; | |
267 } | |
268 | |
269 for (i = 0; i < events; i++) { | |
270 c = event_list[i].data.ptr; | |
271 | |
272 instance = (uintptr_t) c & 1; | |
273 c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1); | |
274 | |
275 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, | |
276 "epoll: fd:%d ev:%04X d:" PTR_FMT, | |
277 c->fd, event_list[i].events, event_list[i].data); | |
278 | |
279 if (c->read->instance != instance) { | |
280 | |
281 /* | |
282 * it's a stale event from a file descriptor | |
283 * that was just closed in this iteration | |
284 */ | |
285 | |
286 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, | |
287 "epoll: stale event " PTR_FMT, c); | |
288 continue; | |
289 } | |
290 | |
291 if (event_list[i].events & EPOLLIN) { | |
292 if (!c->read->active) { | |
293 continue; | |
294 } | |
295 | |
296 c->read->ready = 1; | |
297 c->read->event_handler(c->read); | |
298 } | |
299 | |
300 if (event_list[i].events & EPOLLOUT) { | |
301 if (!c->write->active) { | |
302 continue; | |
303 } | |
304 | |
305 c->write->ready = 1; | |
306 c->write->event_handler(c->write); | |
307 } | |
308 | |
309 if (event_list[i].events & (EPOLLERR|EPOLLHUP|EPOLLMSG)) { | |
310 ngx_log_error(NGX_LOG_ERR, log, 0, | |
311 "epoll_wait() error on fd:%d ev:%d", | |
312 c->fd, event_list[i].events); | |
313 } | |
314 } | |
315 | |
316 if (timer != (ngx_msec_t) -1 && delta) { | |
317 ngx_event_expire_timers((ngx_msec_t) delta); | |
318 } | |
319 | |
320 return NGX_OK; | |
321 } | |
322 | |
323 | |
324 static void *ngx_epoll_create_conf(ngx_cycle_t *cycle) | |
325 { | |
326 ngx_epoll_conf_t *epcf; | |
327 | |
328 ngx_test_null(epcf, ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t)), | |
329 NGX_CONF_ERROR); | |
330 | |
331 epcf->events = NGX_CONF_UNSET; | |
332 | |
333 return epcf; | |
334 } | |
335 | |
336 | |
337 static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf) | |
338 { | |
339 ngx_epoll_conf_t *epcf = conf; | |
340 | |
341 ngx_conf_init_unsigned_value(epcf->events, 512); | |
342 | |
343 return NGX_CONF_OK; | |
344 } |