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