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 }