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