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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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