112Sigor@sysoev.ru 
212Sigor@sysoev.ru /*
312Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
412Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
512Sigor@sysoev.ru  */
612Sigor@sysoev.ru 
712Sigor@sysoev.ru #include <nxt_main.h>
812Sigor@sysoev.ru 
912Sigor@sysoev.ru 
1012Sigor@sysoev.ru /*
1112Sigor@sysoev.ru  * The event ports have been introduced in Solaris 10.
1212Sigor@sysoev.ru  * The PORT_SOURCE_MQ and PORT_SOURCE_FILE sources have
1312Sigor@sysoev.ru  * been added in OpenSolaris.
1412Sigor@sysoev.ru  */
1512Sigor@sysoev.ru 
1612Sigor@sysoev.ru 
1712Sigor@sysoev.ru static nxt_int_t nxt_eventport_create(nxt_event_engine_t *engine,
1812Sigor@sysoev.ru     nxt_uint_t mchanges, nxt_uint_t mevents);
1912Sigor@sysoev.ru static void nxt_eventport_free(nxt_event_engine_t *engine);
2012Sigor@sysoev.ru static void nxt_eventport_enable(nxt_event_engine_t *engine,
2112Sigor@sysoev.ru     nxt_fd_event_t *ev);
2212Sigor@sysoev.ru static void nxt_eventport_disable(nxt_event_engine_t *engine,
2312Sigor@sysoev.ru     nxt_fd_event_t *ev);
2412Sigor@sysoev.ru static nxt_bool_t nxt_eventport_close(nxt_event_engine_t *engine,
2512Sigor@sysoev.ru     nxt_fd_event_t *ev);
2612Sigor@sysoev.ru static void nxt_eventport_enable_read(nxt_event_engine_t *engine,
2712Sigor@sysoev.ru     nxt_fd_event_t *ev);
2812Sigor@sysoev.ru static void nxt_eventport_enable_write(nxt_event_engine_t *engine,
2912Sigor@sysoev.ru     nxt_fd_event_t *ev);
3012Sigor@sysoev.ru static void nxt_eventport_enable_event(nxt_event_engine_t *engine,
3112Sigor@sysoev.ru     nxt_fd_event_t *ev, nxt_uint_t events);
3212Sigor@sysoev.ru static void nxt_eventport_disable_read(nxt_event_engine_t *engine,
3312Sigor@sysoev.ru     nxt_fd_event_t *ev);
3412Sigor@sysoev.ru static void nxt_eventport_disable_write(nxt_event_engine_t *engine,
3512Sigor@sysoev.ru     nxt_fd_event_t *ev);
3612Sigor@sysoev.ru static void nxt_eventport_disable_event(nxt_event_engine_t *engine,
3712Sigor@sysoev.ru     nxt_fd_event_t *ev);
3812Sigor@sysoev.ru static nxt_int_t nxt_eventport_commit_changes(nxt_event_engine_t *engine);
3912Sigor@sysoev.ru static void nxt_eventport_error_handler(nxt_task_t *task, void *obj,
4012Sigor@sysoev.ru     void *data);
4112Sigor@sysoev.ru static void nxt_eventport_block_read(nxt_event_engine_t *engine,
4212Sigor@sysoev.ru     nxt_fd_event_t *ev);
4312Sigor@sysoev.ru static void nxt_eventport_block_write(nxt_event_engine_t *engine,
4412Sigor@sysoev.ru     nxt_fd_event_t *ev);
4512Sigor@sysoev.ru static void nxt_eventport_oneshot_read(nxt_event_engine_t *engine,
4612Sigor@sysoev.ru     nxt_fd_event_t *ev);
4712Sigor@sysoev.ru static void nxt_eventport_oneshot_write(nxt_event_engine_t *engine,
4812Sigor@sysoev.ru     nxt_fd_event_t *ev);
4912Sigor@sysoev.ru static void nxt_eventport_enable_accept(nxt_event_engine_t *engine,
5012Sigor@sysoev.ru     nxt_fd_event_t *ev);
5112Sigor@sysoev.ru static nxt_int_t nxt_eventport_enable_post(nxt_event_engine_t *engine,
5212Sigor@sysoev.ru     nxt_work_handler_t handler);
5312Sigor@sysoev.ru static void nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo);
5412Sigor@sysoev.ru static void nxt_eventport_poll(nxt_event_engine_t *engine,
5512Sigor@sysoev.ru     nxt_msec_t timeout);
5612Sigor@sysoev.ru 
5712Sigor@sysoev.ru 
5812Sigor@sysoev.ru const nxt_event_interface_t  nxt_eventport_engine = {
5912Sigor@sysoev.ru     "eventport",
6012Sigor@sysoev.ru     nxt_eventport_create,
6112Sigor@sysoev.ru     nxt_eventport_free,
6212Sigor@sysoev.ru     nxt_eventport_enable,
6312Sigor@sysoev.ru     nxt_eventport_disable,
6412Sigor@sysoev.ru     nxt_eventport_disable,
6512Sigor@sysoev.ru     nxt_eventport_close,
6612Sigor@sysoev.ru     nxt_eventport_enable_read,
6712Sigor@sysoev.ru     nxt_eventport_enable_write,
6812Sigor@sysoev.ru     nxt_eventport_disable_read,
6912Sigor@sysoev.ru     nxt_eventport_disable_write,
7012Sigor@sysoev.ru     nxt_eventport_block_read,
7112Sigor@sysoev.ru     nxt_eventport_block_write,
7212Sigor@sysoev.ru     nxt_eventport_oneshot_read,
7312Sigor@sysoev.ru     nxt_eventport_oneshot_write,
7412Sigor@sysoev.ru     nxt_eventport_enable_accept,
7512Sigor@sysoev.ru     NULL,
7612Sigor@sysoev.ru     NULL,
7712Sigor@sysoev.ru     nxt_eventport_enable_post,
7812Sigor@sysoev.ru     nxt_eventport_signal,
7912Sigor@sysoev.ru     nxt_eventport_poll,
8012Sigor@sysoev.ru 
81*62Sigor@sysoev.ru     &nxt_unix_conn_io,
8212Sigor@sysoev.ru 
8312Sigor@sysoev.ru     NXT_NO_FILE_EVENTS,
8412Sigor@sysoev.ru     NXT_NO_SIGNAL_EVENTS,
8512Sigor@sysoev.ru };
8612Sigor@sysoev.ru 
8712Sigor@sysoev.ru 
8812Sigor@sysoev.ru static nxt_int_t
8912Sigor@sysoev.ru nxt_eventport_create(nxt_event_engine_t *engine, nxt_uint_t mchanges,
9012Sigor@sysoev.ru     nxt_uint_t mevents)
9112Sigor@sysoev.ru {
9212Sigor@sysoev.ru     nxt_eventport_change_t  *changes;
9312Sigor@sysoev.ru 
9412Sigor@sysoev.ru     engine->u.eventport.fd = -1;
9512Sigor@sysoev.ru     engine->u.eventport.mchanges = mchanges;
9612Sigor@sysoev.ru     engine->u.eventport.mevents = mevents;
9712Sigor@sysoev.ru 
9812Sigor@sysoev.ru     changes = nxt_malloc(sizeof(nxt_eventport_change_t) * mchanges);
9912Sigor@sysoev.ru     if (changes == NULL) {
10012Sigor@sysoev.ru         goto fail;
10112Sigor@sysoev.ru     }
10212Sigor@sysoev.ru 
10312Sigor@sysoev.ru     engine->u.eventport.changes = changes;
10412Sigor@sysoev.ru 
10512Sigor@sysoev.ru     engine->u.eventport.events = nxt_malloc(sizeof(port_event_t) * mevents);
10612Sigor@sysoev.ru     if (engine->u.eventport.events == NULL) {
10712Sigor@sysoev.ru         goto fail;
10812Sigor@sysoev.ru     }
10912Sigor@sysoev.ru 
11012Sigor@sysoev.ru     engine->u.eventport.fd = port_create();
11112Sigor@sysoev.ru     if (engine->u.eventport.fd == -1) {
11212Sigor@sysoev.ru         nxt_log(&engine->task, NXT_LOG_CRIT, "port_create() failed %E",
11312Sigor@sysoev.ru                 nxt_errno);
11412Sigor@sysoev.ru         goto fail;
11512Sigor@sysoev.ru     }
11612Sigor@sysoev.ru 
11712Sigor@sysoev.ru     nxt_debug(&engine->task, "port_create(): %d", engine->u.eventport.fd);
11812Sigor@sysoev.ru 
11912Sigor@sysoev.ru     if (engine->signals != NULL) {
12012Sigor@sysoev.ru         engine->u.eventport.signal_handler = engine->signals->handler;
12112Sigor@sysoev.ru     }
12212Sigor@sysoev.ru 
12312Sigor@sysoev.ru     return NXT_OK;
12412Sigor@sysoev.ru 
12512Sigor@sysoev.ru fail:
12612Sigor@sysoev.ru 
12712Sigor@sysoev.ru     nxt_eventport_free(engine);
12812Sigor@sysoev.ru 
12912Sigor@sysoev.ru     return NXT_ERROR;
13012Sigor@sysoev.ru }
13112Sigor@sysoev.ru 
13212Sigor@sysoev.ru 
13312Sigor@sysoev.ru static void
13412Sigor@sysoev.ru nxt_eventport_free(nxt_event_engine_t *engine)
13512Sigor@sysoev.ru {
13612Sigor@sysoev.ru     int  port;
13712Sigor@sysoev.ru 
13812Sigor@sysoev.ru     port = engine->u.eventport.fd;
13912Sigor@sysoev.ru 
14012Sigor@sysoev.ru     nxt_debug(&engine->task, "eventport %d free", port);
14112Sigor@sysoev.ru 
14212Sigor@sysoev.ru     if (port != -1 && close(port) != 0) {
14312Sigor@sysoev.ru         nxt_log(&engine->task, NXT_LOG_CRIT, "eventport close(%d) failed %E",
14412Sigor@sysoev.ru                 port, nxt_errno);
14512Sigor@sysoev.ru     }
14612Sigor@sysoev.ru 
14712Sigor@sysoev.ru     nxt_free(engine->u.eventport.events);
14812Sigor@sysoev.ru 
14912Sigor@sysoev.ru     nxt_memzero(&engine->u.eventport, sizeof(nxt_eventport_engine_t));
15012Sigor@sysoev.ru }
15112Sigor@sysoev.ru 
15212Sigor@sysoev.ru 
15312Sigor@sysoev.ru static void
15412Sigor@sysoev.ru nxt_eventport_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
15512Sigor@sysoev.ru {
15612Sigor@sysoev.ru     ev->read = NXT_EVENT_ACTIVE;
15712Sigor@sysoev.ru     ev->write = NXT_EVENT_ACTIVE;
15812Sigor@sysoev.ru 
15912Sigor@sysoev.ru     nxt_eventport_enable_event(engine, ev, POLLIN | POLLOUT);
16012Sigor@sysoev.ru }
16112Sigor@sysoev.ru 
16212Sigor@sysoev.ru 
16312Sigor@sysoev.ru static void
16412Sigor@sysoev.ru nxt_eventport_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
16512Sigor@sysoev.ru {
16612Sigor@sysoev.ru     if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) {
16712Sigor@sysoev.ru 
16812Sigor@sysoev.ru         ev->read = NXT_EVENT_INACTIVE;
16912Sigor@sysoev.ru         ev->write = NXT_EVENT_INACTIVE;
17012Sigor@sysoev.ru 
17112Sigor@sysoev.ru         nxt_eventport_disable_event(engine, ev);
17212Sigor@sysoev.ru     }
17312Sigor@sysoev.ru }
17412Sigor@sysoev.ru 
17512Sigor@sysoev.ru 
17612Sigor@sysoev.ru /*
17712Sigor@sysoev.ru  * port_dissociate(3):
17812Sigor@sysoev.ru  *
17912Sigor@sysoev.ru  *   The association is removed if the owner of the association closes the port.
18012Sigor@sysoev.ru  */
18112Sigor@sysoev.ru 
18212Sigor@sysoev.ru static nxt_bool_t
18312Sigor@sysoev.ru nxt_eventport_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
18412Sigor@sysoev.ru {
18512Sigor@sysoev.ru     ev->read = NXT_EVENT_INACTIVE;
18612Sigor@sysoev.ru     ev->write = NXT_EVENT_INACTIVE;
18712Sigor@sysoev.ru 
18812Sigor@sysoev.ru     return ev->changing;
18912Sigor@sysoev.ru }
19012Sigor@sysoev.ru 
19112Sigor@sysoev.ru 
19212Sigor@sysoev.ru static void
19312Sigor@sysoev.ru nxt_eventport_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
19412Sigor@sysoev.ru {
19512Sigor@sysoev.ru     nxt_uint_t  events;
19612Sigor@sysoev.ru 
19712Sigor@sysoev.ru     if (ev->read != NXT_EVENT_BLOCKED) {
19812Sigor@sysoev.ru         events = (ev->write == NXT_EVENT_INACTIVE) ? POLLIN
19912Sigor@sysoev.ru                                                    : (POLLIN | POLLOUT);
20012Sigor@sysoev.ru         nxt_eventport_enable_event(engine, ev, events);
20112Sigor@sysoev.ru     }
20212Sigor@sysoev.ru 
20312Sigor@sysoev.ru     ev->read = NXT_EVENT_ACTIVE;
20412Sigor@sysoev.ru }
20512Sigor@sysoev.ru 
20612Sigor@sysoev.ru 
20712Sigor@sysoev.ru static void
20812Sigor@sysoev.ru nxt_eventport_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
20912Sigor@sysoev.ru {
21012Sigor@sysoev.ru     nxt_uint_t  events;
21112Sigor@sysoev.ru 
21212Sigor@sysoev.ru     if (ev->write != NXT_EVENT_BLOCKED) {
21312Sigor@sysoev.ru         events = (ev->read == NXT_EVENT_INACTIVE) ? POLLOUT
21412Sigor@sysoev.ru                                                   : (POLLIN | POLLOUT);
21512Sigor@sysoev.ru         nxt_eventport_enable_event(engine, ev, events);
21612Sigor@sysoev.ru     }
21712Sigor@sysoev.ru 
21812Sigor@sysoev.ru     ev->write = NXT_EVENT_ACTIVE;
21912Sigor@sysoev.ru }
22012Sigor@sysoev.ru 
22112Sigor@sysoev.ru 
22212Sigor@sysoev.ru /*
22312Sigor@sysoev.ru  * eventport changes are batched to improve instruction and data
22412Sigor@sysoev.ru  * cache locality of several port_associate() and port_dissociate()
22512Sigor@sysoev.ru  * calls followed by port_getn() call.
22612Sigor@sysoev.ru  */
22712Sigor@sysoev.ru 
22812Sigor@sysoev.ru static void
22912Sigor@sysoev.ru nxt_eventport_enable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev,
23012Sigor@sysoev.ru     nxt_uint_t events)
23112Sigor@sysoev.ru {
23212Sigor@sysoev.ru     nxt_eventport_change_t  *change;
23312Sigor@sysoev.ru 
23412Sigor@sysoev.ru     nxt_debug(ev->task, "port %d set event: fd:%d ev:%04XD u:%p",
23512Sigor@sysoev.ru               engine->u.eventport.fd, ev->fd, events, ev);
23612Sigor@sysoev.ru 
23712Sigor@sysoev.ru     if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) {
23812Sigor@sysoev.ru         (void) nxt_eventport_commit_changes(engine);
23912Sigor@sysoev.ru     }
24012Sigor@sysoev.ru 
24112Sigor@sysoev.ru     ev->changing = 1;
24212Sigor@sysoev.ru 
24312Sigor@sysoev.ru     change = &engine->u.eventport.changes[engine->u.eventport.nchanges++];
24412Sigor@sysoev.ru     change->events = events;
24512Sigor@sysoev.ru     change->event = ev;
24612Sigor@sysoev.ru }
24712Sigor@sysoev.ru 
24812Sigor@sysoev.ru 
24912Sigor@sysoev.ru static void
25012Sigor@sysoev.ru nxt_eventport_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
25112Sigor@sysoev.ru {
25212Sigor@sysoev.ru     ev->read = NXT_EVENT_INACTIVE;
25312Sigor@sysoev.ru 
25412Sigor@sysoev.ru     if (ev->write == NXT_EVENT_INACTIVE) {
25512Sigor@sysoev.ru         nxt_eventport_disable_event(engine, ev);
25612Sigor@sysoev.ru 
25712Sigor@sysoev.ru     } else {
25812Sigor@sysoev.ru         nxt_eventport_enable_event(engine, ev, POLLOUT);
25912Sigor@sysoev.ru     }
26012Sigor@sysoev.ru }
26112Sigor@sysoev.ru 
26212Sigor@sysoev.ru 
26312Sigor@sysoev.ru static void
26412Sigor@sysoev.ru nxt_eventport_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
26512Sigor@sysoev.ru {
26612Sigor@sysoev.ru     ev->write = NXT_EVENT_INACTIVE;
26712Sigor@sysoev.ru 
26812Sigor@sysoev.ru     if (ev->read == NXT_EVENT_INACTIVE) {
26912Sigor@sysoev.ru         nxt_eventport_disable_event(engine, ev);
27012Sigor@sysoev.ru 
27112Sigor@sysoev.ru     } else {
27212Sigor@sysoev.ru         nxt_eventport_enable_event(engine, ev, POLLIN);
27312Sigor@sysoev.ru     }
27412Sigor@sysoev.ru }
27512Sigor@sysoev.ru 
27612Sigor@sysoev.ru 
27712Sigor@sysoev.ru static void
27812Sigor@sysoev.ru nxt_eventport_disable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
27912Sigor@sysoev.ru {
28012Sigor@sysoev.ru     nxt_eventport_change_t  *change;
28112Sigor@sysoev.ru 
28212Sigor@sysoev.ru     nxt_debug(ev->task, "port %d disable event : fd:%d",
28312Sigor@sysoev.ru               engine->u.eventport.fd, ev->fd);
28412Sigor@sysoev.ru 
28512Sigor@sysoev.ru     if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) {
28612Sigor@sysoev.ru         (void) nxt_eventport_commit_changes(engine);
28712Sigor@sysoev.ru     }
28812Sigor@sysoev.ru 
28912Sigor@sysoev.ru     ev->changing = 1;
29012Sigor@sysoev.ru 
29112Sigor@sysoev.ru     change = &engine->u.eventport.changes[engine->u.eventport.nchanges++];
29212Sigor@sysoev.ru     change->events = 0;
29312Sigor@sysoev.ru     change->event = ev;
29412Sigor@sysoev.ru }
29512Sigor@sysoev.ru 
29612Sigor@sysoev.ru 
29712Sigor@sysoev.ru static nxt_int_t
29812Sigor@sysoev.ru nxt_eventport_commit_changes(nxt_event_engine_t *engine)
29912Sigor@sysoev.ru {
30012Sigor@sysoev.ru     int                     ret, port;
30112Sigor@sysoev.ru     nxt_int_t               retval;
30212Sigor@sysoev.ru     nxt_fd_event_t          *ev;
30312Sigor@sysoev.ru     nxt_eventport_change_t  *change, *end;
30412Sigor@sysoev.ru 
30512Sigor@sysoev.ru     port = engine->u.eventport.fd;
30612Sigor@sysoev.ru 
30712Sigor@sysoev.ru     nxt_debug(&engine->task, "eventport %d changes:%ui",
30812Sigor@sysoev.ru               port, engine->u.eventport.nchanges);
30912Sigor@sysoev.ru 
31012Sigor@sysoev.ru     retval = NXT_OK;
31112Sigor@sysoev.ru     change = engine->u.eventport.changes;
31212Sigor@sysoev.ru     end = change + engine->u.eventport.nchanges;
31312Sigor@sysoev.ru 
31412Sigor@sysoev.ru     do {
31512Sigor@sysoev.ru         ev = change->event;
31612Sigor@sysoev.ru         ev->changing = 0;
31712Sigor@sysoev.ru 
31812Sigor@sysoev.ru         if (change->events != 0) {
31912Sigor@sysoev.ru             nxt_debug(ev->task, "port_associate(%d): fd:%d ev:%04XD u:%p",
32012Sigor@sysoev.ru                       port, ev->fd, change->events, ev);
32112Sigor@sysoev.ru 
32212Sigor@sysoev.ru             ret = port_associate(port, PORT_SOURCE_FD,
32312Sigor@sysoev.ru                                  ev->fd, change->events, ev);
32412Sigor@sysoev.ru 
32512Sigor@sysoev.ru             if (nxt_fast_path(ret == 0)) {
32612Sigor@sysoev.ru                 goto next;
32712Sigor@sysoev.ru             }
32812Sigor@sysoev.ru 
32912Sigor@sysoev.ru             nxt_log(ev->task, NXT_LOG_CRIT,
33012Sigor@sysoev.ru                     "port_associate(%d, %d, %d, %04XD) failed %E",
33112Sigor@sysoev.ru                     port, PORT_SOURCE_FD, ev->fd, change->events, nxt_errno);
33212Sigor@sysoev.ru 
33312Sigor@sysoev.ru         } else {
33412Sigor@sysoev.ru             nxt_debug(ev->task, "port_dissociate(%d): fd:%d", port, ev->fd);
33512Sigor@sysoev.ru 
33612Sigor@sysoev.ru             ret = port_dissociate(port, PORT_SOURCE_FD, ev->fd);
33712Sigor@sysoev.ru 
33812Sigor@sysoev.ru             if (nxt_fast_path(ret == 0)) {
33912Sigor@sysoev.ru                 goto next;
34012Sigor@sysoev.ru             }
34112Sigor@sysoev.ru 
34212Sigor@sysoev.ru             nxt_log(ev->task, NXT_LOG_CRIT,
34312Sigor@sysoev.ru                     "port_dissociate(%d, %d, %d) failed %E",
34412Sigor@sysoev.ru                     port, PORT_SOURCE_FD, ev->fd, nxt_errno);
34512Sigor@sysoev.ru         }
34612Sigor@sysoev.ru 
34712Sigor@sysoev.ru         nxt_work_queue_add(&engine->fast_work_queue,
34812Sigor@sysoev.ru                            nxt_eventport_error_handler,
34912Sigor@sysoev.ru                            ev->task, ev, ev->data);
35012Sigor@sysoev.ru 
35112Sigor@sysoev.ru         retval = NXT_ERROR;
35212Sigor@sysoev.ru 
35312Sigor@sysoev.ru     next:
35412Sigor@sysoev.ru 
35512Sigor@sysoev.ru         change++;
35612Sigor@sysoev.ru 
35712Sigor@sysoev.ru     } while (change < end);
35812Sigor@sysoev.ru 
35912Sigor@sysoev.ru     engine->u.eventport.nchanges = 0;
36012Sigor@sysoev.ru 
36112Sigor@sysoev.ru     return retval;
36212Sigor@sysoev.ru }
36312Sigor@sysoev.ru 
36412Sigor@sysoev.ru 
36512Sigor@sysoev.ru static void
36612Sigor@sysoev.ru nxt_eventport_error_handler(nxt_task_t *task, void *obj, void *data)
36712Sigor@sysoev.ru {
36812Sigor@sysoev.ru     nxt_fd_event_t  *ev;
36912Sigor@sysoev.ru 
37012Sigor@sysoev.ru     ev = obj;
37112Sigor@sysoev.ru 
37212Sigor@sysoev.ru     ev->read = NXT_EVENT_INACTIVE;
37312Sigor@sysoev.ru     ev->write = NXT_EVENT_INACTIVE;
37412Sigor@sysoev.ru 
37512Sigor@sysoev.ru     ev->error_handler(task, ev, data);
37612Sigor@sysoev.ru }
37712Sigor@sysoev.ru 
37812Sigor@sysoev.ru 
37912Sigor@sysoev.ru static void
38012Sigor@sysoev.ru nxt_eventport_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
38112Sigor@sysoev.ru {
38212Sigor@sysoev.ru     if (ev->read != NXT_EVENT_INACTIVE) {
38312Sigor@sysoev.ru         ev->read = NXT_EVENT_BLOCKED;
38412Sigor@sysoev.ru     }
38512Sigor@sysoev.ru }
38612Sigor@sysoev.ru 
38712Sigor@sysoev.ru 
38812Sigor@sysoev.ru static void
38912Sigor@sysoev.ru nxt_eventport_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
39012Sigor@sysoev.ru {
39112Sigor@sysoev.ru     if (ev->write != NXT_EVENT_INACTIVE) {
39212Sigor@sysoev.ru         ev->write = NXT_EVENT_BLOCKED;
39312Sigor@sysoev.ru     }
39412Sigor@sysoev.ru }
39512Sigor@sysoev.ru 
39612Sigor@sysoev.ru 
39712Sigor@sysoev.ru static void
39812Sigor@sysoev.ru nxt_eventport_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
39912Sigor@sysoev.ru {
40012Sigor@sysoev.ru     if (ev->read == NXT_EVENT_INACTIVE) {
40112Sigor@sysoev.ru         ev->read = NXT_EVENT_ACTIVE;
40212Sigor@sysoev.ru 
40312Sigor@sysoev.ru         nxt_eventport_enable_event(engine, ev, POLLIN);
40412Sigor@sysoev.ru     }
40512Sigor@sysoev.ru }
40612Sigor@sysoev.ru 
40712Sigor@sysoev.ru 
40812Sigor@sysoev.ru static void
40912Sigor@sysoev.ru nxt_eventport_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
41012Sigor@sysoev.ru {
41112Sigor@sysoev.ru     if (ev->write == NXT_EVENT_INACTIVE) {
41212Sigor@sysoev.ru         ev->write = NXT_EVENT_ACTIVE;
41312Sigor@sysoev.ru 
41412Sigor@sysoev.ru         nxt_eventport_enable_event(engine, ev, POLLOUT);
41512Sigor@sysoev.ru     }
41612Sigor@sysoev.ru }
41712Sigor@sysoev.ru 
41812Sigor@sysoev.ru 
41912Sigor@sysoev.ru static void
42012Sigor@sysoev.ru nxt_eventport_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
42112Sigor@sysoev.ru {
42212Sigor@sysoev.ru     ev->read = NXT_EVENT_LEVEL;
42312Sigor@sysoev.ru 
42412Sigor@sysoev.ru     nxt_eventport_enable_event(engine, ev, POLLIN);
42512Sigor@sysoev.ru }
42612Sigor@sysoev.ru 
42712Sigor@sysoev.ru 
42812Sigor@sysoev.ru static nxt_int_t
42912Sigor@sysoev.ru nxt_eventport_enable_post(nxt_event_engine_t *engine,
43012Sigor@sysoev.ru     nxt_work_handler_t handler)
43112Sigor@sysoev.ru {
43212Sigor@sysoev.ru     engine->u.eventport.post_handler = handler;
43312Sigor@sysoev.ru 
43412Sigor@sysoev.ru     return NXT_OK;
43512Sigor@sysoev.ru }
43612Sigor@sysoev.ru 
43712Sigor@sysoev.ru 
43812Sigor@sysoev.ru static void
43912Sigor@sysoev.ru nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo)
44012Sigor@sysoev.ru {
44112Sigor@sysoev.ru     int  port;
44212Sigor@sysoev.ru 
44312Sigor@sysoev.ru     port = engine->u.eventport.fd;
44412Sigor@sysoev.ru 
44512Sigor@sysoev.ru     nxt_debug(&engine->task, "port_send(%d, %ui)", port, signo);
44612Sigor@sysoev.ru 
44712Sigor@sysoev.ru     if (port_send(port, signo, NULL) != 0) {
44812Sigor@sysoev.ru         nxt_log(&engine->task, NXT_LOG_CRIT, "port_send(%d) failed %E",
44912Sigor@sysoev.ru                 port, nxt_errno);
45012Sigor@sysoev.ru     }
45112Sigor@sysoev.ru }
45212Sigor@sysoev.ru 
45312Sigor@sysoev.ru 
45412Sigor@sysoev.ru static void
45512Sigor@sysoev.ru nxt_eventport_poll(nxt_event_engine_t *engine, nxt_msec_t timeout)
45612Sigor@sysoev.ru {
45712Sigor@sysoev.ru     int                 n, events, signo;
45812Sigor@sysoev.ru     uint_t              nevents;
45912Sigor@sysoev.ru     nxt_err_t           err;
46012Sigor@sysoev.ru     nxt_uint_t          i, level;
46112Sigor@sysoev.ru     timespec_t          ts, *tp;
46212Sigor@sysoev.ru     port_event_t        *event;
46312Sigor@sysoev.ru     nxt_fd_event_t      *ev;
46412Sigor@sysoev.ru     nxt_work_handler_t  handler;
46512Sigor@sysoev.ru 
46612Sigor@sysoev.ru     if (engine->u.eventport.nchanges != 0) {
46712Sigor@sysoev.ru         if (nxt_eventport_commit_changes(engine) != NXT_OK) {
46812Sigor@sysoev.ru             /* Error handlers have been enqueued on failure. */
46912Sigor@sysoev.ru             timeout = 0;
47012Sigor@sysoev.ru         }
47112Sigor@sysoev.ru     }
47212Sigor@sysoev.ru 
47312Sigor@sysoev.ru     if (timeout == NXT_INFINITE_MSEC) {
47412Sigor@sysoev.ru         tp = NULL;
47512Sigor@sysoev.ru 
47612Sigor@sysoev.ru     } else {
47712Sigor@sysoev.ru         ts.tv_sec = timeout / 1000;
47812Sigor@sysoev.ru         ts.tv_nsec = (timeout % 1000) * 1000000;
47912Sigor@sysoev.ru         tp = &ts;
48012Sigor@sysoev.ru     }
48112Sigor@sysoev.ru 
48212Sigor@sysoev.ru     nxt_debug(&engine->task, "port_getn(%d) timeout: %M",
48312Sigor@sysoev.ru               engine->u.eventport.fd, timeout);
48412Sigor@sysoev.ru 
48512Sigor@sysoev.ru     /*
48612Sigor@sysoev.ru      * A trap for possible error when Solaris does not update nevents
48712Sigor@sysoev.ru      * if ETIME or EINTR is returned.  This issue will be logged as
48812Sigor@sysoev.ru      * "unexpected port_getn() event".
48912Sigor@sysoev.ru      *
49012Sigor@sysoev.ru      * The details are in OpenSolaris mailing list thread "port_getn()
49112Sigor@sysoev.ru      * and timeouts - is this a bug or an undocumented feature?"
49212Sigor@sysoev.ru      */
49312Sigor@sysoev.ru     event = &engine->u.eventport.events[0];
49412Sigor@sysoev.ru     event->portev_events = -1; /* invalid port events */
49512Sigor@sysoev.ru     event->portev_source = -1; /* invalid port source */
49612Sigor@sysoev.ru     event->portev_object = -1;
49712Sigor@sysoev.ru     event->portev_user = (void *) -1;
49812Sigor@sysoev.ru 
49912Sigor@sysoev.ru     nevents = 1;
50012Sigor@sysoev.ru     n = port_getn(engine->u.eventport.fd, engine->u.eventport.events,
50112Sigor@sysoev.ru                   engine->u.eventport.mevents, &nevents, tp);
50212Sigor@sysoev.ru 
50312Sigor@sysoev.ru     /*
50412Sigor@sysoev.ru      * 32-bit port_getn() on Solaris 10 x86 returns large negative
50512Sigor@sysoev.ru      * values instead of 0 when returning immediately.
50612Sigor@sysoev.ru      */
50712Sigor@sysoev.ru     err = (n < 0) ? nxt_errno : 0;
50812Sigor@sysoev.ru 
50912Sigor@sysoev.ru     nxt_thread_time_update(engine->task.thread);
51012Sigor@sysoev.ru 
51112Sigor@sysoev.ru     if (n == -1) {
51212Sigor@sysoev.ru         if (err == NXT_ETIME || err == NXT_EINTR) {
51312Sigor@sysoev.ru             if (nevents != 0) {
51412Sigor@sysoev.ru                 nxt_log(&engine->task, NXT_LOG_CRIT,
51512Sigor@sysoev.ru                         "port_getn(%d) failed %E, events:%ud",
51612Sigor@sysoev.ru                         engine->u.eventport.fd, err, nevents);
51712Sigor@sysoev.ru             }
51812Sigor@sysoev.ru         }
51912Sigor@sysoev.ru 
52012Sigor@sysoev.ru         if (err != NXT_ETIME) {
52112Sigor@sysoev.ru             level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT;
52212Sigor@sysoev.ru 
52312Sigor@sysoev.ru             nxt_log(&engine->task, level, "port_getn(%d) failed %E",
52412Sigor@sysoev.ru                     engine->u.eventport.fd, err);
52512Sigor@sysoev.ru 
52612Sigor@sysoev.ru             if (err != NXT_EINTR) {
52712Sigor@sysoev.ru                 return;
52812Sigor@sysoev.ru             }
52912Sigor@sysoev.ru         }
53012Sigor@sysoev.ru     }
53112Sigor@sysoev.ru 
53212Sigor@sysoev.ru     nxt_debug(&engine->task, "port_getn(%d) events: %d",
53312Sigor@sysoev.ru               engine->u.eventport.fd, nevents);
53412Sigor@sysoev.ru 
53512Sigor@sysoev.ru     for (i = 0; i < nevents; i++) {
53612Sigor@sysoev.ru         event = &engine->u.eventport.events[i];
53712Sigor@sysoev.ru 
53812Sigor@sysoev.ru         switch (event->portev_source) {
53912Sigor@sysoev.ru 
54012Sigor@sysoev.ru         case PORT_SOURCE_FD:
54112Sigor@sysoev.ru             ev = event->portev_user;
54212Sigor@sysoev.ru             events = event->portev_events;
54312Sigor@sysoev.ru 
54412Sigor@sysoev.ru             nxt_debug(ev->task, "eventport: fd:%d ev:%04Xd u:%p rd:%d wr:%d",
54512Sigor@sysoev.ru                       event->portev_object, events, ev, ev->read, ev->write);
54612Sigor@sysoev.ru 
54712Sigor@sysoev.ru             if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
54812Sigor@sysoev.ru                 nxt_log(ev->task, NXT_LOG_CRIT,
54912Sigor@sysoev.ru                         "port_getn(%d) error fd:%d events:%04Xud",
55012Sigor@sysoev.ru                         engine->u.eventport.fd, ev->fd, events);
55112Sigor@sysoev.ru 
55212Sigor@sysoev.ru                 nxt_work_queue_add(&engine->fast_work_queue,
55312Sigor@sysoev.ru                                    nxt_eventport_error_handler,
55412Sigor@sysoev.ru                                    ev->task, ev, ev->data);
55512Sigor@sysoev.ru                 continue;
55612Sigor@sysoev.ru             }
55712Sigor@sysoev.ru 
55812Sigor@sysoev.ru             if (events & POLLIN) {
55912Sigor@sysoev.ru                 ev->read_ready = 1;
56012Sigor@sysoev.ru 
56112Sigor@sysoev.ru                 if (ev->read != NXT_EVENT_BLOCKED) {
56212Sigor@sysoev.ru                     nxt_work_queue_add(ev->read_work_queue, ev->read_handler,
56312Sigor@sysoev.ru                                        ev->task, ev, ev->data);
56412Sigor@sysoev.ru 
56512Sigor@sysoev.ru                 }
56612Sigor@sysoev.ru 
56712Sigor@sysoev.ru                 if (ev->read != NXT_EVENT_LEVEL) {
56812Sigor@sysoev.ru                     ev->read = NXT_EVENT_INACTIVE;
56912Sigor@sysoev.ru                 }
57012Sigor@sysoev.ru             }
57112Sigor@sysoev.ru 
57212Sigor@sysoev.ru             if (events & POLLOUT) {
57312Sigor@sysoev.ru                 ev->write_ready = 1;
57412Sigor@sysoev.ru 
57512Sigor@sysoev.ru                 if (ev->write != NXT_EVENT_BLOCKED) {
57612Sigor@sysoev.ru                     nxt_work_queue_add(ev->write_work_queue, ev->write_handler,
57712Sigor@sysoev.ru                                        ev->task, ev, ev->data);
57812Sigor@sysoev.ru                 }
57912Sigor@sysoev.ru 
58012Sigor@sysoev.ru                 ev->write = NXT_EVENT_INACTIVE;
58112Sigor@sysoev.ru             }
58212Sigor@sysoev.ru 
58312Sigor@sysoev.ru             /*
58412Sigor@sysoev.ru              * Reactivate counterpart direction, because the
58512Sigor@sysoev.ru              * eventport is oneshot notification facility.
58612Sigor@sysoev.ru              */
58712Sigor@sysoev.ru             events = (ev->read == NXT_EVENT_INACTIVE) ? 0 : POLLIN;
58812Sigor@sysoev.ru             events |= (ev->write == NXT_EVENT_INACTIVE) ? 0 : POLLOUT;
58912Sigor@sysoev.ru 
59012Sigor@sysoev.ru             if (events != 0) {
59112Sigor@sysoev.ru                 nxt_eventport_enable_event(engine, ev, events);
59212Sigor@sysoev.ru             }
59312Sigor@sysoev.ru 
59412Sigor@sysoev.ru             break;
59512Sigor@sysoev.ru 
59612Sigor@sysoev.ru         case PORT_SOURCE_USER:
59712Sigor@sysoev.ru             nxt_debug(&engine->task, "eventport: user ev:%d u:%p",
59812Sigor@sysoev.ru                       event->portev_events, event->portev_user);
59912Sigor@sysoev.ru 
60012Sigor@sysoev.ru             signo = event->portev_events;
60112Sigor@sysoev.ru 
60212Sigor@sysoev.ru             handler = (signo == 0) ? engine->u.eventport.post_handler
60312Sigor@sysoev.ru                                    : engine->u.eventport.signal_handler;
60412Sigor@sysoev.ru 
60512Sigor@sysoev.ru             nxt_work_queue_add(&engine->fast_work_queue, handler,
60612Sigor@sysoev.ru                                &engine->task, (void *) (uintptr_t) signo, NULL);
60712Sigor@sysoev.ru 
60812Sigor@sysoev.ru             break;
60912Sigor@sysoev.ru 
61012Sigor@sysoev.ru         default:
61112Sigor@sysoev.ru             nxt_log(&engine->task, NXT_LOG_CRIT,
61212Sigor@sysoev.ru                     "unexpected port_getn(%d) event: ev:%d src:%d obj:%p u:%p",
61312Sigor@sysoev.ru                     engine->u.eventport.fd, event->portev_events,
61412Sigor@sysoev.ru                     event->portev_source, event->portev_object,
61512Sigor@sysoev.ru                     event->portev_user);
61612Sigor@sysoev.ru         }
61712Sigor@sysoev.ru     }
61812Sigor@sysoev.ru }
619