3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 #if (NGX_TEST_BUILD_DEVPOLL)
14 /* Solaris declarations */
16 #define POLLREMOVE 0x0800
17 #define DP_POLL 0xD001
18 #define DP_ISPOLLED 0xD002
21 struct pollfd *dp_fds;
35 static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
36 static void ngx_devpoll_done(ngx_cycle_t *cycle);
37 static ngx_int_t ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event,
39 static ngx_int_t ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event,
41 static ngx_int_t ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event,
43 static ngx_int_t ngx_devpoll_process_events(ngx_cycle_t *cycle,
44 ngx_msec_t timer, ngx_uint_t flags);
46 static void *ngx_devpoll_create_conf(ngx_cycle_t *cycle);
47 static char *ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf);
50 static struct pollfd *change_list, *event_list;
51 static ngx_uint_t nchanges, max_changes, nevents;
53 static ngx_event_t **change_index;
56 static ngx_str_t devpoll_name = ngx_string("/dev/poll");
58 static ngx_command_t ngx_devpoll_commands[] = {
60 { ngx_string("devpoll_changes"),
61 NGX_EVENT_CONF|NGX_CONF_TAKE1,
62 ngx_conf_set_num_slot,
64 offsetof(ngx_devpoll_conf_t, changes),
67 { ngx_string("devpoll_events"),
68 NGX_EVENT_CONF|NGX_CONF_TAKE1,
69 ngx_conf_set_num_slot,
71 offsetof(ngx_devpoll_conf_t, events),
78 ngx_event_module_t ngx_devpoll_module_ctx = {
80 ngx_devpoll_create_conf, /* create configuration */
81 ngx_devpoll_init_conf, /* init configuration */
84 ngx_devpoll_add_event, /* add an event */
85 ngx_devpoll_del_event, /* delete an event */
86 ngx_devpoll_add_event, /* enable an event */
87 ngx_devpoll_del_event, /* disable an event */
88 NULL, /* add an connection */
89 NULL, /* delete an connection */
90 NULL, /* process the changes */
91 ngx_devpoll_process_events, /* process the events */
92 ngx_devpoll_init, /* init the events */
93 ngx_devpoll_done, /* done the events */
98 ngx_module_t ngx_devpoll_module = {
100 &ngx_devpoll_module_ctx, /* module context */
101 ngx_devpoll_commands, /* module directives */
102 NGX_EVENT_MODULE, /* module type */
103 NULL, /* init master */
104 NULL, /* init module */
105 NULL, /* init process */
106 NULL, /* init thread */
107 NULL, /* exit thread */
108 NULL, /* exit process */
109 NULL, /* exit master */
110 NGX_MODULE_V1_PADDING
115 ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
118 ngx_devpoll_conf_t *dpcf;
120 dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module);
123 dp = open("/dev/poll", O_RDWR);
126 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
127 "open(/dev/poll) failed");
132 if (max_changes < dpcf->changes) {
134 n = nchanges * sizeof(struct pollfd);
135 if (write(dp, change_list, n) != (ssize_t) n) {
136 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
137 "write(/dev/poll) failed");
145 ngx_free(change_list);
148 change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes,
150 if (change_list == NULL) {
155 ngx_free(change_index);
158 change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes,
160 if (change_index == NULL) {
165 max_changes = dpcf->changes;
167 if (nevents < dpcf->events) {
169 ngx_free(event_list);
172 event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events,
174 if (event_list == NULL) {
179 nevents = dpcf->events;
183 ngx_event_actions = ngx_devpoll_module_ctx.actions;
185 ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT;
192 ngx_devpoll_done(ngx_cycle_t *cycle)
194 if (close(dp) == -1) {
195 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
196 "close(/dev/poll) failed");
201 ngx_free(change_list);
202 ngx_free(event_list);
203 ngx_free(change_index);
215 ngx_devpoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
221 #if (NGX_READ_EVENT != POLLIN)
222 event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
227 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
228 "devpoll add event: fd:%d ev:%04Xi", c->fd, event);
233 return ngx_devpoll_set_event(ev, event, 0);
238 ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
245 #if (NGX_READ_EVENT != POLLIN)
246 event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
249 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
250 "devpoll del event: fd:%d ev:%04Xi", c->fd, event);
252 if (ngx_devpoll_set_event(ev, POLLREMOVE, flags) == NGX_ERROR) {
258 if (flags & NGX_CLOSE_EVENT) {
259 e = (event == POLLIN) ? c->write : c->read;
268 /* restore the pair event if it exists */
270 if (event == POLLIN) {
279 if (e && e->active) {
280 return ngx_devpoll_set_event(e, event, 0);
288 ngx_devpoll_set_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
295 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
296 "devpoll fd:%d ev:%04Xi fl:%04Xi", c->fd, event, flags);
298 if (nchanges >= max_changes) {
299 ngx_log_error(NGX_LOG_WARN, ev->log, 0,
300 "/dev/pool change list is filled up");
302 n = nchanges * sizeof(struct pollfd);
303 if (write(dp, change_list, n) != (ssize_t) n) {
304 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
305 "write(/dev/poll) failed");
312 change_list[nchanges].fd = c->fd;
313 change_list[nchanges].events = (short) event;
314 change_list[nchanges].revents = 0;
316 change_index[nchanges] = ev;
317 ev->index = nchanges;
321 if (flags & NGX_CLOSE_EVENT) {
322 n = nchanges * sizeof(struct pollfd);
323 if (write(dp, change_list, n) != (ssize_t) n) {
324 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
325 "write(/dev/poll) failed");
337 ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
340 int events, revents, rc;
346 ngx_event_t *rev, *wev, **queue;
351 /* NGX_TIMER_INFINITE == INFTIM */
353 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
354 "devpoll timer: %M", timer);
357 n = nchanges * sizeof(struct pollfd);
358 if (write(dp, change_list, n) != (ssize_t) n) {
359 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
360 "write(/dev/poll) failed");
367 dvp.dp_fds = event_list;
368 dvp.dp_nfds = (int) nevents;
369 dvp.dp_timeout = timer;
370 events = ioctl(dp, DP_POLL, &dvp);
378 if (flags & NGX_UPDATE_TIME) {
379 ngx_time_update(0, 0);
383 if (err == NGX_EINTR) {
385 if (ngx_event_timer_alarm) {
386 ngx_event_timer_alarm = 0;
390 level = NGX_LOG_INFO;
393 level = NGX_LOG_ALERT;
396 ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
401 if (timer != NGX_TIMER_INFINITE) {
405 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
406 "ioctl(DP_POLL) returned no events without timeout");
410 ngx_mutex_lock(ngx_posted_events_mutex);
412 for (i = 0; i < events; i++) {
414 fd = event_list[i].fd;
415 revents = event_list[i].revents;
417 c = ngx_cycle->files[fd];
419 if (c == NULL || c->fd == -1) {
425 rc = ioctl(dp, DP_ISPOLLED, &pfd);
430 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
431 "ioctl(DP_ISPOLLED) failed for socket %d, event",
436 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
437 "phantom event %04Xd for closed and removed socket %d",
442 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
443 "unexpected event %04Xd for closed and removed socket %d, ",
444 "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
445 revents, fd, rc, pfd.fd, pfd.revents);
448 pfd.events = POLLREMOVE;
451 if (write(dp, &pfd, sizeof(struct pollfd))
452 != (ssize_t) sizeof(struct pollfd))
454 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
455 "write(/dev/poll) for %d failed, fd");
458 if (close(fd) == -1) {
459 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
460 "close(%d) failed", fd);
469 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
470 "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
471 fd, event_list[i].events, revents);
473 if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
474 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
475 "ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
476 fd, event_list[i].events, revents);
479 if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
480 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
481 "strange ioctl(DP_POLL) events "
482 "fd:%d ev:%04Xd rev:%04Xd",
483 fd, event_list[i].events, revents);
486 if ((revents & (POLLERR|POLLHUP|POLLNVAL))
487 && (revents & (POLLIN|POLLOUT)) == 0)
490 * if the error events were returned without POLLIN or POLLOUT,
491 * then add these flags to handle the events at least in one
495 revents |= POLLIN|POLLOUT;
500 if ((revents & POLLIN) && rev->active) {
502 if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
503 rev->posted_ready = 1;
509 if (flags & NGX_POST_EVENTS) {
510 queue = (ngx_event_t **) (rev->accept ?
511 &ngx_posted_accept_events : &ngx_posted_events);
513 ngx_locked_post_event(rev, queue);
522 if ((revents & POLLOUT) && wev->active) {
524 if (flags & NGX_POST_THREAD_EVENTS) {
525 wev->posted_ready = 1;
531 if (flags & NGX_POST_EVENTS) {
532 ngx_locked_post_event(wev, &ngx_posted_events);
540 ngx_mutex_unlock(ngx_posted_events_mutex);
547 ngx_devpoll_create_conf(ngx_cycle_t *cycle)
549 ngx_devpoll_conf_t *dpcf;
551 dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t));
553 return NGX_CONF_ERROR;
556 dpcf->changes = NGX_CONF_UNSET;
557 dpcf->events = NGX_CONF_UNSET;
564 ngx_devpoll_init_conf(ngx_cycle_t *cycle, void *conf)
566 ngx_devpoll_conf_t *dpcf = conf;
568 ngx_conf_init_uint_value(dpcf->changes, 32);
569 ngx_conf_init_uint_value(dpcf->events, 32);