xref: /nginx/src/event/modules/ngx_win32_poll_module.c (revision 7583:efd71d49bde0)
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
ngx_poll_init(ngx_cycle_t * cycle,ngx_msec_t timer)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
ngx_poll_done(ngx_cycle_t * cycle)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
ngx_poll_add_event(ngx_event_t * ev,ngx_int_t event,ngx_uint_t flags)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
ngx_poll_del_event(ngx_event_t * ev,ngx_int_t event,ngx_uint_t flags)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
ngx_poll_process_events(ngx_cycle_t * cycle,ngx_msec_t timer,ngx_uint_t flags)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             ev->available = -1;
384 
385             queue = ev->accept ? &ngx_posted_accept_events
386                                : &ngx_posted_events;
387 
388             ngx_post_event(ev, queue);
389         }
390 
391         if ((revents & POLLOUT) && c->write->active) {
392             found = 1;
393 
394             ev = c->write;
395             ev->ready = 1;
396 
397             ngx_post_event(ev, &ngx_posted_events);
398         }
399 
400         if (found) {
401             ready--;
402             continue;
403         }
404     }
405 
406     if (ready != 0) {
407         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events");
408     }
409 
410     return NGX_OK;
411 }
412 
413 
414 static char *
ngx_poll_init_conf(ngx_cycle_t * cycle,void * conf)415 ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf)
416 {
417     ngx_event_conf_t  *ecf;
418 
419     ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
420 
421     if (ecf->use != ngx_poll_module.ctx_index) {
422         return NGX_CONF_OK;
423     }
424 
425 #if (NGX_LOAD_WSAPOLL)
426 
427     if (!ngx_have_wsapoll) {
428         ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
429                       "poll is not available on this platform");
430         return NGX_CONF_ERROR;
431     }
432 
433 #endif
434 
435     return NGX_CONF_OK;
436 }
437