xref: /unit/src/nxt_select_engine.c (revision 62)
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 static nxt_int_t nxt_select_create(nxt_event_engine_t *engine,
1112Sigor@sysoev.ru     nxt_uint_t mchanges, nxt_uint_t mevents);
1212Sigor@sysoev.ru static void nxt_select_free(nxt_event_engine_t *engine);
1312Sigor@sysoev.ru static void nxt_select_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev);
1412Sigor@sysoev.ru static void nxt_select_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev);
1512Sigor@sysoev.ru static nxt_bool_t nxt_select_close(nxt_event_engine_t *engine,
1612Sigor@sysoev.ru     nxt_fd_event_t *ev);
1712Sigor@sysoev.ru static void nxt_select_enable_read(nxt_event_engine_t *engine,
1812Sigor@sysoev.ru     nxt_fd_event_t *ev);
1912Sigor@sysoev.ru static void nxt_select_enable_write(nxt_event_engine_t *engine,
2012Sigor@sysoev.ru     nxt_fd_event_t *ev);
2112Sigor@sysoev.ru static void nxt_select_error_handler(nxt_task_t *task, void *obj, void *data);
2212Sigor@sysoev.ru static void nxt_select_disable_read(nxt_event_engine_t *engine,
2312Sigor@sysoev.ru     nxt_fd_event_t *ev);
2412Sigor@sysoev.ru static void nxt_select_disable_write(nxt_event_engine_t *engine,
2512Sigor@sysoev.ru     nxt_fd_event_t *ev);
2612Sigor@sysoev.ru static void nxt_select_block_read(nxt_event_engine_t *engine,
2712Sigor@sysoev.ru     nxt_fd_event_t *ev);
2812Sigor@sysoev.ru static void nxt_select_block_write(nxt_event_engine_t *engine,
2912Sigor@sysoev.ru     nxt_fd_event_t *ev);
3012Sigor@sysoev.ru static void nxt_select_oneshot_read(nxt_event_engine_t *engine,
3112Sigor@sysoev.ru     nxt_fd_event_t *ev);
3212Sigor@sysoev.ru static void nxt_select_oneshot_write(nxt_event_engine_t *engine,
3312Sigor@sysoev.ru     nxt_fd_event_t *ev);
3412Sigor@sysoev.ru static void nxt_select_poll(nxt_event_engine_t *engine, nxt_msec_t timeout);
3512Sigor@sysoev.ru 
3612Sigor@sysoev.ru 
3712Sigor@sysoev.ru const nxt_event_interface_t  nxt_select_engine = {
3812Sigor@sysoev.ru     "select",
3912Sigor@sysoev.ru     nxt_select_create,
4012Sigor@sysoev.ru     nxt_select_free,
4112Sigor@sysoev.ru     nxt_select_enable,
4212Sigor@sysoev.ru     nxt_select_disable,
4312Sigor@sysoev.ru     nxt_select_disable,
4412Sigor@sysoev.ru     nxt_select_close,
4512Sigor@sysoev.ru     nxt_select_enable_read,
4612Sigor@sysoev.ru     nxt_select_enable_write,
4712Sigor@sysoev.ru     nxt_select_disable_read,
4812Sigor@sysoev.ru     nxt_select_disable_write,
4912Sigor@sysoev.ru     nxt_select_block_read,
5012Sigor@sysoev.ru     nxt_select_block_write,
5112Sigor@sysoev.ru     nxt_select_oneshot_read,
5212Sigor@sysoev.ru     nxt_select_oneshot_write,
5312Sigor@sysoev.ru     nxt_select_enable_read,
5412Sigor@sysoev.ru     NULL,
5512Sigor@sysoev.ru     NULL,
5612Sigor@sysoev.ru     NULL,
5712Sigor@sysoev.ru     NULL,
5812Sigor@sysoev.ru     nxt_select_poll,
5912Sigor@sysoev.ru 
60*62Sigor@sysoev.ru     &nxt_unix_conn_io,
6112Sigor@sysoev.ru 
6212Sigor@sysoev.ru     NXT_NO_FILE_EVENTS,
6312Sigor@sysoev.ru     NXT_NO_SIGNAL_EVENTS,
6412Sigor@sysoev.ru };
6512Sigor@sysoev.ru 
6612Sigor@sysoev.ru 
6712Sigor@sysoev.ru static nxt_int_t
6812Sigor@sysoev.ru nxt_select_create(nxt_event_engine_t *engine, nxt_uint_t mchanges,
6912Sigor@sysoev.ru     nxt_uint_t mevents)
7012Sigor@sysoev.ru {
7112Sigor@sysoev.ru     engine->u.select.nfds = -1;
7212Sigor@sysoev.ru     engine->u.select.update_nfds = 0;
7312Sigor@sysoev.ru 
7412Sigor@sysoev.ru     engine->u.select.events = nxt_zalloc(FD_SETSIZE * sizeof(nxt_fd_event_t *));
7512Sigor@sysoev.ru 
7612Sigor@sysoev.ru     if (engine->u.select.events != NULL) {
7712Sigor@sysoev.ru         return NXT_OK;
7812Sigor@sysoev.ru     }
7912Sigor@sysoev.ru 
8012Sigor@sysoev.ru     nxt_select_free(engine);
8112Sigor@sysoev.ru 
8212Sigor@sysoev.ru     return NXT_ERROR;
8312Sigor@sysoev.ru }
8412Sigor@sysoev.ru 
8512Sigor@sysoev.ru 
8612Sigor@sysoev.ru static void
8712Sigor@sysoev.ru nxt_select_free(nxt_event_engine_t *engine)
8812Sigor@sysoev.ru {
8912Sigor@sysoev.ru     nxt_debug(&engine->task, "select free");
9012Sigor@sysoev.ru 
9112Sigor@sysoev.ru     nxt_free(engine->u.select.events);
9212Sigor@sysoev.ru 
9312Sigor@sysoev.ru     nxt_memzero(&engine->u.select, sizeof(nxt_select_engine_t));
9412Sigor@sysoev.ru }
9512Sigor@sysoev.ru 
9612Sigor@sysoev.ru 
9712Sigor@sysoev.ru static void
9812Sigor@sysoev.ru nxt_select_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
9912Sigor@sysoev.ru {
10012Sigor@sysoev.ru     nxt_select_enable_read(engine, ev);
10112Sigor@sysoev.ru     nxt_select_enable_write(engine, ev);
10212Sigor@sysoev.ru }
10312Sigor@sysoev.ru 
10412Sigor@sysoev.ru 
10512Sigor@sysoev.ru static void
10612Sigor@sysoev.ru nxt_select_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
10712Sigor@sysoev.ru {
10812Sigor@sysoev.ru     if (ev->read != NXT_EVENT_INACTIVE) {
10912Sigor@sysoev.ru         nxt_select_disable_read(engine, ev);
11012Sigor@sysoev.ru     }
11112Sigor@sysoev.ru 
11212Sigor@sysoev.ru     if (ev->write != NXT_EVENT_INACTIVE) {
11312Sigor@sysoev.ru         nxt_select_disable_write(engine, ev);
11412Sigor@sysoev.ru     }
11512Sigor@sysoev.ru }
11612Sigor@sysoev.ru 
11712Sigor@sysoev.ru 
11812Sigor@sysoev.ru static nxt_bool_t
11912Sigor@sysoev.ru nxt_select_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
12012Sigor@sysoev.ru {
12112Sigor@sysoev.ru     nxt_select_disable(engine, ev);
12212Sigor@sysoev.ru 
12312Sigor@sysoev.ru     return 0;
12412Sigor@sysoev.ru }
12512Sigor@sysoev.ru 
12612Sigor@sysoev.ru 
12712Sigor@sysoev.ru static void
12812Sigor@sysoev.ru nxt_select_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
12912Sigor@sysoev.ru {
13012Sigor@sysoev.ru     nxt_fd_t  fd;
13112Sigor@sysoev.ru 
13212Sigor@sysoev.ru     fd = ev->fd;
13312Sigor@sysoev.ru 
13412Sigor@sysoev.ru     nxt_debug(ev->task, "select enable read: fd:%d", fd);
13512Sigor@sysoev.ru 
13612Sigor@sysoev.ru     if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) {
13712Sigor@sysoev.ru         nxt_work_queue_add(&engine->fast_work_queue, nxt_select_error_handler,
13812Sigor@sysoev.ru                            ev->task, ev, ev->data);
13912Sigor@sysoev.ru         return;
14012Sigor@sysoev.ru     }
14112Sigor@sysoev.ru 
14212Sigor@sysoev.ru     ev->read = NXT_EVENT_ACTIVE;
14312Sigor@sysoev.ru 
14412Sigor@sysoev.ru     FD_SET(fd, &engine->u.select.main_read_fd_set);
14512Sigor@sysoev.ru     engine->u.select.events[fd] = ev;
14612Sigor@sysoev.ru 
14712Sigor@sysoev.ru     if (engine->u.select.nfds < fd) {
14812Sigor@sysoev.ru         engine->u.select.nfds = fd;
14912Sigor@sysoev.ru         engine->u.select.update_nfds = 0;
15012Sigor@sysoev.ru     }
15112Sigor@sysoev.ru }
15212Sigor@sysoev.ru 
15312Sigor@sysoev.ru 
15412Sigor@sysoev.ru static void
15512Sigor@sysoev.ru nxt_select_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
15612Sigor@sysoev.ru {
15712Sigor@sysoev.ru     nxt_fd_t  fd;
15812Sigor@sysoev.ru 
15912Sigor@sysoev.ru     fd = ev->fd;
16012Sigor@sysoev.ru 
16112Sigor@sysoev.ru     nxt_debug(ev->task, "select enable write: fd:%d", fd);
16212Sigor@sysoev.ru 
16312Sigor@sysoev.ru     if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) {
16412Sigor@sysoev.ru         nxt_work_queue_add(&engine->fast_work_queue, nxt_select_error_handler,
16512Sigor@sysoev.ru                            ev->task, ev, ev->data);
16612Sigor@sysoev.ru         return;
16712Sigor@sysoev.ru     }
16812Sigor@sysoev.ru 
16912Sigor@sysoev.ru     ev->write = NXT_EVENT_ACTIVE;
17012Sigor@sysoev.ru 
17112Sigor@sysoev.ru     FD_SET(fd, &engine->u.select.main_write_fd_set);
17212Sigor@sysoev.ru     engine->u.select.events[fd] = ev;
17312Sigor@sysoev.ru 
17412Sigor@sysoev.ru     if (engine->u.select.nfds < fd) {
17512Sigor@sysoev.ru         engine->u.select.nfds = fd;
17612Sigor@sysoev.ru         engine->u.select.update_nfds = 0;
17712Sigor@sysoev.ru     }
17812Sigor@sysoev.ru }
17912Sigor@sysoev.ru 
18012Sigor@sysoev.ru 
18112Sigor@sysoev.ru static void
18212Sigor@sysoev.ru nxt_select_error_handler(nxt_task_t *task, void *obj, void *data)
18312Sigor@sysoev.ru {
18412Sigor@sysoev.ru     nxt_fd_event_t  *ev;
18512Sigor@sysoev.ru 
18612Sigor@sysoev.ru     ev = obj;
18712Sigor@sysoev.ru 
18812Sigor@sysoev.ru     ev->read = NXT_EVENT_INACTIVE;
18912Sigor@sysoev.ru     ev->write = NXT_EVENT_INACTIVE;
19012Sigor@sysoev.ru 
19112Sigor@sysoev.ru     ev->error_handler(task, ev, data);
19212Sigor@sysoev.ru }
19312Sigor@sysoev.ru 
19412Sigor@sysoev.ru 
19512Sigor@sysoev.ru static void
19612Sigor@sysoev.ru nxt_select_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
19712Sigor@sysoev.ru {
19812Sigor@sysoev.ru     nxt_fd_t  fd;
19912Sigor@sysoev.ru 
20012Sigor@sysoev.ru     fd = ev->fd;
20112Sigor@sysoev.ru 
20212Sigor@sysoev.ru     nxt_debug(ev->task, "select disable read: fd:%d", fd);
20312Sigor@sysoev.ru 
20412Sigor@sysoev.ru     if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) {
20512Sigor@sysoev.ru         return;
20612Sigor@sysoev.ru     }
20712Sigor@sysoev.ru 
20812Sigor@sysoev.ru     FD_CLR(fd, &engine->u.select.main_read_fd_set);
20912Sigor@sysoev.ru 
21012Sigor@sysoev.ru     ev->read = NXT_EVENT_INACTIVE;
21112Sigor@sysoev.ru 
21212Sigor@sysoev.ru     if (ev->write == NXT_EVENT_INACTIVE) {
21312Sigor@sysoev.ru         engine->u.select.events[fd] = NULL;
21412Sigor@sysoev.ru         engine->u.select.update_nfds = 1;
21512Sigor@sysoev.ru     }
21612Sigor@sysoev.ru }
21712Sigor@sysoev.ru 
21812Sigor@sysoev.ru 
21912Sigor@sysoev.ru static void
22012Sigor@sysoev.ru nxt_select_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
22112Sigor@sysoev.ru {
22212Sigor@sysoev.ru     nxt_fd_t  fd;
22312Sigor@sysoev.ru 
22412Sigor@sysoev.ru     fd = ev->fd;
22512Sigor@sysoev.ru 
22612Sigor@sysoev.ru     nxt_debug(ev->task, "select disable write: fd:%d", fd);
22712Sigor@sysoev.ru 
22812Sigor@sysoev.ru     if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) {
22912Sigor@sysoev.ru         return;
23012Sigor@sysoev.ru     }
23112Sigor@sysoev.ru 
23212Sigor@sysoev.ru     FD_CLR(fd, &engine->u.select.main_write_fd_set);
23312Sigor@sysoev.ru 
23412Sigor@sysoev.ru     ev->write = NXT_EVENT_INACTIVE;
23512Sigor@sysoev.ru 
23612Sigor@sysoev.ru     if (ev->read == NXT_EVENT_INACTIVE) {
23712Sigor@sysoev.ru         engine->u.select.events[fd] = NULL;
23812Sigor@sysoev.ru         engine->u.select.update_nfds = 1;
23912Sigor@sysoev.ru     }
24012Sigor@sysoev.ru }
24112Sigor@sysoev.ru 
24212Sigor@sysoev.ru 
24312Sigor@sysoev.ru static void
24412Sigor@sysoev.ru nxt_select_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
24512Sigor@sysoev.ru {
24612Sigor@sysoev.ru     if (ev->read != NXT_EVENT_INACTIVE) {
24712Sigor@sysoev.ru         nxt_select_disable_read(engine, ev);
24812Sigor@sysoev.ru     }
24912Sigor@sysoev.ru }
25012Sigor@sysoev.ru 
25112Sigor@sysoev.ru 
25212Sigor@sysoev.ru static void
25312Sigor@sysoev.ru nxt_select_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
25412Sigor@sysoev.ru {
25512Sigor@sysoev.ru     if (ev->write != NXT_EVENT_INACTIVE) {
25612Sigor@sysoev.ru         nxt_select_disable_write(engine, ev);
25712Sigor@sysoev.ru     }
25812Sigor@sysoev.ru }
25912Sigor@sysoev.ru 
26012Sigor@sysoev.ru 
26112Sigor@sysoev.ru static void
26212Sigor@sysoev.ru nxt_select_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
26312Sigor@sysoev.ru {
26412Sigor@sysoev.ru     nxt_select_enable_read(engine, ev);
26512Sigor@sysoev.ru 
26612Sigor@sysoev.ru     ev->read = NXT_EVENT_ONESHOT;
26712Sigor@sysoev.ru }
26812Sigor@sysoev.ru 
26912Sigor@sysoev.ru 
27012Sigor@sysoev.ru static void
27112Sigor@sysoev.ru nxt_select_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
27212Sigor@sysoev.ru {
27312Sigor@sysoev.ru     nxt_select_enable_write(engine, ev);
27412Sigor@sysoev.ru 
27512Sigor@sysoev.ru     ev->write = NXT_EVENT_ONESHOT;
27612Sigor@sysoev.ru }
27712Sigor@sysoev.ru 
27812Sigor@sysoev.ru 
27912Sigor@sysoev.ru static void
28012Sigor@sysoev.ru nxt_select_poll(nxt_event_engine_t *engine, nxt_msec_t timeout)
28112Sigor@sysoev.ru {
28212Sigor@sysoev.ru     int             nevents, nfds, found;
28312Sigor@sysoev.ru     nxt_err_t       err;
28412Sigor@sysoev.ru     nxt_int_t       i;
28512Sigor@sysoev.ru     nxt_uint_t      fd, level;
28612Sigor@sysoev.ru     nxt_fd_event_t  *ev;
28712Sigor@sysoev.ru     struct timeval  tv, *tp;
28812Sigor@sysoev.ru 
28912Sigor@sysoev.ru     if (timeout == NXT_INFINITE_MSEC) {
29012Sigor@sysoev.ru         tp = NULL;
29112Sigor@sysoev.ru 
29212Sigor@sysoev.ru     } else {
29312Sigor@sysoev.ru         tv.tv_sec = (long) (timeout / 1000);
29412Sigor@sysoev.ru         tv.tv_usec = (long) ((timeout % 1000) * 1000);
29512Sigor@sysoev.ru         tp = &tv;
29612Sigor@sysoev.ru     }
29712Sigor@sysoev.ru 
29812Sigor@sysoev.ru     if (engine->u.select.update_nfds) {
29912Sigor@sysoev.ru         for (i = engine->u.select.nfds; i >= 0; i--) {
30012Sigor@sysoev.ru             if (engine->u.select.events[i] != NULL) {
30112Sigor@sysoev.ru                 engine->u.select.nfds = i;
30212Sigor@sysoev.ru                 engine->u.select.update_nfds = 0;
30312Sigor@sysoev.ru                 break;
30412Sigor@sysoev.ru             }
30512Sigor@sysoev.ru         }
30612Sigor@sysoev.ru     }
30712Sigor@sysoev.ru 
30812Sigor@sysoev.ru     engine->u.select.work_read_fd_set = engine->u.select.main_read_fd_set;
30912Sigor@sysoev.ru     engine->u.select.work_write_fd_set = engine->u.select.main_write_fd_set;
31012Sigor@sysoev.ru 
31112Sigor@sysoev.ru     nfds = engine->u.select.nfds + 1;
31212Sigor@sysoev.ru 
31312Sigor@sysoev.ru     nxt_debug(&engine->task, "select() nfds:%d timeout:%M", nfds, timeout);
31412Sigor@sysoev.ru 
31512Sigor@sysoev.ru     nevents = select(nfds, &engine->u.select.work_read_fd_set,
31612Sigor@sysoev.ru                      &engine->u.select.work_write_fd_set, NULL, tp);
31712Sigor@sysoev.ru 
31812Sigor@sysoev.ru     err = (nevents == -1) ? nxt_errno : 0;
31912Sigor@sysoev.ru 
32012Sigor@sysoev.ru     nxt_thread_time_update(engine->task.thread);
32112Sigor@sysoev.ru 
32212Sigor@sysoev.ru     nxt_debug(&engine->task, "select(): %d", nevents);
32312Sigor@sysoev.ru 
32412Sigor@sysoev.ru     if (nevents == -1) {
32512Sigor@sysoev.ru         level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT;
32612Sigor@sysoev.ru         nxt_log(&engine->task, level, "select() failed %E", err);
32712Sigor@sysoev.ru         return;
32812Sigor@sysoev.ru     }
32912Sigor@sysoev.ru 
33012Sigor@sysoev.ru     for (fd = 0; fd < (nxt_uint_t) nfds && nevents != 0; fd++) {
33112Sigor@sysoev.ru 
33212Sigor@sysoev.ru         found = 0;
33312Sigor@sysoev.ru 
33412Sigor@sysoev.ru         if (FD_ISSET(fd, &engine->u.select.work_read_fd_set)) {
33512Sigor@sysoev.ru             ev = engine->u.select.events[fd];
33612Sigor@sysoev.ru 
33712Sigor@sysoev.ru             nxt_debug(ev->task, "select() fd:%ui read rd:%d wr:%d",
33812Sigor@sysoev.ru                       fd, ev->read, ev->write);
33912Sigor@sysoev.ru 
34012Sigor@sysoev.ru             ev->read_ready = 1;
34112Sigor@sysoev.ru 
34212Sigor@sysoev.ru             if (ev->read == NXT_EVENT_ONESHOT) {
34312Sigor@sysoev.ru                 nxt_select_disable_read(engine, ev);
34412Sigor@sysoev.ru             }
34512Sigor@sysoev.ru 
34612Sigor@sysoev.ru             nxt_work_queue_add(ev->read_work_queue, ev->read_handler,
34712Sigor@sysoev.ru                                ev->task, ev, ev->data);
34812Sigor@sysoev.ru             found = 1;
34912Sigor@sysoev.ru         }
35012Sigor@sysoev.ru 
35112Sigor@sysoev.ru         if (FD_ISSET(fd, &engine->u.select.work_write_fd_set)) {
35212Sigor@sysoev.ru             ev = engine->u.select.events[fd];
35312Sigor@sysoev.ru 
35412Sigor@sysoev.ru             nxt_debug(ev->task, "select() fd:%ui write rd:%d wr:%d",
35512Sigor@sysoev.ru                       fd, ev->read, ev->write);
35612Sigor@sysoev.ru 
35712Sigor@sysoev.ru             ev->write_ready = 1;
35812Sigor@sysoev.ru 
35912Sigor@sysoev.ru             if (ev->write == NXT_EVENT_ONESHOT) {
36012Sigor@sysoev.ru                 nxt_select_disable_write(engine, ev);
36112Sigor@sysoev.ru             }
36212Sigor@sysoev.ru 
36312Sigor@sysoev.ru             nxt_work_queue_add(ev->write_work_queue, ev->write_handler,
36412Sigor@sysoev.ru                                ev->task, ev, ev->data);
36512Sigor@sysoev.ru             found = 1;
36612Sigor@sysoev.ru         }
36712Sigor@sysoev.ru 
36812Sigor@sysoev.ru         nevents -= found;
36912Sigor@sysoev.ru     }
37012Sigor@sysoev.ru }
371