3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
10 #include <ngx_event.h>
13 #if (NGX_TEST_BUILD_EVENTPORT)
15 #define ushort_t u_short
18 #ifndef CLOCK_REALTIME
19 #define CLOCK_REALTIME 0
20 typedef int clockid_t
;
21 typedef void * timer_t
;
24 /* Solaris declarations */
26 #define PORT_SOURCE_AIO 1
27 #define PORT_SOURCE_TIMER 2
28 #define PORT_SOURCE_USER 3
29 #define PORT_SOURCE_FD 4
30 #define PORT_SOURCE_ALERT 5
31 #define PORT_SOURCE_MQ 6
40 int portev_events
; /* event data is source specific */
41 ushort_t portev_source
; /* event source */
42 ushort_t portev_pad
; /* port internal use */
43 uintptr_t portev_object
; /* source specific object */
44 void *portev_user
; /* user cookie */
47 typedef struct port_notify
{
48 int portnfy_port
; /* bind request(s) to port */
49 void *portnfy_user
; /* user defined */
52 #if (__FreeBSD_version < 700005)
54 typedef struct itimerspec
{ /* definition per POSIX.4 */
55 struct timespec it_interval
;/* timer period */
56 struct timespec it_value
; /* timer expiration */
61 int port_create(void);
69 int port_associate(int port
, int source
, uintptr_t object
, int events
,
72 int port_associate(int port
, int source
, uintptr_t object
, int events
,
79 int port_dissociate(int port
, int source
, uintptr_t object
);
81 int port_dissociate(int port
, int source
, uintptr_t object
)
87 int port_getn(int port
, port_event_t list
[], uint_t max
, uint_t
*nget
,
88 struct timespec
*timeout
);
90 int port_getn(int port
, port_event_t list
[], uint_t max
, uint_t
*nget
,
91 struct timespec
*timeout
)
97 int timer_create(clockid_t clock_id
, struct sigevent
*evp
, timer_t
*timerid
);
99 int timer_create(clockid_t clock_id
, struct sigevent
*evp
, timer_t
*timerid
)
105 int timer_settime(timer_t timerid
, int flags
, const struct itimerspec
*value
,
106 struct itimerspec
*ovalue
);
108 int timer_settime(timer_t timerid
, int flags
, const struct itimerspec
*value
,
109 struct itimerspec
*ovalue
)
115 int timer_delete(timer_t timerid
);
117 int timer_delete(timer_t timerid
)
127 } ngx_eventport_conf_t
;
130 static ngx_int_t
ngx_eventport_init(ngx_cycle_t
*cycle
, ngx_msec_t timer
);
131 static void ngx_eventport_done(ngx_cycle_t
*cycle
);
132 static ngx_int_t
ngx_eventport_add_event(ngx_event_t
*ev
, ngx_int_t event
,
134 static ngx_int_t
ngx_eventport_del_event(ngx_event_t
*ev
, ngx_int_t event
,
136 static ngx_int_t
ngx_eventport_process_events(ngx_cycle_t
*cycle
,
137 ngx_msec_t timer
, ngx_uint_t flags
);
139 static void *ngx_eventport_create_conf(ngx_cycle_t
*cycle
);
140 static char *ngx_eventport_init_conf(ngx_cycle_t
*cycle
, void *conf
);
143 static port_event_t
*event_list
;
144 static ngx_uint_t nevents
;
145 static timer_t event_timer
= (timer_t
) -1;
147 static ngx_str_t eventport_name
= ngx_string("eventport");
150 static ngx_command_t ngx_eventport_commands
[] = {
152 { ngx_string("eventport_events"),
153 NGX_EVENT_CONF
|NGX_CONF_TAKE1
,
154 ngx_conf_set_num_slot
,
156 offsetof(ngx_eventport_conf_t
, events
),
163 ngx_event_module_t ngx_eventport_module_ctx
= {
165 ngx_eventport_create_conf
, /* create configuration */
166 ngx_eventport_init_conf
, /* init configuration */
169 ngx_eventport_add_event
, /* add an event */
170 ngx_eventport_del_event
, /* delete an event */
171 ngx_eventport_add_event
, /* enable an event */
172 ngx_eventport_del_event
, /* disable an event */
173 NULL
, /* add an connection */
174 NULL
, /* delete an connection */
175 NULL
, /* process the changes */
176 ngx_eventport_process_events
, /* process the events */
177 ngx_eventport_init
, /* init the events */
178 ngx_eventport_done
, /* done the events */
183 ngx_module_t ngx_eventport_module
= {
185 &ngx_eventport_module_ctx
, /* module context */
186 ngx_eventport_commands
, /* module directives */
187 NGX_EVENT_MODULE
, /* module type */
188 NULL
, /* init master */
189 NULL
, /* init module */
190 NULL
, /* init process */
191 NULL
, /* init thread */
192 NULL
, /* exit thread */
193 NULL
, /* exit process */
194 NULL
, /* exit master */
195 NGX_MODULE_V1_PADDING
200 ngx_eventport_init(ngx_cycle_t
*cycle
, ngx_msec_t timer
)
203 struct itimerspec its
;
205 ngx_eventport_conf_t
*epcf
;
207 epcf
= ngx_event_get_conf(cycle
->conf_ctx
, ngx_eventport_module
);
213 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
214 "port_create() failed");
219 if (nevents
< epcf
->events
) {
221 ngx_free(event_list
);
224 event_list
= ngx_alloc(sizeof(port_event_t
) * epcf
->events
,
226 if (event_list
== NULL
) {
231 ngx_event_flags
= NGX_USE_EVENTPORT_EVENT
;
234 ngx_memzero(&pn
, sizeof(port_notify_t
));
235 pn
.portnfy_port
= ep
;
237 ngx_memzero(&sev
, sizeof(struct sigevent
));
238 sev
.sigev_notify
= SIGEV_PORT
;
239 #if !(NGX_TEST_BUILD_EVENTPORT)
240 sev
.sigev_value
.sival_ptr
= &pn
;
243 if (timer_create(CLOCK_REALTIME
, &sev
, &event_timer
) == -1) {
244 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
245 "timer_create() failed");
249 its
.it_interval
.tv_sec
= timer
/ 1000;
250 its
.it_interval
.tv_nsec
= (timer
% 1000) * 1000000;
251 its
.it_value
.tv_sec
= timer
/ 1000;
252 its
.it_value
.tv_nsec
= (timer
% 1000) * 1000000;
254 if (timer_settime(event_timer
, 0, &its
, NULL
) == -1) {
255 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
256 "timer_settime() failed");
260 ngx_event_flags
|= NGX_USE_TIMER_EVENT
;
263 nevents
= epcf
->events
;
267 ngx_event_actions
= ngx_eventport_module_ctx
.actions
;
274 ngx_eventport_done(ngx_cycle_t
*cycle
)
276 if (event_timer
!= (timer_t
) -1) {
277 if (timer_delete(event_timer
) == -1) {
278 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, ngx_errno
,
279 "timer_delete() failed");
282 event_timer
= (timer_t
) -1;
285 if (close(ep
) == -1) {
286 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, ngx_errno
,
287 "close() event port failed");
292 ngx_free(event_list
);
300 ngx_eventport_add_event(ngx_event_t
*ev
, ngx_int_t event
, ngx_uint_t flags
)
302 ngx_int_t events
, prev
;
310 if (event
== NGX_READ_EVENT
) {
313 #if (NGX_READ_EVENT != POLLIN)
320 #if (NGX_WRITE_EVENT != POLLOUT)
329 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, ev
->log
, 0,
330 "eventport add event: fd:%d ev:%04Xi", c
->fd
, events
);
332 if (port_associate(ep
, PORT_SOURCE_FD
, c
->fd
, events
,
333 (void *) ((uintptr_t) ev
| ev
->instance
))
336 ngx_log_error(NGX_LOG_ALERT
, ev
->log
, ngx_errno
,
337 "port_associate() failed");
349 ngx_eventport_del_event(ngx_event_t
*ev
, ngx_int_t event
, ngx_uint_t flags
)
355 * when the file descriptor is closed, the event port automatically
356 * dissociates it from the port, so we do not need to dissociate explicitly
357 * the event before the closing the file descriptor
360 if (flags
& NGX_CLOSE_EVENT
) {
368 if (event
== NGX_READ_EVENT
) {
378 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, ev
->log
, 0,
379 "eventport change event: fd:%d ev:%04Xi", c
->fd
, event
);
381 if (port_associate(ep
, PORT_SOURCE_FD
, c
->fd
, event
,
382 (void *) ((uintptr_t) ev
| ev
->instance
))
385 ngx_log_error(NGX_LOG_ALERT
, ev
->log
, ngx_errno
,
386 "port_associate() failed");
391 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, ev
->log
, 0,
392 "eventport del event: fd:%d", c
->fd
);
394 if (port_dissociate(ep
, PORT_SOURCE_FD
, c
->fd
) == -1) {
395 ngx_log_error(NGX_LOG_ALERT
, ev
->log
, ngx_errno
,
396 "port_dissociate() failed");
409 ngx_eventport_process_events(ngx_cycle_t
*cycle
, ngx_msec_t timer
,
417 ngx_event_t
*ev
, *rev
, *wev
, **queue
;
419 struct timespec ts
, *tp
;
421 if (timer
== NGX_TIMER_INFINITE
) {
425 ts
.tv_sec
= timer
/ 1000;
426 ts
.tv_nsec
= (timer
% 1000) * 1000000;
430 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
431 "eventport timer: %M", timer
);
435 n
= port_getn(ep
, event_list
, (u_int
) nevents
, &events
, tp
);
439 if (flags
& NGX_UPDATE_TIME
) {
445 if (timer
!= NGX_TIMER_INFINITE
) {
449 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
450 "port_getn() returned no events without timeout");
454 level
= (err
== NGX_EINTR
) ? NGX_LOG_INFO
: NGX_LOG_ALERT
;
455 ngx_log_error(level
, cycle
->log
, err
, "port_getn() failed");
460 if (timer
!= NGX_TIMER_INFINITE
) {
464 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
465 "port_getn() returned no events without timeout");
469 ngx_mutex_lock(ngx_posted_events_mutex
);
471 for (i
= 0; i
< events
; i
++) {
473 if (event_list
[i
].portev_source
== PORT_SOURCE_TIMER
) {
478 ev
= event_list
[i
].portev_user
;
480 switch (event_list
[i
].portev_source
) {
484 instance
= (uintptr_t) ev
& 1;
485 ev
= (ngx_event_t
*) ((uintptr_t) ev
& (uintptr_t) ~1);
487 if (ev
->closed
|| ev
->instance
!= instance
) {
490 * the stale event from a file descriptor
491 * that was just closed in this iteration
494 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
495 "eventport: stale event %p", ev
);
499 revents
= event_list
[i
].portev_events
;
501 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
502 "eventport: fd:%d, ev:%04Xd",
503 event_list
[i
].portev_object
, revents
);
505 if (revents
& (POLLERR
|POLLHUP
|POLLNVAL
)) {
506 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, cycle
->log
, 0,
507 "port_getn() error fd:%d ev:%04Xd",
508 event_list
[i
].portev_object
, revents
);
511 if (revents
& ~(POLLIN
|POLLOUT
|POLLERR
|POLLHUP
|POLLNVAL
)) {
512 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
513 "strange port_getn() events fd:%d ev:%04Xd",
514 event_list
[i
].portev_object
, revents
);
517 if ((revents
& (POLLERR
|POLLHUP
|POLLNVAL
))
518 && (revents
& (POLLIN
|POLLOUT
)) == 0)
521 * if the error events were returned without POLLIN or POLLOUT,
522 * then add these flags to handle the events at least in one
526 revents
|= POLLIN
|POLLOUT
;
536 if (revents
& POLLIN
) {
538 if ((flags
& NGX_POST_THREAD_EVENTS
) && !rev
->accept
) {
539 rev
->posted_ready
= 1;
545 if (flags
& NGX_POST_EVENTS
) {
546 queue
= (ngx_event_t
**) (rev
->accept
?
547 &ngx_posted_accept_events
: &ngx_posted_events
);
549 ngx_locked_post_event(rev
, queue
);
554 if (ev
->closed
|| ev
->instance
!= instance
) {
560 if (ngx_use_accept_mutex
) {
561 ngx_accept_events
= 1;
565 if (port_associate(ep
, PORT_SOURCE_FD
, c
->fd
, POLLIN
,
566 (void *) ((uintptr_t) ev
| ev
->instance
))
569 ngx_log_error(NGX_LOG_ALERT
, ev
->log
, ngx_errno
,
570 "port_associate() failed");
576 if (revents
& POLLOUT
) {
578 if (flags
& NGX_POST_THREAD_EVENTS
) {
579 wev
->posted_ready
= 1;
585 if (flags
& NGX_POST_EVENTS
) {
586 ngx_locked_post_event(wev
, &ngx_posted_events
);
596 ngx_log_error(NGX_LOG_ALERT
, cycle
->log
, 0,
597 "unexpected even_port object %d",
598 event_list
[i
].portev_object
);
603 ngx_mutex_unlock(ngx_posted_events_mutex
);
610 ngx_eventport_create_conf(ngx_cycle_t
*cycle
)
612 ngx_eventport_conf_t
*epcf
;
614 epcf
= ngx_palloc(cycle
->pool
, sizeof(ngx_eventport_conf_t
));
619 epcf
->events
= NGX_CONF_UNSET
;
626 ngx_eventport_init_conf(ngx_cycle_t
*cycle
, void *conf
)
628 ngx_eventport_conf_t
*epcf
= conf
;
630 ngx_conf_init_uint_value(epcf
->events
, 32);