xref: /unit/src/nxt_pollset_engine.c (revision 564:762f8c976ead)
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  * pollset has been introduced in AIX 5L 5.3.
1212Sigor@sysoev.ru  *
1312Sigor@sysoev.ru  * pollset_create() returns a pollset_t descriptor which is not
1412Sigor@sysoev.ru  * a file descriptor, so it cannot be added to another pollset.
1512Sigor@sysoev.ru  * The first pollset_create() call returns 0.
1612Sigor@sysoev.ru  */
1712Sigor@sysoev.ru 
1812Sigor@sysoev.ru 
1912Sigor@sysoev.ru #define NXT_POLLSET_ADD     0
2012Sigor@sysoev.ru #define NXT_POLLSET_UPDATE  1
2112Sigor@sysoev.ru #define NXT_POLLSET_CHANGE  2
2212Sigor@sysoev.ru #define NXT_POLLSET_DELETE  3
2312Sigor@sysoev.ru 
2412Sigor@sysoev.ru 
2512Sigor@sysoev.ru static nxt_int_t nxt_pollset_create(nxt_event_engine_t *engine,
2612Sigor@sysoev.ru     nxt_uint_t mchanges, nxt_uint_t mevents);
2712Sigor@sysoev.ru static void nxt_pollset_free(nxt_event_engine_t *engine);
2812Sigor@sysoev.ru static void nxt_pollset_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev);
2912Sigor@sysoev.ru static void nxt_pollset_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev);
3012Sigor@sysoev.ru static nxt_bool_t nxt_pollset_close(nxt_event_engine_t *engine,
3112Sigor@sysoev.ru     nxt_fd_event_t *ev);
3212Sigor@sysoev.ru static void nxt_pollset_enable_read(nxt_event_engine_t *engine,
3312Sigor@sysoev.ru     nxt_fd_event_t *ev);
3412Sigor@sysoev.ru static void nxt_pollset_enable_write(nxt_event_engine_t *engine,
3512Sigor@sysoev.ru     nxt_fd_event_t *ev);
3612Sigor@sysoev.ru static void nxt_pollset_disable_read(nxt_event_engine_t *engine,
3712Sigor@sysoev.ru     nxt_fd_event_t *ev);
3812Sigor@sysoev.ru static void nxt_pollset_disable_write(nxt_event_engine_t *engine,
3912Sigor@sysoev.ru     nxt_fd_event_t *ev);
4012Sigor@sysoev.ru static void nxt_pollset_block_read(nxt_event_engine_t *engine,
4112Sigor@sysoev.ru     nxt_fd_event_t *ev);
4212Sigor@sysoev.ru static void nxt_pollset_block_write(nxt_event_engine_t *engine,
4312Sigor@sysoev.ru     nxt_fd_event_t *ev);
4412Sigor@sysoev.ru static void nxt_pollset_oneshot_read(nxt_event_engine_t *engine,
4512Sigor@sysoev.ru     nxt_fd_event_t *ev);
4612Sigor@sysoev.ru static void nxt_pollset_oneshot_write(nxt_event_engine_t *engine,
4712Sigor@sysoev.ru     nxt_fd_event_t *ev);
4812Sigor@sysoev.ru static void nxt_pollset_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev,
4912Sigor@sysoev.ru     nxt_uint_t op, nxt_uint_t events);
5012Sigor@sysoev.ru static nxt_int_t nxt_pollset_commit_changes(nxt_event_engine_t *engine);
5112Sigor@sysoev.ru static void nxt_pollset_change_error(nxt_event_engine_t *engine,
5212Sigor@sysoev.ru     nxt_fd_event_t *ev);
5312Sigor@sysoev.ru static void nxt_pollset_remove(nxt_event_engine_t *engine, nxt_fd_t fd);
5412Sigor@sysoev.ru static nxt_int_t nxt_pollset_write(nxt_event_engine_t *engine,
5512Sigor@sysoev.ru     struct poll_ctl *ctl, int n);
5612Sigor@sysoev.ru static void nxt_pollset_poll(nxt_event_engine_t *engine, nxt_msec_t timeout);
5712Sigor@sysoev.ru 
5812Sigor@sysoev.ru 
5912Sigor@sysoev.ru const nxt_event_interface_t  nxt_pollset_engine = {
6012Sigor@sysoev.ru     "pollset",
6112Sigor@sysoev.ru     nxt_pollset_create,
6212Sigor@sysoev.ru     nxt_pollset_free,
6312Sigor@sysoev.ru     nxt_pollset_enable,
6412Sigor@sysoev.ru     nxt_pollset_disable,
6512Sigor@sysoev.ru     nxt_pollset_disable,
6612Sigor@sysoev.ru     nxt_pollset_close,
6712Sigor@sysoev.ru     nxt_pollset_enable_read,
6812Sigor@sysoev.ru     nxt_pollset_enable_write,
6912Sigor@sysoev.ru     nxt_pollset_disable_read,
7012Sigor@sysoev.ru     nxt_pollset_disable_write,
7112Sigor@sysoev.ru     nxt_pollset_block_read,
7212Sigor@sysoev.ru     nxt_pollset_block_write,
7312Sigor@sysoev.ru     nxt_pollset_oneshot_read,
7412Sigor@sysoev.ru     nxt_pollset_oneshot_write,
7512Sigor@sysoev.ru     nxt_pollset_enable_read,
7612Sigor@sysoev.ru     NULL,
7712Sigor@sysoev.ru     NULL,
7812Sigor@sysoev.ru     NULL,
7912Sigor@sysoev.ru     NULL,
8012Sigor@sysoev.ru     nxt_pollset_poll,
8112Sigor@sysoev.ru 
8262Sigor@sysoev.ru     &nxt_unix_conn_io,
8312Sigor@sysoev.ru 
8412Sigor@sysoev.ru     NXT_NO_FILE_EVENTS,
8512Sigor@sysoev.ru     NXT_NO_SIGNAL_EVENTS,
8612Sigor@sysoev.ru };
8712Sigor@sysoev.ru 
8812Sigor@sysoev.ru 
8912Sigor@sysoev.ru static nxt_int_t
nxt_pollset_create(nxt_event_engine_t * engine,nxt_uint_t mchanges,nxt_uint_t mevents)9012Sigor@sysoev.ru nxt_pollset_create(nxt_event_engine_t *engine, nxt_uint_t mchanges,
9112Sigor@sysoev.ru     nxt_uint_t mevents)
9212Sigor@sysoev.ru {
9312Sigor@sysoev.ru     void  *changes;
9412Sigor@sysoev.ru 
9512Sigor@sysoev.ru     engine->u.pollset.ps = -1;
9612Sigor@sysoev.ru     engine->u.pollset.mchanges = mchanges;
9712Sigor@sysoev.ru     engine->u.pollset.mevents = mevents;
9812Sigor@sysoev.ru 
9912Sigor@sysoev.ru     changes = nxt_malloc(sizeof(nxt_pollset_change_t) * mchanges);
10012Sigor@sysoev.ru     if (changes == NULL) {
10112Sigor@sysoev.ru         goto fail;
10212Sigor@sysoev.ru     }
10312Sigor@sysoev.ru 
10412Sigor@sysoev.ru     engine->u.pollset.changes = changes;
10512Sigor@sysoev.ru 
10612Sigor@sysoev.ru     /*
10712Sigor@sysoev.ru      * NXT_POLLSET_CHANGE requires two struct poll_ctl's
10812Sigor@sysoev.ru      * for PS_DELETE and subsequent PS_ADD.
10912Sigor@sysoev.ru      */
11012Sigor@sysoev.ru     changes = nxt_malloc(2 * sizeof(struct poll_ctl) * mchanges);
11112Sigor@sysoev.ru     if (changes == NULL) {
11212Sigor@sysoev.ru         goto fail;
11312Sigor@sysoev.ru     }
11412Sigor@sysoev.ru 
11512Sigor@sysoev.ru     engine->u.pollset.write_changes = changes;
11612Sigor@sysoev.ru 
11712Sigor@sysoev.ru     engine->u.pollset.events = nxt_malloc(sizeof(struct pollfd) * mevents);
11812Sigor@sysoev.ru     if (engine->u.pollset.events == NULL) {
11912Sigor@sysoev.ru         goto fail;
12012Sigor@sysoev.ru     }
12112Sigor@sysoev.ru 
12212Sigor@sysoev.ru     engine->u.pollset.ps = pollset_create(-1);
12312Sigor@sysoev.ru 
12412Sigor@sysoev.ru     if (engine->u.pollset.ps == -1) {
125*564Svbart@nginx.com         nxt_alert(&engine->task, "pollset_create() failed %E", nxt_errno);
12612Sigor@sysoev.ru         goto fail;
12712Sigor@sysoev.ru     }
12812Sigor@sysoev.ru 
12912Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset_create(): %d", engine->u.pollset.ps);
13012Sigor@sysoev.ru 
13112Sigor@sysoev.ru     return NXT_OK;
13212Sigor@sysoev.ru 
13312Sigor@sysoev.ru fail:
13412Sigor@sysoev.ru 
13512Sigor@sysoev.ru     nxt_pollset_free(engine);
13612Sigor@sysoev.ru 
13712Sigor@sysoev.ru     return NXT_ERROR;
13812Sigor@sysoev.ru }
13912Sigor@sysoev.ru 
14012Sigor@sysoev.ru 
14112Sigor@sysoev.ru static void
nxt_pollset_free(nxt_event_engine_t * engine)14212Sigor@sysoev.ru nxt_pollset_free(nxt_event_engine_t *engine)
14312Sigor@sysoev.ru {
14412Sigor@sysoev.ru     pollset_t  ps;
14512Sigor@sysoev.ru 
14612Sigor@sysoev.ru     ps = engine->u.pollset.ps;
14712Sigor@sysoev.ru 
14812Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset %d free", ps);
14912Sigor@sysoev.ru 
15012Sigor@sysoev.ru     if (ps != -1 && pollset_destroy(ps) != 0) {
151*564Svbart@nginx.com         nxt_alert(&engine->task, "pollset_destroy(%d) failed %E",
152*564Svbart@nginx.com                   ps, nxt_errno);
15312Sigor@sysoev.ru     }
15412Sigor@sysoev.ru 
15512Sigor@sysoev.ru     nxt_free(engine->u.pollset.events);
15612Sigor@sysoev.ru     nxt_free(engine->u.pollset.write_changes);
15712Sigor@sysoev.ru     nxt_free(engine->u.pollset.changes);
15812Sigor@sysoev.ru     nxt_fd_event_hash_destroy(&engine->u.pollset.fd_hash);
15912Sigor@sysoev.ru 
16012Sigor@sysoev.ru     nxt_memzero(&engine->u.pollset, sizeof(nxt_pollset_engine_t));
16112Sigor@sysoev.ru }
16212Sigor@sysoev.ru 
16312Sigor@sysoev.ru 
16412Sigor@sysoev.ru static void
nxt_pollset_enable(nxt_event_engine_t * engine,nxt_fd_event_t * ev)16512Sigor@sysoev.ru nxt_pollset_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
16612Sigor@sysoev.ru {
16712Sigor@sysoev.ru     ev->read = NXT_EVENT_ACTIVE;
16812Sigor@sysoev.ru     ev->write = NXT_EVENT_ACTIVE;
16912Sigor@sysoev.ru 
17012Sigor@sysoev.ru     nxt_pollset_change(engine, ev, NXT_POLLSET_ADD, POLLIN | POLLOUT);
17112Sigor@sysoev.ru }
17212Sigor@sysoev.ru 
17312Sigor@sysoev.ru 
17412Sigor@sysoev.ru static void
nxt_pollset_disable(nxt_event_engine_t * engine,nxt_fd_event_t * ev)17512Sigor@sysoev.ru nxt_pollset_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
17612Sigor@sysoev.ru {
17712Sigor@sysoev.ru     if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) {
17812Sigor@sysoev.ru 
17912Sigor@sysoev.ru         ev->read = NXT_EVENT_INACTIVE;
18012Sigor@sysoev.ru         ev->write = NXT_EVENT_INACTIVE;
18112Sigor@sysoev.ru 
18212Sigor@sysoev.ru         nxt_pollset_change(engine, ev, NXT_POLLSET_DELETE, 0);
18312Sigor@sysoev.ru     }
18412Sigor@sysoev.ru }
18512Sigor@sysoev.ru 
18612Sigor@sysoev.ru 
18712Sigor@sysoev.ru /*
18812Sigor@sysoev.ru  * A closed descriptor must be deleted from a pollset, otherwise next
18912Sigor@sysoev.ru  * pollset_poll() will return POLLNVAL on it.  However, pollset_ctl()
19012Sigor@sysoev.ru  * allows to delete the already closed file descriptor from the pollset
19112Sigor@sysoev.ru  * using PS_DELETE, so the removal can be batched, pollset_ctl(2):
19212Sigor@sysoev.ru  *
19312Sigor@sysoev.ru  *   After a file descriptor is added to a pollset, the file descriptor will
19412Sigor@sysoev.ru  *   not be removed until a pollset_ctl call with the cmd of PS_DELETE is
19512Sigor@sysoev.ru  *   executed.  The file descriptor remains in the pollset even if the file
19612Sigor@sysoev.ru  *   descriptor is closed.  A pollset_poll operation on a pollset containing
19712Sigor@sysoev.ru  *   a closed file descriptor returns a POLLNVAL event for that file
19812Sigor@sysoev.ru  *   descriptor. If the file descriptor is later allocated to a new object,
19912Sigor@sysoev.ru  *   the new object will be polled on future pollset_poll calls.
20012Sigor@sysoev.ru  */
20112Sigor@sysoev.ru 
20212Sigor@sysoev.ru static nxt_bool_t
nxt_pollset_close(nxt_event_engine_t * engine,nxt_fd_event_t * ev)20312Sigor@sysoev.ru nxt_pollset_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
20412Sigor@sysoev.ru {
20512Sigor@sysoev.ru     nxt_pollset_disable(engine, ev);
20612Sigor@sysoev.ru 
20712Sigor@sysoev.ru     return ev->changing;
20812Sigor@sysoev.ru }
20912Sigor@sysoev.ru 
21012Sigor@sysoev.ru 
21112Sigor@sysoev.ru static void
nxt_pollset_enable_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)21212Sigor@sysoev.ru nxt_pollset_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
21312Sigor@sysoev.ru {
21412Sigor@sysoev.ru     nxt_uint_t  op, events;
21512Sigor@sysoev.ru 
21612Sigor@sysoev.ru     if (ev->read != NXT_EVENT_BLOCKED) {
21712Sigor@sysoev.ru 
21812Sigor@sysoev.ru         events = POLLIN;
21912Sigor@sysoev.ru 
22012Sigor@sysoev.ru         if (ev->write == NXT_EVENT_INACTIVE) {
22112Sigor@sysoev.ru             op = NXT_POLLSET_ADD;
22212Sigor@sysoev.ru 
22312Sigor@sysoev.ru         } else if (ev->write == NXT_EVENT_BLOCKED) {
22412Sigor@sysoev.ru             ev->write = NXT_EVENT_INACTIVE;
22512Sigor@sysoev.ru             op = NXT_POLLSET_CHANGE;
22612Sigor@sysoev.ru 
22712Sigor@sysoev.ru         } else {
22812Sigor@sysoev.ru             op = NXT_POLLSET_UPDATE;
22912Sigor@sysoev.ru             events = POLLIN | POLLOUT;
23012Sigor@sysoev.ru         }
23112Sigor@sysoev.ru 
23212Sigor@sysoev.ru         nxt_pollset_change(engine, ev, op, events);
23312Sigor@sysoev.ru     }
23412Sigor@sysoev.ru 
23512Sigor@sysoev.ru     ev->read = NXT_EVENT_ACTIVE;
23612Sigor@sysoev.ru }
23712Sigor@sysoev.ru 
23812Sigor@sysoev.ru 
23912Sigor@sysoev.ru static void
nxt_pollset_enable_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)24012Sigor@sysoev.ru nxt_pollset_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
24112Sigor@sysoev.ru {
24212Sigor@sysoev.ru     nxt_uint_t  op, events;
24312Sigor@sysoev.ru 
24412Sigor@sysoev.ru     if (ev->write != NXT_EVENT_BLOCKED) {
24512Sigor@sysoev.ru 
24612Sigor@sysoev.ru         events = POLLOUT;
24712Sigor@sysoev.ru 
24812Sigor@sysoev.ru         if (ev->read == NXT_EVENT_INACTIVE) {
24912Sigor@sysoev.ru             op = NXT_POLLSET_ADD;
25012Sigor@sysoev.ru 
25112Sigor@sysoev.ru         } else if (ev->read == NXT_EVENT_BLOCKED) {
25212Sigor@sysoev.ru             ev->read = NXT_EVENT_INACTIVE;
25312Sigor@sysoev.ru             op = NXT_POLLSET_CHANGE;
25412Sigor@sysoev.ru 
25512Sigor@sysoev.ru         } else {
25612Sigor@sysoev.ru             op = NXT_POLLSET_UPDATE;
25712Sigor@sysoev.ru             events = POLLIN | POLLOUT;
25812Sigor@sysoev.ru         }
25912Sigor@sysoev.ru 
26012Sigor@sysoev.ru         nxt_pollset_change(engine, ev, op, events);
26112Sigor@sysoev.ru     }
26212Sigor@sysoev.ru 
26312Sigor@sysoev.ru     ev->write = NXT_EVENT_ACTIVE;
26412Sigor@sysoev.ru }
26512Sigor@sysoev.ru 
26612Sigor@sysoev.ru 
26712Sigor@sysoev.ru static void
nxt_pollset_disable_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)26812Sigor@sysoev.ru nxt_pollset_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
26912Sigor@sysoev.ru {
27012Sigor@sysoev.ru     nxt_uint_t  op, events;
27112Sigor@sysoev.ru 
27212Sigor@sysoev.ru     ev->read = NXT_EVENT_INACTIVE;
27312Sigor@sysoev.ru 
27412Sigor@sysoev.ru     if (ev->write <= NXT_EVENT_BLOCKED) {
27512Sigor@sysoev.ru         ev->write = NXT_EVENT_INACTIVE;
27612Sigor@sysoev.ru         op = NXT_POLLSET_DELETE;
27712Sigor@sysoev.ru         events = POLLREMOVE;
27812Sigor@sysoev.ru 
27912Sigor@sysoev.ru     } else {
28012Sigor@sysoev.ru         op = NXT_POLLSET_CHANGE;
28112Sigor@sysoev.ru         events = POLLOUT;
28212Sigor@sysoev.ru     }
28312Sigor@sysoev.ru 
28412Sigor@sysoev.ru     nxt_pollset_change(engine, ev, op, events);
28512Sigor@sysoev.ru }
28612Sigor@sysoev.ru 
28712Sigor@sysoev.ru 
28812Sigor@sysoev.ru static void
nxt_pollset_disable_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)28912Sigor@sysoev.ru nxt_pollset_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
29012Sigor@sysoev.ru {
29112Sigor@sysoev.ru     nxt_uint_t  op, events;
29212Sigor@sysoev.ru 
29312Sigor@sysoev.ru     ev->write = NXT_EVENT_INACTIVE;
29412Sigor@sysoev.ru 
29512Sigor@sysoev.ru     if (ev->read <= NXT_EVENT_BLOCKED) {
29612Sigor@sysoev.ru         ev->read = NXT_EVENT_INACTIVE;
29712Sigor@sysoev.ru         op = NXT_POLLSET_DELETE;
29812Sigor@sysoev.ru         events = POLLREMOVE;
29912Sigor@sysoev.ru 
30012Sigor@sysoev.ru     } else {
30112Sigor@sysoev.ru         op = NXT_POLLSET_CHANGE;
30212Sigor@sysoev.ru         events = POLLIN;
30312Sigor@sysoev.ru     }
30412Sigor@sysoev.ru 
30512Sigor@sysoev.ru     nxt_pollset_change(engine, ev, op, events);
30612Sigor@sysoev.ru }
30712Sigor@sysoev.ru 
30812Sigor@sysoev.ru 
30912Sigor@sysoev.ru static void
nxt_pollset_block_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)31012Sigor@sysoev.ru nxt_pollset_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
31112Sigor@sysoev.ru {
31212Sigor@sysoev.ru     if (ev->read != NXT_EVENT_INACTIVE) {
31312Sigor@sysoev.ru         ev->read = NXT_EVENT_BLOCKED;
31412Sigor@sysoev.ru     }
31512Sigor@sysoev.ru }
31612Sigor@sysoev.ru 
31712Sigor@sysoev.ru 
31812Sigor@sysoev.ru static void
nxt_pollset_block_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)31912Sigor@sysoev.ru nxt_pollset_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
32012Sigor@sysoev.ru {
32112Sigor@sysoev.ru     if (ev->write != NXT_EVENT_INACTIVE) {
32212Sigor@sysoev.ru         ev->write = NXT_EVENT_BLOCKED;
32312Sigor@sysoev.ru     }
32412Sigor@sysoev.ru }
32512Sigor@sysoev.ru 
32612Sigor@sysoev.ru 
32712Sigor@sysoev.ru static void
nxt_pollset_oneshot_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)32812Sigor@sysoev.ru nxt_pollset_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
32912Sigor@sysoev.ru {
33012Sigor@sysoev.ru     nxt_pollset_enable_read(engine, ev);
33112Sigor@sysoev.ru 
33212Sigor@sysoev.ru     ev->read = NXT_EVENT_ONESHOT;
33312Sigor@sysoev.ru }
33412Sigor@sysoev.ru 
33512Sigor@sysoev.ru 
33612Sigor@sysoev.ru static void
nxt_pollset_oneshot_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)33712Sigor@sysoev.ru nxt_pollset_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
33812Sigor@sysoev.ru {
33912Sigor@sysoev.ru     nxt_pollset_enable_write(engine, ev);
34012Sigor@sysoev.ru 
34112Sigor@sysoev.ru     ev->write = NXT_EVENT_ONESHOT;
34212Sigor@sysoev.ru }
34312Sigor@sysoev.ru 
34412Sigor@sysoev.ru 
34512Sigor@sysoev.ru /*
34612Sigor@sysoev.ru  * PS_ADD adds only a new file descriptor to a pollset.
34712Sigor@sysoev.ru  * PS_DELETE removes a file descriptor from a pollset.
34812Sigor@sysoev.ru  *
34912Sigor@sysoev.ru  * PS_MOD can add a new file descriptor or modify events for a file
35012Sigor@sysoev.ru  * descriptor which is already in a pollset.  However, modified events
35112Sigor@sysoev.ru  * are always ORed, so to delete an event for a file descriptor,
35212Sigor@sysoev.ru  * the file descriptor must be removed using PS_DELETE and then
35312Sigor@sysoev.ru  * added again without the event.
35412Sigor@sysoev.ru  */
35512Sigor@sysoev.ru 
35612Sigor@sysoev.ru static void
nxt_pollset_change(nxt_event_engine_t * engine,nxt_fd_event_t * ev,nxt_uint_t op,nxt_uint_t events)35712Sigor@sysoev.ru nxt_pollset_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev,
35812Sigor@sysoev.ru     nxt_uint_t op, nxt_uint_t events)
35912Sigor@sysoev.ru {
36012Sigor@sysoev.ru     nxt_pollset_change_t  *change;
36112Sigor@sysoev.ru 
36212Sigor@sysoev.ru     nxt_debug(ev->task, "pollset %d change fd:%d op:%ui ev:%04Xi",
36312Sigor@sysoev.ru               engine->u.pollset.ps, ev->fd, op, events);
36412Sigor@sysoev.ru 
36512Sigor@sysoev.ru     if (engine->u.pollset.nchanges >= engine->u.pollset.mchanges) {
36612Sigor@sysoev.ru         (void) nxt_pollset_commit_changes(engine);
36712Sigor@sysoev.ru     }
36812Sigor@sysoev.ru 
36912Sigor@sysoev.ru     ev->changing = 1;
37012Sigor@sysoev.ru 
37112Sigor@sysoev.ru     change = &engine->u.pollset.changes[engine->u.pollset.nchanges++];
37212Sigor@sysoev.ru     change->op = op;
37312Sigor@sysoev.ru     change->cmd = (op == NXT_POLLSET_DELETE) ? PS_DELETE : PS_MOD;
37412Sigor@sysoev.ru     change->events = events;
37512Sigor@sysoev.ru     change->event = ev;
37612Sigor@sysoev.ru }
37712Sigor@sysoev.ru 
37812Sigor@sysoev.ru 
37912Sigor@sysoev.ru static nxt_int_t
nxt_pollset_commit_changes(nxt_event_engine_t * engine)38012Sigor@sysoev.ru nxt_pollset_commit_changes(nxt_event_engine_t *engine)
38112Sigor@sysoev.ru {
38212Sigor@sysoev.ru     size_t                n;
38312Sigor@sysoev.ru     nxt_int_t             ret, retval;
38412Sigor@sysoev.ru     nxt_fd_event_t        *ev;
38512Sigor@sysoev.ru     struct poll_ctl       *ctl, *write_changes;
38612Sigor@sysoev.ru     nxt_pollset_change_t  *change, *end;
38712Sigor@sysoev.ru 
38812Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset %d changes:%ui",
38912Sigor@sysoev.ru               engine->u.pollset.ps, engine->u.pollset.nchanges);
39012Sigor@sysoev.ru 
39112Sigor@sysoev.ru     retval = NXT_OK;
39212Sigor@sysoev.ru     n = 0;
39312Sigor@sysoev.ru     write_changes = engine->u.pollset.write_changes;
39412Sigor@sysoev.ru     change = engine->u.pollset.changes;
39512Sigor@sysoev.ru     end = change + engine->u.pollset.nchanges;
39612Sigor@sysoev.ru 
39712Sigor@sysoev.ru     do {
39812Sigor@sysoev.ru         ev = change->event;
39912Sigor@sysoev.ru         ev->changing = 0;
40012Sigor@sysoev.ru 
40112Sigor@sysoev.ru         nxt_debug(&engine->task, "pollset fd:%d op:%d ev:%04Xd",
40212Sigor@sysoev.ru                   ev->fd, change->op, change->events);
40312Sigor@sysoev.ru 
40412Sigor@sysoev.ru         if (change->op == NXT_POLLSET_CHANGE) {
40512Sigor@sysoev.ru             ctl = &write_changes[n++];
40612Sigor@sysoev.ru             ctl->cmd = PS_DELETE;
40712Sigor@sysoev.ru             ctl->events = 0;
40812Sigor@sysoev.ru             ctl->fd = ev->fd;
40912Sigor@sysoev.ru         }
41012Sigor@sysoev.ru 
41112Sigor@sysoev.ru         ctl = &write_changes[n++];
41212Sigor@sysoev.ru         ctl->cmd = change->cmd;
41312Sigor@sysoev.ru         ctl->events = change->events;
41412Sigor@sysoev.ru         ctl->fd = ev->fd;
41512Sigor@sysoev.ru 
41612Sigor@sysoev.ru         change++;
41712Sigor@sysoev.ru 
41812Sigor@sysoev.ru     } while (change < end);
41912Sigor@sysoev.ru 
42012Sigor@sysoev.ru     change = engine->u.pollset.changes;
42112Sigor@sysoev.ru     end = change + engine->u.pollset.nchanges;
42212Sigor@sysoev.ru 
42312Sigor@sysoev.ru     ret = nxt_pollset_write(engine, write_changes, n);
42412Sigor@sysoev.ru 
42512Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
42612Sigor@sysoev.ru 
42712Sigor@sysoev.ru         do {
42812Sigor@sysoev.ru             nxt_pollset_change_error(engine, change->event);
42912Sigor@sysoev.ru             change++;
43012Sigor@sysoev.ru         } while (change < end);
43112Sigor@sysoev.ru 
43212Sigor@sysoev.ru         engine->u.pollset.nchanges = 0;
43312Sigor@sysoev.ru 
43412Sigor@sysoev.ru         return NXT_ERROR;
43512Sigor@sysoev.ru     }
43612Sigor@sysoev.ru 
43712Sigor@sysoev.ru     do {
43812Sigor@sysoev.ru         ev = change->event;
43912Sigor@sysoev.ru 
44012Sigor@sysoev.ru         if (change->op == NXT_POLLSET_ADD) {
44112Sigor@sysoev.ru             ret = nxt_fd_event_hash_add(&engine->u.pollset.fd_hash, ev->fd, ev);
44212Sigor@sysoev.ru 
44312Sigor@sysoev.ru             if (nxt_slow_path(ret != NXT_OK)) {
44412Sigor@sysoev.ru                 nxt_pollset_change_error(engine, ev);
44512Sigor@sysoev.ru                 retval = NXT_ERROR;
44612Sigor@sysoev.ru             }
44712Sigor@sysoev.ru 
44812Sigor@sysoev.ru         } else if (change->op == NXT_POLLSET_DELETE) {
44912Sigor@sysoev.ru             nxt_fd_event_hash_delete(&engine->task, &engine->u.pollset.fd_hash,
45012Sigor@sysoev.ru                                      ev->fd, 0);
45112Sigor@sysoev.ru         }
45212Sigor@sysoev.ru 
45312Sigor@sysoev.ru         /* Nothing to do for NXT_POLLSET_UPDATE and NXT_POLLSET_CHANGE. */
45412Sigor@sysoev.ru 
45512Sigor@sysoev.ru         change++;
45612Sigor@sysoev.ru 
45712Sigor@sysoev.ru     } while (change < end);
45812Sigor@sysoev.ru 
45912Sigor@sysoev.ru     engine->u.pollset.nchanges = 0;
46012Sigor@sysoev.ru 
46112Sigor@sysoev.ru     return retval;
46212Sigor@sysoev.ru }
46312Sigor@sysoev.ru 
46412Sigor@sysoev.ru 
46512Sigor@sysoev.ru static void
nxt_pollset_change_error(nxt_event_engine_t * engine,nxt_fd_event_t * ev)46612Sigor@sysoev.ru nxt_pollset_change_error(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
46712Sigor@sysoev.ru {
46812Sigor@sysoev.ru     ev->read = NXT_EVENT_INACTIVE;
46912Sigor@sysoev.ru     ev->write = NXT_EVENT_INACTIVE;
47012Sigor@sysoev.ru 
47112Sigor@sysoev.ru     nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler,
47212Sigor@sysoev.ru                        ev->task, ev, ev->data);
47312Sigor@sysoev.ru 
47412Sigor@sysoev.ru     nxt_fd_event_hash_delete(&engine->task, &engine->u.pollset.fd_hash,
47512Sigor@sysoev.ru                              ev->fd, 1);
47612Sigor@sysoev.ru 
47712Sigor@sysoev.ru     nxt_pollset_remove(engine, ev->fd);
47812Sigor@sysoev.ru }
47912Sigor@sysoev.ru 
48012Sigor@sysoev.ru 
48112Sigor@sysoev.ru static void
nxt_pollset_remove(nxt_event_engine_t * engine,nxt_fd_t fd)48212Sigor@sysoev.ru nxt_pollset_remove(nxt_event_engine_t *engine, nxt_fd_t fd)
48312Sigor@sysoev.ru {
48412Sigor@sysoev.ru     int              n;
48512Sigor@sysoev.ru     struct pollfd    pfd;
48612Sigor@sysoev.ru     struct poll_ctl  ctl;
48712Sigor@sysoev.ru 
48812Sigor@sysoev.ru     pfd.fd = fd;
48912Sigor@sysoev.ru     pfd.events = 0;
49012Sigor@sysoev.ru     pfd.revents = 0;
49112Sigor@sysoev.ru 
49212Sigor@sysoev.ru     n = pollset_query(engine->u.pollset.ps, &pfd);
49312Sigor@sysoev.ru 
49412Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset_query(%d, %d): %d",
49512Sigor@sysoev.ru               engine->u.pollset.ps, fd, n);
49612Sigor@sysoev.ru 
49712Sigor@sysoev.ru     if (n == 0) {
49812Sigor@sysoev.ru         /* The file descriptor is not in the pollset. */
49912Sigor@sysoev.ru         return;
50012Sigor@sysoev.ru     }
50112Sigor@sysoev.ru 
50212Sigor@sysoev.ru     if (n == -1) {
503*564Svbart@nginx.com         nxt_alert(&engine->task, "pollset_query(%d, %d) failed %E",
504*564Svbart@nginx.com                   engine->u.pollset.ps, fd, nxt_errno);
50512Sigor@sysoev.ru         /* Fall through. */
50612Sigor@sysoev.ru     }
50712Sigor@sysoev.ru 
50812Sigor@sysoev.ru     /* n == 1: The file descriptor is in the pollset. */
50912Sigor@sysoev.ru 
51012Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset %d remove fd:%d",
51112Sigor@sysoev.ru               engine->u.pollset.ps, fd);
51212Sigor@sysoev.ru 
51312Sigor@sysoev.ru     ctl.cmd = PS_DELETE;
51412Sigor@sysoev.ru     ctl.events = 0;
51512Sigor@sysoev.ru     ctl.fd = fd;
51612Sigor@sysoev.ru 
51712Sigor@sysoev.ru     nxt_pollset_write(engine, &ctl, 1);
51812Sigor@sysoev.ru }
51912Sigor@sysoev.ru 
52012Sigor@sysoev.ru 
52112Sigor@sysoev.ru static nxt_int_t
nxt_pollset_write(nxt_event_engine_t * engine,struct poll_ctl * ctl,int n)52212Sigor@sysoev.ru nxt_pollset_write(nxt_event_engine_t *engine, struct poll_ctl *ctl, int n)
52312Sigor@sysoev.ru {
52412Sigor@sysoev.ru     pollset_t  ps;
52512Sigor@sysoev.ru 
52612Sigor@sysoev.ru     ps = engine->u.pollset.ps;
52712Sigor@sysoev.ru 
52812Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset_ctl(%d) changes:%d", ps, n);
52912Sigor@sysoev.ru 
53012Sigor@sysoev.ru     nxt_set_errno(0);
53112Sigor@sysoev.ru 
53212Sigor@sysoev.ru     n = pollset_ctl(ps, ctl, n);
53312Sigor@sysoev.ru 
53412Sigor@sysoev.ru     if (nxt_fast_path(n == 0)) {
53512Sigor@sysoev.ru         return NXT_OK;
53612Sigor@sysoev.ru     }
53712Sigor@sysoev.ru 
538*564Svbart@nginx.com     nxt_alert(&engine->task, "pollset_ctl(%d) failed: %d %E", ps, n, nxt_errno);
53912Sigor@sysoev.ru 
54012Sigor@sysoev.ru     return NXT_ERROR;
54112Sigor@sysoev.ru }
54212Sigor@sysoev.ru 
54312Sigor@sysoev.ru 
54412Sigor@sysoev.ru static void
nxt_pollset_poll(nxt_event_engine_t * engine,nxt_msec_t timeout)54512Sigor@sysoev.ru nxt_pollset_poll(nxt_event_engine_t *engine, nxt_msec_t timeout)
54612Sigor@sysoev.ru {
54712Sigor@sysoev.ru     int             nevents;
54812Sigor@sysoev.ru     nxt_fd_t        fd;
54912Sigor@sysoev.ru     nxt_int_t       i;
55012Sigor@sysoev.ru     nxt_err_t       err;
55112Sigor@sysoev.ru     nxt_uint_t      events, level;
55212Sigor@sysoev.ru     struct pollfd   *pfd;
55312Sigor@sysoev.ru     nxt_fd_event_t  *ev;
55412Sigor@sysoev.ru 
55512Sigor@sysoev.ru     if (engine->u.pollset.nchanges != 0) {
55612Sigor@sysoev.ru         if (nxt_pollset_commit_changes(engine) != NXT_OK) {
55712Sigor@sysoev.ru             /* Error handlers have been enqueued on failure. */
55812Sigor@sysoev.ru             timeout = 0;
55912Sigor@sysoev.ru         }
56012Sigor@sysoev.ru     }
56112Sigor@sysoev.ru 
56212Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset_poll(%d) timeout:%M",
56312Sigor@sysoev.ru               engine->u.pollset.ps, timeout);
56412Sigor@sysoev.ru 
56512Sigor@sysoev.ru     nevents = pollset_poll(engine->u.pollset.ps, engine->u.pollset.events,
56612Sigor@sysoev.ru                            engine->u.pollset.mevents, timeout);
56712Sigor@sysoev.ru 
56812Sigor@sysoev.ru     err = (nevents == -1) ? nxt_errno : 0;
56912Sigor@sysoev.ru 
57012Sigor@sysoev.ru     nxt_thread_time_update(engine->task.thread);
57112Sigor@sysoev.ru 
57212Sigor@sysoev.ru     nxt_debug(&engine->task, "pollset_poll(%d): %d",
57312Sigor@sysoev.ru               engine->u.pollset.ps, nevents);
57412Sigor@sysoev.ru 
57512Sigor@sysoev.ru     if (nevents == -1) {
576*564Svbart@nginx.com         level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT;
57712Sigor@sysoev.ru 
57812Sigor@sysoev.ru         nxt_log(&engine->task, level, "pollset_poll(%d) failed %E",
57912Sigor@sysoev.ru                 engine->u.pollset.ps, err);
58012Sigor@sysoev.ru 
58112Sigor@sysoev.ru         return;
58212Sigor@sysoev.ru     }
58312Sigor@sysoev.ru 
58412Sigor@sysoev.ru     for (i = 0; i < nevents; i++) {
58512Sigor@sysoev.ru 
58612Sigor@sysoev.ru         pfd = &engine->u.pollset.events[i];
58712Sigor@sysoev.ru         fd = pfd->fd;
58812Sigor@sysoev.ru         events = pfd->revents;
58912Sigor@sysoev.ru 
59012Sigor@sysoev.ru         ev = nxt_fd_event_hash_get(&engine->task, &engine->u.pollset.fd_hash,
59112Sigor@sysoev.ru                                    fd);
59212Sigor@sysoev.ru 
59312Sigor@sysoev.ru         if (nxt_slow_path(ev == NULL)) {
594*564Svbart@nginx.com             nxt_alert(&engine->task,
595*564Svbart@nginx.com                       "pollset_poll(%d) returned invalid "
596*564Svbart@nginx.com                       "fd:%d ev:%04Xd rev:%04uXi",
597*564Svbart@nginx.com                       engine->u.pollset.ps, fd, pfd->events, events);
59812Sigor@sysoev.ru 
59912Sigor@sysoev.ru             nxt_pollset_remove(engine, fd);
60012Sigor@sysoev.ru             continue;
60112Sigor@sysoev.ru         }
60212Sigor@sysoev.ru 
60312Sigor@sysoev.ru         nxt_debug(ev->task, "pollset: fd:%d ev:%04uXi", fd, events);
60412Sigor@sysoev.ru 
60512Sigor@sysoev.ru         if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
606*564Svbart@nginx.com             nxt_alert(ev->task,
607*564Svbart@nginx.com                       "pollset_poll(%d) error fd:%d ev:%04Xd rev:%04uXi",
608*564Svbart@nginx.com                       engine->u.pollset.ps, fd, pfd->events, events);
60912Sigor@sysoev.ru 
61012Sigor@sysoev.ru             nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler,
61112Sigor@sysoev.ru                                ev->task, ev, ev->data);
61212Sigor@sysoev.ru             continue;
61312Sigor@sysoev.ru         }
61412Sigor@sysoev.ru 
61512Sigor@sysoev.ru         if (events & POLLIN) {
61612Sigor@sysoev.ru             ev->read_ready = 1;
61712Sigor@sysoev.ru 
61812Sigor@sysoev.ru             if (ev->read != NXT_EVENT_BLOCKED) {
61912Sigor@sysoev.ru                 nxt_work_queue_add(ev->read_work_queue, ev->read_handler,
62012Sigor@sysoev.ru                                    ev->task, ev, ev->data);
62112Sigor@sysoev.ru             }
62212Sigor@sysoev.ru 
62312Sigor@sysoev.ru             if (ev->read == NXT_EVENT_BLOCKED
62412Sigor@sysoev.ru                 || ev->read == NXT_EVENT_ONESHOT)
62512Sigor@sysoev.ru             {
62612Sigor@sysoev.ru                 nxt_pollset_disable_read(engine, ev);
62712Sigor@sysoev.ru             }
62812Sigor@sysoev.ru         }
62912Sigor@sysoev.ru 
63012Sigor@sysoev.ru         if (events & POLLOUT) {
63112Sigor@sysoev.ru             ev->write_ready = 1;
63212Sigor@sysoev.ru 
63312Sigor@sysoev.ru             if (ev->write != NXT_EVENT_BLOCKED) {
63412Sigor@sysoev.ru                 nxt_work_queue_add(ev->write_work_queue, ev->write_handler,
63512Sigor@sysoev.ru                                    ev->task, ev, ev->data);
63612Sigor@sysoev.ru             }
63712Sigor@sysoev.ru 
63812Sigor@sysoev.ru             if (ev->write == NXT_EVENT_BLOCKED
63912Sigor@sysoev.ru                 || ev->write == NXT_EVENT_ONESHOT)
64012Sigor@sysoev.ru             {
64112Sigor@sysoev.ru                 nxt_pollset_disable_write(engine, ev);
64212Sigor@sysoev.ru             }
64312Sigor@sysoev.ru         }
64412Sigor@sysoev.ru     }
64512Sigor@sysoev.ru }
646