1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11
12
13 static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
14 static void ngx_poll_done(ngx_cycle_t *cycle);
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);
19 static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
20 ngx_uint_t flags);
21 static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf);
22
23
24 static struct pollfd *event_list;
25 static ngx_uint_t nevents;
26
27
28 static ngx_str_t poll_name = ngx_string("poll");
29
30 static 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, /* trigger a notify */
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 = {
51 NGX_MODULE_V1,
52 &ngx_poll_module_ctx, /* module context */
53 NULL, /* module directives */
54 NGX_EVENT_MODULE, /* module type */
55 NULL, /* init master */
56 NULL, /* init module */
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
63 };
64
65
66
67 static ngx_int_t
ngx_poll_init(ngx_cycle_t * cycle,ngx_msec_t timer)68 ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
69 {
70 struct pollfd *list;
71
72 if (event_list == NULL) {
73 nevents = 0;
74 }
75
76 if (ngx_process >= NGX_PROCESS_WORKER
77 || cycle->old_cycle == NULL
78 || cycle->old_cycle->connection_n < cycle->connection_n)
79 {
80 list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n,
81 cycle->log);
82 if (list == NULL) {
83 return NGX_ERROR;
84 }
85
86 if (event_list) {
87 ngx_memcpy(list, event_list, sizeof(struct pollfd) * 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
98 ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
99
100 return NGX_OK;
101 }
102
103
104 static void
ngx_poll_done(ngx_cycle_t * cycle)105 ngx_poll_done(ngx_cycle_t *cycle)
106 {
107 ngx_free(event_list);
108
109 event_list = NULL;
110 }
111
112
113 static ngx_int_t
ngx_poll_add_event(ngx_event_t * ev,ngx_int_t event,ngx_uint_t flags)114 ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
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,
125 "poll event fd:%d ev:%i is already set", c->fd, event);
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,
143 "poll add event: fd:%d ev:%i", c->fd, event);
144
145 if (e == NULL || e->index == NGX_INVALID_INDEX) {
146 event_list[nevents].fd = c->fd;
147 event_list[nevents].events = (short) event;
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,
155 "poll add index: %i", e->index);
156
157 event_list[e->index].events |= (short) event;
158 ev->index = e->index;
159 }
160
161 return NGX_OK;
162 }
163
164
165 static ngx_int_t
ngx_poll_del_event(ngx_event_t * ev,ngx_int_t event,ngx_uint_t flags)166 ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
167 {
168 ngx_event_t *e;
169 ngx_connection_t *c;
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,
177 "poll event fd:%d ev:%i is already deleted",
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,
196 "poll del event: fd:%d ev:%i", c->fd, event);
197
198 if (e == NULL || e->index == NGX_INVALID_INDEX) {
199 nevents--;
200
201 if (ev->index < nevents) {
202
203 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
204 "index: copy event %ui to %i", nevents, ev->index);
205
206 event_list[ev->index] = event_list[nevents];
207
208 c = ngx_cycle->files[event_list[nevents].fd];
209
210 if (c->fd == -1) {
211 ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
212 "unexpected last event");
213
214 } else {
215 if (c->read->index == nevents) {
216 c->read->index = ev->index;
217 }
218
219 if (c->write->index == nevents) {
220 c->write->index = ev->index;
221 }
222 }
223 }
224
225 } else {
226 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
227 "poll del index: %i", e->index);
228
229 event_list[e->index].events &= (short) ~event;
230 }
231
232 ev->index = NGX_INVALID_INDEX;
233
234 return NGX_OK;
235 }
236
237
238 static ngx_int_t
ngx_poll_process_events(ngx_cycle_t * cycle,ngx_msec_t timer,ngx_uint_t flags)239 ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
240 {
241 int ready, revents;
242 ngx_err_t err;
243 ngx_uint_t i, found, level;
244 ngx_event_t *ev;
245 ngx_queue_t *queue;
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,
254 "poll: %ui: fd:%d ev:%04Xd",
255 i, event_list[i].fd, event_list[i].events);
256 }
257 }
258 #endif
259
260 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer);
261
262 ready = poll(event_list, (u_int) nevents, (int) timer);
263
264 err = (ready == -1) ? ngx_errno : 0;
265
266 if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
267 ngx_time_update();
268 }
269
270 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
271 "poll ready %d of %ui", ready, nevents);
272
273 if (err) {
274 if (err == NGX_EINTR) {
275
276 if (ngx_event_timer_alarm) {
277 ngx_event_timer_alarm = 0;
278 return NGX_OK;
279 }
280
281 level = NGX_LOG_INFO;
282
283 } else {
284 level = NGX_LOG_ALERT;
285 }
286
287 ngx_log_error(level, cycle->log, err, "poll() failed");
288 return NGX_ERROR;
289 }
290
291 if (ready == 0) {
292 if (timer != NGX_TIMER_INFINITE) {
293 return NGX_OK;
294 }
295
296 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
297 "poll() returned no events without timeout");
298 return NGX_ERROR;
299 }
300
301 for (i = 0; i < nevents && ready; i++) {
302
303 revents = event_list[i].revents;
304
305 #if 1
306 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
307 "poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
308 i, event_list[i].fd, event_list[i].events, revents);
309 #else
310 if (revents) {
311 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
312 "poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
313 i, event_list[i].fd, event_list[i].events, revents);
314 }
315 #endif
316
317 if (revents & POLLNVAL) {
318 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
319 "poll() error fd:%d ev:%04Xd rev:%04Xd",
320 event_list[i].fd, event_list[i].events, revents);
321 }
322
323 if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
324 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
325 "strange poll() events fd:%d ev:%04Xd rev:%04Xd",
326 event_list[i].fd, event_list[i].events, revents);
327 }
328
329 if (event_list[i].fd == -1) {
330 /*
331 * the disabled event, a workaround for our possible bug,
332 * see the comment below
333 */
334 continue;
335 }
336
337 c = ngx_cycle->files[event_list[i].fd];
338
339 if (c->fd == -1) {
340 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");
341
342 /*
343 * it is certainly our fault and it should be investigated,
344 * in the meantime we disable this event to avoid a CPU spinning
345 */
346
347 if (i == nevents - 1) {
348 nevents--;
349 } else {
350 event_list[i].fd = -1;
351 }
352
353 continue;
354 }
355
356 if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
357
358 /*
359 * if the error events were returned, add POLLIN and POLLOUT
360 * to handle the events at least in one active handler
361 */
362
363 revents |= POLLIN|POLLOUT;
364 }
365
366 found = 0;
367
368 if ((revents & POLLIN) && c->read->active) {
369 found = 1;
370
371 ev = c->read;
372 ev->ready = 1;
373
374 queue = ev->accept ? &ngx_posted_accept_events
375 : &ngx_posted_events;
376
377 ngx_post_event(ev, queue);
378 }
379
380 if ((revents & POLLOUT) && c->write->active) {
381 found = 1;
382
383 ev = c->write;
384 ev->ready = 1;
385
386 ngx_post_event(ev, &ngx_posted_events);
387 }
388
389 if (found) {
390 ready--;
391 continue;
392 }
393 }
394
395 if (ready != 0) {
396 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events");
397 }
398
399 return NGX_OK;
400 }
401
402
403 static char *
ngx_poll_init_conf(ngx_cycle_t * cycle,void * conf)404 ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf)
405 {
406 ngx_event_conf_t *ecf;
407
408 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
409
410 if (ecf->use != ngx_poll_module.ctx_index) {
411 return NGX_CONF_OK;
412 }
413
414 return NGX_CONF_OK;
415 }
416