Mercurial > hg > nginx
comparison src/event/modules/ngx_win32_poll_module.c @ 7444:4089b3d2cb59
Win32: added WSAPoll() support.
WSAPoll() is only available with Windows Vista and newer (and only
available during compilation if _WIN32_WINNT >= 0x0600). To make
sure the code works with Windows XP, we do not redefine _WIN32_WINNT,
but instead load WSAPoll() dynamically if it is not available during
compilation.
Also, sockets are not guaranteed to be small integers on Windows.
So an index array is used instead of NGX_USE_FD_EVENT to map
events to connections.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 24 Jan 2019 21:51:21 +0300 |
parents | src/event/modules/ngx_poll_module.c@e0e636ab10be |
children | efd71d49bde0 |
comparison
equal
deleted
inserted
replaced
7443:f3ff79ae31d9 | 7444:4089b3d2cb59 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 * Copyright (C) Maxim Dounin | |
5 * Copyright (C) Nginx, Inc. | |
6 */ | |
7 | |
8 | |
9 #include <ngx_config.h> | |
10 #include <ngx_core.h> | |
11 #include <ngx_event.h> | |
12 | |
13 | |
14 static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer); | |
15 static void ngx_poll_done(ngx_cycle_t *cycle); | |
16 static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, | |
17 ngx_uint_t flags); | |
18 static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, | |
19 ngx_uint_t flags); | |
20 static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, | |
21 ngx_uint_t flags); | |
22 static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf); | |
23 | |
24 | |
25 static struct pollfd *event_list; | |
26 static ngx_connection_t **event_index; | |
27 static ngx_uint_t nevents; | |
28 | |
29 | |
30 static ngx_str_t poll_name = ngx_string("poll"); | |
31 | |
32 static ngx_event_module_t ngx_poll_module_ctx = { | |
33 &poll_name, | |
34 NULL, /* create configuration */ | |
35 ngx_poll_init_conf, /* init configuration */ | |
36 | |
37 { | |
38 ngx_poll_add_event, /* add an event */ | |
39 ngx_poll_del_event, /* delete an event */ | |
40 ngx_poll_add_event, /* enable an event */ | |
41 ngx_poll_del_event, /* disable an event */ | |
42 NULL, /* add an connection */ | |
43 NULL, /* delete an connection */ | |
44 NULL, /* trigger a notify */ | |
45 ngx_poll_process_events, /* process the events */ | |
46 ngx_poll_init, /* init the events */ | |
47 ngx_poll_done /* done the events */ | |
48 } | |
49 | |
50 }; | |
51 | |
52 ngx_module_t ngx_poll_module = { | |
53 NGX_MODULE_V1, | |
54 &ngx_poll_module_ctx, /* module context */ | |
55 NULL, /* module directives */ | |
56 NGX_EVENT_MODULE, /* module type */ | |
57 NULL, /* init master */ | |
58 NULL, /* init module */ | |
59 NULL, /* init process */ | |
60 NULL, /* init thread */ | |
61 NULL, /* exit thread */ | |
62 NULL, /* exit process */ | |
63 NULL, /* exit master */ | |
64 NGX_MODULE_V1_PADDING | |
65 }; | |
66 | |
67 | |
68 | |
69 static ngx_int_t | |
70 ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer) | |
71 { | |
72 struct pollfd *list; | |
73 ngx_connection_t **index; | |
74 | |
75 if (event_list == NULL) { | |
76 nevents = 0; | |
77 } | |
78 | |
79 if (ngx_process >= NGX_PROCESS_WORKER | |
80 || cycle->old_cycle == NULL | |
81 || cycle->old_cycle->connection_n < cycle->connection_n) | |
82 { | |
83 list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n, | |
84 cycle->log); | |
85 if (list == NULL) { | |
86 return NGX_ERROR; | |
87 } | |
88 | |
89 if (event_list) { | |
90 ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents); | |
91 ngx_free(event_list); | |
92 } | |
93 | |
94 event_list = list; | |
95 | |
96 index = ngx_alloc(sizeof(ngx_connection_t *) * cycle->connection_n, | |
97 cycle->log); | |
98 if (index == NULL) { | |
99 return NGX_ERROR; | |
100 } | |
101 | |
102 if (event_index) { | |
103 ngx_memcpy(index, event_index, | |
104 sizeof(ngx_connection_t *) * nevents); | |
105 ngx_free(event_index); | |
106 } | |
107 | |
108 event_index = index; | |
109 } | |
110 | |
111 ngx_io = ngx_os_io; | |
112 | |
113 ngx_event_actions = ngx_poll_module_ctx.actions; | |
114 | |
115 ngx_event_flags = NGX_USE_LEVEL_EVENT; | |
116 | |
117 return NGX_OK; | |
118 } | |
119 | |
120 | |
121 static void | |
122 ngx_poll_done(ngx_cycle_t *cycle) | |
123 { | |
124 ngx_free(event_list); | |
125 ngx_free(event_index); | |
126 | |
127 event_list = NULL; | |
128 event_index = NULL; | |
129 } | |
130 | |
131 | |
132 static ngx_int_t | |
133 ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) | |
134 { | |
135 ngx_event_t *e; | |
136 ngx_connection_t *c; | |
137 | |
138 c = ev->data; | |
139 | |
140 ev->active = 1; | |
141 | |
142 if (ev->index != NGX_INVALID_INDEX) { | |
143 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
144 "poll event fd:%d ev:%i is already set", c->fd, event); | |
145 return NGX_OK; | |
146 } | |
147 | |
148 if (event == NGX_READ_EVENT) { | |
149 e = c->write; | |
150 #if (NGX_READ_EVENT != POLLIN) | |
151 event = POLLIN; | |
152 #endif | |
153 | |
154 } else { | |
155 e = c->read; | |
156 #if (NGX_WRITE_EVENT != POLLOUT) | |
157 event = POLLOUT; | |
158 #endif | |
159 } | |
160 | |
161 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
162 "poll add event: fd:%d ev:%i", c->fd, event); | |
163 | |
164 if (e == NULL || e->index == NGX_INVALID_INDEX) { | |
165 | |
166 event_list[nevents].fd = c->fd; | |
167 event_list[nevents].events = (short) event; | |
168 event_list[nevents].revents = 0; | |
169 | |
170 event_index[nevents] = c; | |
171 | |
172 ev->index = nevents; | |
173 nevents++; | |
174 | |
175 } else { | |
176 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
177 "poll add index: %i", e->index); | |
178 | |
179 event_list[e->index].events |= (short) event; | |
180 ev->index = e->index; | |
181 } | |
182 | |
183 return NGX_OK; | |
184 } | |
185 | |
186 | |
187 static ngx_int_t | |
188 ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) | |
189 { | |
190 ngx_event_t *e; | |
191 ngx_connection_t *c; | |
192 | |
193 c = ev->data; | |
194 | |
195 ev->active = 0; | |
196 | |
197 if (ev->index == NGX_INVALID_INDEX) { | |
198 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
199 "poll event fd:%d ev:%i is already deleted", | |
200 c->fd, event); | |
201 return NGX_OK; | |
202 } | |
203 | |
204 if (event == NGX_READ_EVENT) { | |
205 e = c->write; | |
206 #if (NGX_READ_EVENT != POLLIN) | |
207 event = POLLIN; | |
208 #endif | |
209 | |
210 } else { | |
211 e = c->read; | |
212 #if (NGX_WRITE_EVENT != POLLOUT) | |
213 event = POLLOUT; | |
214 #endif | |
215 } | |
216 | |
217 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
218 "poll del event: fd:%d ev:%i", c->fd, event); | |
219 | |
220 if (e == NULL || e->index == NGX_INVALID_INDEX) { | |
221 nevents--; | |
222 | |
223 if (ev->index < nevents) { | |
224 | |
225 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
226 "index: copy event %ui to %i", nevents, ev->index); | |
227 | |
228 event_list[ev->index] = event_list[nevents]; | |
229 event_index[ev->index] = event_index[nevents]; | |
230 | |
231 c = event_index[ev->index]; | |
232 | |
233 if (c->fd == (ngx_socket_t) -1) { | |
234 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
235 "unexpected last event"); | |
236 | |
237 } else { | |
238 if (c->read->index == nevents) { | |
239 c->read->index = ev->index; | |
240 } | |
241 | |
242 if (c->write->index == nevents) { | |
243 c->write->index = ev->index; | |
244 } | |
245 } | |
246 } | |
247 | |
248 } else { | |
249 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
250 "poll del index: %i", e->index); | |
251 | |
252 event_list[e->index].events &= (short) ~event; | |
253 } | |
254 | |
255 ev->index = NGX_INVALID_INDEX; | |
256 | |
257 return NGX_OK; | |
258 } | |
259 | |
260 | |
261 static ngx_int_t | |
262 ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) | |
263 { | |
264 int ready, revents; | |
265 ngx_err_t err; | |
266 ngx_uint_t i, found; | |
267 ngx_event_t *ev; | |
268 ngx_queue_t *queue; | |
269 ngx_connection_t *c; | |
270 | |
271 /* NGX_TIMER_INFINITE == INFTIM */ | |
272 | |
273 #if (NGX_DEBUG0) | |
274 if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { | |
275 for (i = 0; i < nevents; i++) { | |
276 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
277 "poll: %ui: fd:%d ev:%04Xd", | |
278 i, event_list[i].fd, event_list[i].events); | |
279 } | |
280 } | |
281 #endif | |
282 | |
283 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer); | |
284 | |
285 ready = WSAPoll(event_list, (u_int) nevents, (int) timer); | |
286 | |
287 err = (ready == -1) ? ngx_errno : 0; | |
288 | |
289 if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { | |
290 ngx_time_update(); | |
291 } | |
292 | |
293 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
294 "poll ready %d of %ui", ready, nevents); | |
295 | |
296 if (err) { | |
297 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "WSAPoll() failed"); | |
298 return NGX_ERROR; | |
299 } | |
300 | |
301 if (ready == 0) { | |
302 if (timer != NGX_TIMER_INFINITE) { | |
303 return NGX_OK; | |
304 } | |
305 | |
306 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
307 "WSAPoll() returned no events without timeout"); | |
308 return NGX_ERROR; | |
309 } | |
310 | |
311 for (i = 0; i < nevents && ready; i++) { | |
312 | |
313 revents = event_list[i].revents; | |
314 | |
315 #if 1 | |
316 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
317 "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", | |
318 i, event_list[i].fd, event_list[i].events, revents); | |
319 #else | |
320 if (revents) { | |
321 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
322 "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", | |
323 i, event_list[i].fd, event_list[i].events, revents); | |
324 } | |
325 #endif | |
326 | |
327 if (revents & POLLNVAL) { | |
328 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
329 "poll() error fd:%d ev:%04Xd rev:%04Xd", | |
330 event_list[i].fd, event_list[i].events, revents); | |
331 } | |
332 | |
333 if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) { | |
334 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
335 "strange poll() events fd:%d ev:%04Xd rev:%04Xd", | |
336 event_list[i].fd, event_list[i].events, revents); | |
337 } | |
338 | |
339 if (event_list[i].fd == (ngx_socket_t) -1) { | |
340 /* | |
341 * the disabled event, a workaround for our possible bug, | |
342 * see the comment below | |
343 */ | |
344 continue; | |
345 } | |
346 | |
347 c = event_index[i]; | |
348 | |
349 if (c->fd == (ngx_socket_t) -1) { | |
350 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event"); | |
351 | |
352 /* | |
353 * it is certainly our fault and it should be investigated, | |
354 * in the meantime we disable this event to avoid a CPU spinning | |
355 */ | |
356 | |
357 if (i == nevents - 1) { | |
358 nevents--; | |
359 } else { | |
360 event_list[i].fd = (ngx_socket_t) -1; | |
361 } | |
362 | |
363 continue; | |
364 } | |
365 | |
366 if (revents & (POLLERR|POLLHUP|POLLNVAL)) { | |
367 | |
368 /* | |
369 * if the error events were returned, add POLLIN and POLLOUT | |
370 * to handle the events at least in one active handler | |
371 */ | |
372 | |
373 revents |= POLLIN|POLLOUT; | |
374 } | |
375 | |
376 found = 0; | |
377 | |
378 if ((revents & POLLIN) && c->read->active) { | |
379 found = 1; | |
380 | |
381 ev = c->read; | |
382 ev->ready = 1; | |
383 | |
384 queue = ev->accept ? &ngx_posted_accept_events | |
385 : &ngx_posted_events; | |
386 | |
387 ngx_post_event(ev, queue); | |
388 } | |
389 | |
390 if ((revents & POLLOUT) && c->write->active) { | |
391 found = 1; | |
392 | |
393 ev = c->write; | |
394 ev->ready = 1; | |
395 | |
396 ngx_post_event(ev, &ngx_posted_events); | |
397 } | |
398 | |
399 if (found) { | |
400 ready--; | |
401 continue; | |
402 } | |
403 } | |
404 | |
405 if (ready != 0) { | |
406 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events"); | |
407 } | |
408 | |
409 return NGX_OK; | |
410 } | |
411 | |
412 | |
413 static char * | |
414 ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf) | |
415 { | |
416 ngx_event_conf_t *ecf; | |
417 | |
418 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); | |
419 | |
420 if (ecf->use != ngx_poll_module.ctx_index) { | |
421 return NGX_CONF_OK; | |
422 } | |
423 | |
424 #if (NGX_LOAD_WSAPOLL) | |
425 | |
426 if (!ngx_have_wsapoll) { | |
427 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, | |
428 "poll is not available on this platform"); | |
429 return NGX_CONF_ERROR; | |
430 } | |
431 | |
432 #endif | |
433 | |
434 return NGX_CONF_OK; | |
435 } |