Annotation of embedaddon/nginx/src/event/modules/ngx_devpoll_module.c, revision 1.1.1.1
1.1 misho 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: #if (NGX_TEST_BUILD_DEVPOLL)
14:
15: /* Solaris declarations */
16:
17: #define POLLREMOVE 0x0800
18: #define DP_POLL 0xD001
19: #define DP_ISPOLLED 0xD002
20:
21: struct dvpoll {
22: struct pollfd *dp_fds;
23: int dp_nfds;
24: int dp_timeout;
25: };
26:
27: #endif
28:
29:
30: typedef struct {
31: ngx_uint_t changes;
32: ngx_uint_t events;
33: } ngx_devpoll_conf_t;
34:
35:
36: static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
37: static void ngx_devpoll_done(ngx_cycle_t *cycle);
38: static ngx_int_t ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event,
39: ngx_uint_t flags);
40: static ngx_int_t ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event,
41: ngx_uint_t flags);
42: static ngx_int_t ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event,
43: ngx_uint_t flags);
44: static ngx_int_t ngx_devpoll_process_events(ngx_cycle_t *cycle,
45: ngx_msec_t timer, ngx_uint_t flags);
46:
47: static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
48: static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);
49:
50: static int dp = -1;
51: static struct pollfd *change_list, *event_list;
52: static ngx_uint_t nchanges, max_changes, nevents;
53:
54: static ngx_event_t **change_index;
55:
56:
57: static ngx_str_t devpoll_name = ngx_string("/dev/poll");
58:
59: static ngx_command_t ngx_devpoll_commands[] = {
60:
61: { ngx_string("devpoll_changes"),
62: NGX_EVENT_CONF|NGX_CONF_TAKE1,
63: ngx_conf_set_num_slot,
64: 0,
65: offsetof(ngx_devpoll_conf_t, changes),
66: NULL },
67:
68: { ngx_string("devpoll_events"),
69: NGX_EVENT_CONF|NGX_CONF_TAKE1,
70: ngx_conf_set_num_slot,
71: 0,
72: offsetof(ngx_devpoll_conf_t, events),
73: NULL },
74:
75: ngx_null_command
76: };
77:
78:
79: ngx_event_module_t ngx_devpoll_module_ctx = {
80: &devpoll_name,
81: ngx_devpoll_create_conf, /* create configuration */
82: ngx_devpoll_init_conf, /* init configuration */
83:
84: {
85: ngx_devpoll_add_event, /* add an event */
86: ngx_devpoll_del_event, /* delete an event */
87: ngx_devpoll_add_event, /* enable an event */
88: ngx_devpoll_del_event, /* disable an event */
89: NULL, /* add an connection */
90: NULL, /* delete an connection */
91: NULL, /* process the changes */
92: ngx_devpoll_process_events, /* process the events */
93: ngx_devpoll_init, /* init the events */
94: ngx_devpoll_done, /* done the events */
95: }
96:
97: };
98:
99: ngx_module_t ngx_devpoll_module = {
100: NGX_MODULE_V1,
101: &ngx_devpoll_module_ctx, /* module context */
102: ngx_devpoll_commands, /* module directives */
103: NGX_EVENT_MODULE, /* module type */
104: NULL, /* init master */
105: NULL, /* init module */
106: NULL, /* init process */
107: NULL, /* init thread */
108: NULL, /* exit thread */
109: NULL, /* exit process */
110: NULL, /* exit master */
111: NGX_MODULE_V1_PADDING
112: };
113:
114:
115: static ngx_int_t
116: ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
117: {
118: size_t n;
119: ngx_devpoll_conf_t *dpcf;
120:
121: dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module);
122:
123: if (dp == -1) {
124: dp = open("/dev/poll", O_RDWR);
125:
126: if (dp == -1) {
127: ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
128: "open(/dev/poll) failed");
129: return NGX_ERROR;
130: }
131: }
132:
133: if (max_changes < dpcf->changes) {
134: if (nchanges) {
135: n = nchanges * sizeof(struct pollfd);
136: if (write(dp, change_list, n) != (ssize_t) n) {
137: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
138: "write(/dev/poll) failed");
139: return NGX_ERROR;
140: }
141:
142: nchanges = 0;
143: }
144:
145: if (change_list) {
146: ngx_free(change_list);
147: }
148:
149: change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes,
150: cycle->log);
151: if (change_list == NULL) {
152: return NGX_ERROR;
153: }
154:
155: if (change_index) {
156: ngx_free(change_index);
157: }
158:
159: change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes,
160: cycle->log);
161: if (change_index == NULL) {
162: return NGX_ERROR;
163: }
164: }
165:
166: max_changes = dpcf->changes;
167:
168: if (nevents < dpcf->events) {
169: if (event_list) {
170: ngx_free(event_list);
171: }
172:
173: event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events,
174: cycle->log);
175: if (event_list == NULL) {
176: return NGX_ERROR;
177: }
178: }
179:
180: nevents = dpcf->events;
181:
182: ngx_io = ngx_os_io;
183:
184: ngx_event_actions = ngx_devpoll_module_ctx.actions;
185:
186: ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
187:
188: return NGX_OK;
189: }
190:
191:
192: static void
193: ngx_devpoll_done(ngx_cycle_t *cycle)
194: {
195: if (close(dp) == -1) {
196: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
197: "close(/dev/poll) failed");
198: }
199:
200: dp = -1;
201:
202: ngx_free(change_list);
203: ngx_free(event_list);
204: ngx_free(change_index);
205:
206: change_list = NULL;
207: event_list = NULL;
208: change_index = NULL;
209: max_changes = 0;
210: nchanges = 0;
211: nevents = 0;
212: }
213:
214:
215: static ngx_int_t
216: ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
217: {
218: #if (NGX_DEBUG)
219: ngx_connection_t *c;
220: #endif
221:
222: #if (NGX_READ_EVENT != POLLIN)
223: event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
224: #endif
225:
226: #if (NGX_DEBUG)
227: c = ev->data;
228: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
229: "devpoll add event: fd:%d ev:%04Xi", c->fd, event);
230: #endif
231:
232: ev->active = 1;
233:
234: return ngx_devpoll_set_event(ev, event, 0);
235: }
236:
237:
238: static ngx_int_t
239: ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
240: {
241: ngx_event_t *e;
242: ngx_connection_t *c;
243:
244: c = ev->data;
245:
246: #if (NGX_READ_EVENT != POLLIN)
247: event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
248: #endif
249:
250: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
251: "devpoll del event: fd:%d ev:%04Xi", c->fd, event);
252:
253: if (ngx_devpoll_set_event(ev, POLLREMOVE, flags) == NGX_ERROR) {
254: return NGX_ERROR;
255: }
256:
257: ev->active = 0;
258:
259: if (flags & NGX_CLOSE_EVENT) {
260: e = (event == POLLIN) ? c->write : c->read;
261:
262: if (e) {
263: e->active = 0;
264: }
265:
266: return NGX_OK;
267: }
268:
269: /* restore the pair event if it exists */
270:
271: if (event == POLLIN) {
272: e = c->write;
273: event = POLLOUT;
274:
275: } else {
276: e = c->read;
277: event = POLLIN;
278: }
279:
280: if (e && e->active) {
281: return ngx_devpoll_set_event(e, event, 0);
282: }
283:
284: return NGX_OK;
285: }
286:
287:
288: static ngx_int_t
289: ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
290: {
291: size_t n;
292: ngx_connection_t *c;
293:
294: c = ev->data;
295:
296: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
297: "devpoll fd:%d ev:%04Xi fl:%04Xi", c->fd, event, flags);
298:
299: if (nchanges >= max_changes) {
300: ngx_log_error(NGX_LOG_WARN, ev->log, 0,
301: "/dev/pool change list is filled up");
302:
303: n = nchanges * sizeof(struct pollfd);
304: if (write(dp, change_list, n) != (ssize_t) n) {
305: ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
306: "write(/dev/poll) failed");
307: return NGX_ERROR;
308: }
309:
310: nchanges = 0;
311: }
312:
313: change_list[nchanges].fd = c->fd;
314: change_list[nchanges].events = (short) event;
315: change_list[nchanges].revents = 0;
316:
317: change_index[nchanges] = ev;
318: ev->index = nchanges;
319:
320: nchanges++;
321:
322: if (flags & NGX_CLOSE_EVENT) {
323: n = nchanges * sizeof(struct pollfd);
324: if (write(dp, change_list, n) != (ssize_t) n) {
325: ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
326: "write(/dev/poll) failed");
327: return NGX_ERROR;
328: }
329:
330: nchanges = 0;
331: }
332:
333: return NGX_OK;
334: }
335:
336:
337: ngx_int_t
338: ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
339: ngx_uint_t flags)
340: {
341: int events, revents, rc;
342: size_t n;
343: ngx_fd_t fd;
344: ngx_err_t err;
345: ngx_int_t i;
346: ngx_uint_t level, instance;
347: ngx_event_t *rev, *wev, **queue;
348: ngx_connection_t *c;
349: struct pollfd pfd;
350: struct dvpoll dvp;
351:
352: /* NGX_TIMER_INFINITE == INFTIM */
353:
354: ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
355: "devpoll timer: %M", timer);
356:
357: if (nchanges) {
358: n = nchanges * sizeof(struct pollfd);
359: if (write(dp, change_list, n) != (ssize_t) n) {
360: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
361: "write(/dev/poll) failed");
362: return NGX_ERROR;
363: }
364:
365: nchanges = 0;
366: }
367:
368: dvp.dp_fds = event_list;
369: dvp.dp_nfds = (int) nevents;
370: dvp.dp_timeout = timer;
371: events = ioctl(dp, DP_POLL, &dvp);
372:
373: err = (events == -1) ? ngx_errno : 0;
374:
375: if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
376: ngx_time_update();
377: }
378:
379: if (err) {
380: if (err == NGX_EINTR) {
381:
382: if (ngx_event_timer_alarm) {
383: ngx_event_timer_alarm = 0;
384: return NGX_OK;
385: }
386:
387: level = NGX_LOG_INFO;
388:
389: } else {
390: level = NGX_LOG_ALERT;
391: }
392:
393: ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
394: return NGX_ERROR;
395: }
396:
397: if (events == 0) {
398: if (timer != NGX_TIMER_INFINITE) {
399: return NGX_OK;
400: }
401:
402: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
403: "ioctl(DP_POLL) returned no events without timeout");
404: return NGX_ERROR;
405: }
406:
407: ngx_mutex_lock(ngx_posted_events_mutex);
408:
409: for (i = 0; i < events; i++) {
410:
411: fd = event_list[i].fd;
412: revents = event_list[i].revents;
413:
414: c = ngx_cycle->files[fd];
415:
416: if (c == NULL || c->fd == -1) {
417:
418: pfd.fd = fd;
419: pfd.events = 0;
420: pfd.revents = 0;
421:
422: rc = ioctl(dp, DP_ISPOLLED, &pfd);
423:
424: switch (rc) {
425:
426: case -1:
427: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
428: "ioctl(DP_ISPOLLED) failed for socket %d, event",
429: fd, revents);
430: break;
431:
432: case 0:
433: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
434: "phantom event %04Xd for closed and removed socket %d",
435: revents, fd);
436: break;
437:
438: default:
439: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
440: "unexpected event %04Xd for closed and removed socket %d, ",
441: "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
442: revents, fd, rc, pfd.fd, pfd.revents);
443:
444: pfd.fd = fd;
445: pfd.events = POLLREMOVE;
446: pfd.revents = 0;
447:
448: if (write(dp, &pfd, sizeof(struct pollfd))
449: != (ssize_t) sizeof(struct pollfd))
450: {
451: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
452: "write(/dev/poll) for %d failed, fd");
453: }
454:
455: if (close(fd) == -1) {
456: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
457: "close(%d) failed", fd);
458: }
459:
460: break;
461: }
462:
463: continue;
464: }
465:
466: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
467: "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
468: fd, event_list[i].events, revents);
469:
470: if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
471: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
472: "ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
473: fd, event_list[i].events, revents);
474: }
475:
476: if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
477: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
478: "strange ioctl(DP_POLL) events "
479: "fd:%d ev:%04Xd rev:%04Xd",
480: fd, event_list[i].events, revents);
481: }
482:
483: if ((revents & (POLLERR|POLLHUP|POLLNVAL))
484: && (revents & (POLLIN|POLLOUT)) == 0)
485: {
486: /*
487: * if the error events were returned without POLLIN or POLLOUT,
488: * then add these flags to handle the events at least in one
489: * active handler
490: */
491:
492: revents |= POLLIN|POLLOUT;
493: }
494:
495: rev = c->read;
496:
497: if ((revents & POLLIN) && rev->active) {
498:
499: if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
500: rev->posted_ready = 1;
501:
502: } else {
503: rev->ready = 1;
504: }
505:
506: if (flags & NGX_POST_EVENTS) {
507: queue = (ngx_event_t **) (rev->accept ?
508: &ngx_posted_accept_events : &ngx_posted_events);
509:
510: ngx_locked_post_event(rev, queue);
511:
512: } else {
513: instance = rev->instance;
514:
515: rev->handler(rev);
516:
517: if (c->fd == -1 || rev->instance != instance) {
518: continue;
519: }
520: }
521: }
522:
523: wev = c->write;
524:
525: if ((revents & POLLOUT) && wev->active) {
526:
527: if (flags & NGX_POST_THREAD_EVENTS) {
528: wev->posted_ready = 1;
529:
530: } else {
531: wev->ready = 1;
532: }
533:
534: if (flags & NGX_POST_EVENTS) {
535: ngx_locked_post_event(wev, &ngx_posted_events);
536:
537: } else {
538: wev->handler(wev);
539: }
540: }
541: }
542:
543: ngx_mutex_unlock(ngx_posted_events_mutex);
544:
545: return NGX_OK;
546: }
547:
548:
549: static void *
550: ngx_devpoll_create_conf(ngx_cycle_t *cycle)
551: {
552: ngx_devpoll_conf_t *dpcf;
553:
554: dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
555: if (dpcf == NULL) {
556: return NULL;
557: }
558:
559: dpcf->changes = NGX_CONF_UNSET;
560: dpcf->events = NGX_CONF_UNSET;
561:
562: return dpcf;
563: }
564:
565:
566: static char *
567: ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf)
568: {
569: ngx_devpoll_conf_t *dpcf = conf;
570:
571: ngx_conf_init_uint_value(dpcf->changes, 32);
572: ngx_conf_init_uint_value(dpcf->events, 32);
573:
574: return NGX_CONF_OK;
575: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>