3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 #if (TEST_BUILD_DEVPOLL)
14 /* Solaris declarations */
16 #define POLLREMOVE 0x0800
17 #define DP_POLL 0xD001
20 struct pollfd
*dp_fds
;
34 static int ngx_devpoll_init(ngx_cycle_t
*cycle
);
35 static void ngx_devpoll_done(ngx_cycle_t
*cycle
);
36 static int ngx_devpoll_add_event(ngx_event_t
*ev
, int event
, u_int flags
);
37 static int ngx_devpoll_del_event(ngx_event_t
*ev
, int event
, u_int flags
);
38 static int ngx_devpoll_set_event(ngx_event_t
*ev
, int event
, u_int flags
);
39 static int ngx_devpoll_process_events(ngx_cycle_t
*cycle
);
41 static void *ngx_devpoll_create_conf(ngx_cycle_t
*cycle
);
42 static char *ngx_devpoll_init_conf(ngx_cycle_t
*cycle
, void *conf
);
45 static struct pollfd
*change_list
, *event_list
;
46 static u_int nchanges
, max_changes
, nevents
;
48 static ngx_event_t
**change_index
;
51 static ngx_str_t devpoll_name
= ngx_string("/dev/poll");
53 static ngx_command_t ngx_devpoll_commands
[] = {
55 {ngx_string("devpoll_changes"),
56 NGX_EVENT_CONF
|NGX_CONF_TAKE1
,
57 ngx_conf_set_num_slot
,
59 offsetof(ngx_devpoll_conf_t
, changes
),
62 {ngx_string("devpoll_events"),
63 NGX_EVENT_CONF
|NGX_CONF_TAKE1
,
64 ngx_conf_set_num_slot
,
66 offsetof(ngx_devpoll_conf_t
, events
),
73 ngx_event_module_t ngx_devpoll_module_ctx
= {
75 ngx_devpoll_create_conf
, /* create configuration */
76 ngx_devpoll_init_conf
, /* init configuration */
79 ngx_devpoll_add_event
, /* add an event */
80 ngx_devpoll_del_event
, /* delete an event */
81 ngx_devpoll_add_event
, /* enable an event */
82 ngx_devpoll_del_event
, /* disable an event */
83 NULL
, /* add an connection */
84 NULL
, /* delete an connection */
85 NULL
, /* process the changes */
86 ngx_devpoll_process_events
, /* process the events */
87 ngx_devpoll_init
, /* init the events */
88 ngx_devpoll_done
, /* done the events */
93 ngx_module_t ngx_devpoll_module
= {
95 &ngx_devpoll_module_ctx
, /* module context */
96 ngx_devpoll_commands
, /* module directives */
97 NGX_EVENT_MODULE
, /* module type */
98 NULL
, /* init module */
99 NULL
/* init process */
103 static int ngx_devpoll_init(ngx_cycle_t
*cycle
)
106 ngx_devpoll_conf_t
*dpcf
;
108 dpcf
= ngx_event_get_conf(cycle
->conf_ctx
, ngx_devpoll_module
);
111 dp
= open("/dev/poll", O_RDWR
);
114 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
115 "open(/dev/poll) failed");
120 if (max_changes
< dpcf
->changes
) {
122 n
= nchanges
* sizeof(struct pollfd
);
123 if (write(dp
, change_list
, n
) != (ssize_t
) n
) {
124 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, ngx_errno
,
125 "write(/dev/poll) failed");
133 ngx_free(change_list
);
136 ngx_test_null(change_list
,
137 ngx_alloc(sizeof(struct pollfd
) * dpcf
->changes
,
142 ngx_free(change_index
);
145 ngx_test_null(change_index
,
146 ngx_alloc(sizeof(ngx_event_t
*) * dpcf
->changes
,
151 max_changes
= dpcf
->changes
;
153 if (nevents
< dpcf
->events
) {
155 ngx_free(event_list
);
158 ngx_test_null(event_list
,
159 ngx_alloc(sizeof(struct pollfd
) * dpcf
->events
,
164 nevents
= dpcf
->events
;
168 ngx_event_actions
= ngx_devpoll_module_ctx
.actions
;
170 ngx_event_flags
= NGX_USE_LEVEL_EVENT
;
176 static void ngx_devpoll_done(ngx_cycle_t
*cycle
)
178 if (close(dp
) == -1) {
179 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, ngx_errno
,
180 "close(/dev/poll) failed");
185 ngx_free(change_list
);
186 ngx_free(event_list
);
187 ngx_free(change_index
);
198 static int ngx_devpoll_add_event(ngx_event_t
*ev
, int event
, u_int flags
)
204 #if (NGX_READ_EVENT != POLLIN)
205 event
= (event
== NGX_READ_EVENT
) ? POLLIN
: POLLOUT
;
210 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, ev
->log
, 0,
211 "devpoll add event: fd:%d ev:%04X", c
->fd
, event
);
216 return ngx_devpoll_set_event(ev
, event
, 0);
220 static int ngx_devpoll_del_event(ngx_event_t
*ev
, int event
, u_int flags
)
227 #if (NGX_READ_EVENT != POLLIN)
228 event
= (event
== NGX_READ_EVENT
) ? POLLIN
: POLLOUT
;
231 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, ev
->log
, 0,
232 "devpoll del event: fd:%d ev:%04X", c
->fd
, event
);
234 if (ngx_devpoll_set_event(ev
, POLLREMOVE
, flags
) == NGX_ERROR
) {
240 if (flags
& NGX_CLOSE_EVENT
) {
244 /* restore the paired event if it exists */
246 if (event
== POLLIN
) {
255 if (e
&& e
->active
) {
256 return ngx_devpoll_set_event(e
, event
, 0);
263 static int ngx_devpoll_set_event(ngx_event_t
*ev
, int event
, u_int flags
)
270 ngx_log_debug3(NGX_LOG_DEBUG_EVENT
, ev
->log
, 0,
271 "devpoll fd:%d ev:%04X fl:%04X", c
->fd
, event
, flags
);
273 if (nchanges
>= max_changes
) {
274 ngx_log_error(NGX_LOG_WARN
, ev
->log
, 0,
275 "/dev/pool change list is filled up");
277 n
= nchanges
* sizeof(struct pollfd
);
278 if (write(dp
, change_list
, n
) != (ssize_t
) n
) {
279 ngx_log_error(NGX_LOG_ALERT
, ev
->log
, ngx_errno
,
280 "write(/dev/poll) failed");
287 change_list
[nchanges
].fd
= c
->fd
;
288 change_list
[nchanges
].events
= event
;
289 change_list
[nchanges
].revents
= 0;
291 change_index
[nchanges
] = ev
;
292 ev
->index
= nchanges
;
296 if (flags
& NGX_CLOSE_EVENT
) {
297 n
= nchanges
* sizeof(struct pollfd
);
298 if (write(dp
, change_list
, n
) != (ssize_t
) n
) {
299 ngx_log_error(NGX_LOG_ALERT
, ev
->log
, ngx_errno
,
300 "write(/dev/poll) failed");
311 int ngx_devpoll_process_events(ngx_cycle_t
*cycle
)
315 ngx_uint_t j
, lock
, accept_lock
, expire
;
319 ngx_cycle_t
**old_cycle
;
320 ngx_event_t
*rev
, *wev
;
322 ngx_epoch_msec_t delta
;
327 timer
= ngx_event_find_timer();
333 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
334 "devpoll expired timer");
336 ngx_event_expire_timers((ngx_msec_t
)
337 (ngx_elapsed_msec
- ngx_old_elapsed_msec
));
340 /* NGX_TIMER_INFINITE == INFTIM */
342 if (timer
== NGX_TIMER_INFINITE
) {
349 ngx_old_elapsed_msec
= ngx_elapsed_msec
;
352 if (ngx_accept_mutex
) {
353 if (ngx_accept_disabled
> 0) {
354 ngx_accept_disabled
--;
357 if (ngx_trylock_accept_mutex(cycle
) == NGX_ERROR
) {
361 if (ngx_accept_mutex_held
) {
364 } else if (timer
== NGX_TIMER_INFINITE
365 || timer
> ngx_accept_mutex_delay
)
367 timer
= ngx_accept_mutex_delay
;
373 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
374 "devpoll timer: %d", timer
);
377 n
= nchanges
* sizeof(struct pollfd
);
378 if (write(dp
, change_list
, n
) != (ssize_t
) n
) {
379 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, ngx_errno
,
380 "write(/dev/poll) failed");
381 ngx_accept_mutex_unlock();
386 dvp
.dp_fds
= event_list
;
387 dvp
.dp_nfds
= nevents
;
388 dvp
.dp_timeout
= timer
;
389 events
= ioctl(dp
, DP_POLL
, &dvp
);
399 ngx_gettimeofday(&tv
);
400 ngx_time_update(tv
.tv_sec
);
402 delta
= ngx_elapsed_msec
;
403 ngx_elapsed_msec
= (ngx_epoch_msec_t
) tv
.tv_sec
* 1000
404 + tv
.tv_usec
/ 1000 - ngx_start_msec
;
407 ngx_log_error((err
== NGX_EINTR
) ? NGX_LOG_INFO
: NGX_LOG_ALERT
,
408 cycle
->log
, err
, "ioctl(DP_POLL) failed");
409 ngx_accept_mutex_unlock();
413 if (timer
!= NGX_TIMER_INFINITE
) {
414 delta
= ngx_elapsed_msec
- delta
;
416 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
417 "devpoll timer: %d, delta: %d", timer
, (int) delta
);
420 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
421 "ioctl(DP_POLL) returned no events without timeout");
422 ngx_accept_mutex_unlock();
427 if (ngx_mutex_lock(ngx_posted_events_mutex
) == NGX_ERROR
) {
428 ngx_accept_mutex_unlock();
434 for (i
= 0; i
< events
; i
++) {
435 c
= &ngx_cycle
->connections
[event_list
[i
].fd
];
438 old_cycle
= ngx_old_cycles
.elts
;
439 for (j
= 0; j
< ngx_old_cycles
.nelts
; j
++) {
440 if (old_cycle
[j
] == NULL
) {
443 c
= &old_cycle
[j
]->connections
[event_list
[i
].fd
];
451 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, 0, "unknown cycle");
455 ngx_log_debug3(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
456 "devpoll: fd:%d, ev:%04X, rev:%04X",
458 event_list
[i
].events
, event_list
[i
].revents
);
460 if (event_list
[i
].revents
& (POLLERR
|POLLHUP
|POLLNVAL
)) {
461 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
462 "ioctl(DP_POLL) error fd:%d ev:%04X rev:%04X",
464 event_list
[i
].events
, event_list
[i
].revents
);
467 if (event_list
[i
].revents
& ~(POLLIN
|POLLOUT
|POLLERR
|POLLHUP
|POLLNVAL
))
469 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
470 "strange ioctl(DP_POLL) events "
471 "fd:%d ev:%04X rev:%04X",
473 event_list
[i
].events
, event_list
[i
].revents
);
478 if ((event_list
[i
].events
& (POLLOUT
|POLLERR
|POLLHUP
)) && wev
->active
) {
481 if (!ngx_threaded
&& !ngx_accept_mutex_held
) {
482 wev
->event_handler(wev
);
490 * POLLIN must be handled after POLLOUT because we use
491 * the optimization to avoid the unnecessary mutex locking/unlocking
492 * if the accept event is the last one.
497 if ((event_list
[i
].events
& (POLLIN
|POLLERR
|POLLHUP
)) && rev
->active
) {
500 if (!ngx_threaded
&& !ngx_accept_mutex_held
) {
501 rev
->event_handler(rev
);
503 } else if (!rev
->accept
) {
506 } else if (ngx_accept_disabled
<= 0) {
507 ngx_mutex_unlock(ngx_posted_events_mutex
);
509 c
->read
->event_handler(rev
);
511 if (ngx_accept_disabled
> 0) {
512 ngx_accept_mutex_unlock();
516 if (i
+ 1 == events
) {
521 if (ngx_mutex_lock(ngx_posted_events_mutex
) == NGX_ERROR
) {
523 ngx_accept_mutex_unlock();
532 ngx_accept_mutex_unlock();
536 ngx_mutex_unlock(ngx_posted_events_mutex
);
539 if (expire
&& delta
) {
540 ngx_event_expire_timers((ngx_msec_t
) delta
);
544 ngx_event_process_posted(cycle
);
551 static void *ngx_devpoll_create_conf(ngx_cycle_t
*cycle
)
553 ngx_devpoll_conf_t
*dpcf
;
555 ngx_test_null(dpcf
, ngx_palloc(cycle
->pool
, sizeof(ngx_devpoll_conf_t
)),
558 dpcf
->changes
= NGX_CONF_UNSET
;
559 dpcf
->events
= NGX_CONF_UNSET
;
565 static char *ngx_devpoll_init_conf(ngx_cycle_t
*cycle
, void *conf
)
567 ngx_devpoll_conf_t
*dpcf
= conf
;
569 ngx_conf_init_unsigned_value(dpcf
->changes
, 512);
570 ngx_conf_init_unsigned_value(dpcf
->events
, 512);