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