diff options
41 files changed, 4375 insertions, 4497 deletions
diff --git a/auto/sources b/auto/sources index 1cde9015..049ef1ef 100644 --- a/auto/sources +++ b/auto/sources @@ -55,10 +55,9 @@ NXT_LIB_DEPS=" \ src/nxt_service.h \ src/nxt_fiber.h \ src/nxt_log_moderation.h \ - src/nxt_event_set.h \ src/nxt_event_engine.h \ src/nxt_timer.h \ - src/nxt_event_fd.h \ + src/nxt_fd_event.h \ src/nxt_event_conn.h \ src/nxt_event_file.h \ src/nxt_job.h \ @@ -113,9 +112,9 @@ NXT_LIB_SRCS=" \ src/nxt_service.c \ src/nxt_fiber.c \ src/nxt_log_moderation.c \ - src/nxt_event_set.c \ src/nxt_event_engine.c \ src/nxt_timer.c \ + src/nxt_fd_event.c \ src/nxt_event_conn.c \ src/nxt_event_conn_connect.c \ src/nxt_event_conn_accept.c \ @@ -163,13 +162,13 @@ NXT_LIB_GNUTLS_SRCS="src/nxt_gnutls.c" NXT_LIB_CYASSL_SRCS="src/nxt_cyassl.c" NXT_LIB_POLARSSL_SRCS="src/nxt_polarssl.c" -NXT_LIB_EPOLL_SRCS="src/nxt_epoll.c" -NXT_LIB_KQUEUE_SRCS="src/nxt_kqueue.c" -NXT_LIB_EVENTPORT_SRCS="src/nxt_eventport.c" -NXT_LIB_DEVPOLL_SRCS="src/nxt_devpoll.c" -NXT_LIB_POLLSET_SRCS="src/nxt_pollset.c" -NXT_LIB_POLL_SRCS="src/nxt_poll.c" -NXT_LIB_SELECT_SRCS="src/nxt_select.c" +NXT_LIB_EPOLL_SRCS="src/nxt_epoll_engine.c" +NXT_LIB_KQUEUE_SRCS="src/nxt_kqueue_engine.c" +NXT_LIB_EVENTPORT_SRCS="src/nxt_eventport_engine.c" +NXT_LIB_DEVPOLL_SRCS="src/nxt_devpoll_engine.c" +NXT_LIB_POLLSET_SRCS="src/nxt_pollset_engine.c" +NXT_LIB_POLL_SRCS="src/nxt_poll_engine.c" +NXT_LIB_SELECT_SRCS="src/nxt_select_engine.c" NXT_LIB_LINUX_SENDFILE_SRCS="src/nxt_linux_sendfile.c" NXT_LIB_FREEBSD_SENDFILE_SRCS="src/nxt_freebsd_sendfile.c" diff --git a/src/nxt_application.c b/src/nxt_application.c index 5e76613b..64886cf9 100644 --- a/src/nxt_application.c +++ b/src/nxt_application.c @@ -516,7 +516,7 @@ nxt_app_conn_update(nxt_thread_t *thr, nxt_event_conn_t *c, nxt_log_t *log) c->task.log = &c->log; c->task.ident = c->log.ident; - c->io = thr->engine->event->io; + c->io = thr->engine->event.io; c->max_chunk = NXT_INT32_T_MAX; c->sendfile = NXT_CONN_SENDFILE_UNSET; @@ -831,10 +831,27 @@ nxt_app_delivery_ready(nxt_task_t *task, void *obj, void *data) } +static const nxt_event_conn_state_t nxt_app_delivery_close_state + nxt_aligned(64) = +{ + NXT_EVENT_NO_BUF_PROCESS, + NXT_EVENT_TIMER_NO_AUTORESET, + + nxt_app_close_request, + NULL, + NULL, + + NULL, + NULL, + 0, +}; + + static void nxt_app_delivery_completion(nxt_task_t *task, void *obj, void *data) { nxt_buf_t *b, *bn, *free; + nxt_event_conn_t *c; nxt_app_request_t *r; nxt_debug(task, "app delivery completion"); @@ -857,8 +874,10 @@ nxt_app_delivery_completion(nxt_task_t *task, void *obj, void *data) if (nxt_buf_is_last(b)) { r = (nxt_app_request_t *) b->parent; - nxt_work_queue_add(&task->thread->engine->final_work_queue, - nxt_app_close_request, task, r, NULL); + c = r->event_conn; + c->write_state = &nxt_app_delivery_close_state; + + nxt_event_conn_close(task->thread->engine, c); } } @@ -940,12 +959,11 @@ nxt_app_close_request(nxt_task_t *task, void *obj, void *data) nxt_event_conn_t *c; nxt_app_request_t *r; - r = obj; - c = r->event_conn; + c = obj; nxt_debug(task, "app close connection"); - nxt_event_conn_close(task, c); + r = c->socket.data; nxt_mem_pool_destroy(c->mem_pool); nxt_mem_pool_destroy(r->mem_pool); diff --git a/src/nxt_cycle.c b/src/nxt_cycle.c index 447f0b37..a39bb02a 100644 --- a/src/nxt_cycle.c +++ b/src/nxt_cycle.c @@ -297,8 +297,8 @@ nxt_cycle_systemd_listen_sockets(nxt_thread_t *thr, nxt_cycle_t *cycle) static nxt_int_t nxt_cycle_event_engines(nxt_thread_t *thr, nxt_cycle_t *cycle) { - nxt_event_engine_t *engine, **e, **engines; - const nxt_event_set_ops_t *event_set; + nxt_event_engine_t *engine, **e, **engines; + const nxt_event_interface_t *interface; cycle->engines = nxt_array_create(cycle->mem_pool, 1, sizeof(nxt_event_engine_t *)); @@ -318,14 +318,14 @@ nxt_cycle_event_engines(nxt_thread_t *thr, nxt_cycle_t *cycle) *e = engines[0]; } else { - event_set = nxt_service_get(cycle->services, "engine", NULL); + interface = nxt_service_get(cycle->services, "engine", NULL); - if (nxt_slow_path(event_set == NULL)) { + if (nxt_slow_path(interface == NULL)) { /* TODO: log */ return NXT_ERROR; } - engine = nxt_event_engine_create(thr, event_set, + engine = nxt_event_engine_create(thr, interface, nxt_master_process_signals, 0, 0); if (nxt_slow_path(engine == NULL)) { @@ -464,9 +464,9 @@ fail: static void nxt_cycle_initial_start(nxt_task_t *task, nxt_cycle_t *cycle) { - nxt_int_t ret; - nxt_thread_t *thr; - const nxt_event_set_ops_t *event_set; + nxt_int_t ret; + nxt_thread_t *thr; + const nxt_event_interface_t *interface; thr = task->thread; @@ -482,12 +482,12 @@ nxt_cycle_initial_start(nxt_task_t *task, nxt_cycle_t *cycle) * 1) inherited kqueue descriptor is invalid, * 2) the signal thread is not inherited. */ - event_set = nxt_service_get(cycle->services, "engine", cycle->engine); - if (event_set == NULL) { + interface = nxt_service_get(cycle->services, "engine", cycle->engine); + if (interface == NULL) { goto fail; } - ret = nxt_event_engine_change(thr, task, event_set, cycle->batch); + ret = nxt_event_engine_change(thr, task, interface, cycle->batch); if (ret != NXT_OK) { goto fail; } @@ -608,7 +608,7 @@ nxt_cycle_close_idle_connections(nxt_thread_t *thr, nxt_task_t *task) if (!c->socket.read_ready) { nxt_queue_remove(link); - nxt_event_conn_close(task, c); + nxt_event_conn_close(thr->engine, c); } } } @@ -635,7 +635,7 @@ nxt_cycle_exit(nxt_task_t *task, void *obj, void *data) nxt_cycle_pid_file_delete(cycle); } - if (!task->thread->engine->event->signal_support) { + if (!task->thread->engine->event.signal_support) { nxt_event_engine_signals_stop(task->thread->engine); } @@ -650,17 +650,17 @@ static nxt_int_t nxt_cycle_event_engine_change(nxt_thread_t *thr, nxt_task_t *task, nxt_cycle_t *cycle) { - const nxt_event_set_ops_t *event_set; + const nxt_event_interface_t *interface; if (thr->engine->batch == cycle->batch - && nxt_strcmp(thr->engine->event->name, cycle->engine) == 0) + && nxt_strcmp(thr->engine->event.name, cycle->engine) == 0) { return NXT_OK; } - event_set = nxt_service_get(cycle->services, "engine", cycle->engine); - if (event_set != NULL) { - return nxt_event_engine_change(thr, task, event_set, cycle->batch); + interface = nxt_service_get(cycle->services, "engine", cycle->engine); + if (interface != NULL) { + return nxt_event_engine_change(thr, task, interface, cycle->batch); } return NXT_ERROR; @@ -789,11 +789,11 @@ nxt_cycle_thread_pool_exit(nxt_task_t *task, void *obj, void *data) static nxt_int_t nxt_cycle_conf_init(nxt_thread_t *thr, nxt_cycle_t *cycle) { - nxt_int_t ret; - nxt_str_t *prefix; - nxt_file_t *file; - nxt_file_name_str_t file_name; - const nxt_event_set_ops_t *event_set; + nxt_int_t ret; + nxt_str_t *prefix; + nxt_file_t *file; + nxt_file_name_str_t file_name; + const nxt_event_interface_t *interface; cycle->daemon = 1; cycle->master_process = 1; @@ -815,12 +815,12 @@ nxt_cycle_conf_init(nxt_thread_t *thr, nxt_cycle_t *cycle) /* An engine's parameters. */ - event_set = nxt_service_get(cycle->services, "engine", cycle->engine); - if (event_set == NULL) { + interface = nxt_service_get(cycle->services, "engine", cycle->engine); + if (interface == NULL) { return NXT_ERROR; } - cycle->engine = event_set->name; + cycle->engine = interface->name; prefix = nxt_file_name_is_absolute(cycle->pid) ? NULL : cycle->prefix; diff --git a/src/nxt_devpoll.c b/src/nxt_devpoll.c deleted file mode 100644 index 8fbe8184..00000000 --- a/src/nxt_devpoll.c +++ /dev/null @@ -1,699 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -/* - * "/dev/poll" has been introduced in Solaris 7 (11/99), HP-UX 11.22 (named - * "eventport pseudo driver" internally, not to be confused with Solaris 10 - * event ports), IRIX 6.5.15, and Tru64 UNIX 5.1A. - * - * Although "/dev/poll" descriptor is a file descriptor, nevertheless - * it cannot be added to another poll set, Solaris poll(7d): - * - * The /dev/poll driver does not yet support polling. Polling on a - * /dev/poll file descriptor will result in POLLERR being returned - * in the revents field of pollfd structure. - */ - - -#define NXT_DEVPOLL_ADD 0 -#define NXT_DEVPOLL_UPDATE 1 -#define NXT_DEVPOLL_CHANGE 2 -#define NXT_DEVPOLL_DELETE 3 - - -static nxt_event_set_t *nxt_devpoll_create(nxt_event_signals_t *signals, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_devpoll_free(nxt_event_set_t *event_set); -static void nxt_devpoll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_devpoll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -#if (NXT_HPUX) -static void nxt_devpoll_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_devpoll_drop_changes(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -#endif -static void nxt_devpoll_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_block_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t op, nxt_uint_t events); -static nxt_int_t nxt_devpoll_commit_changes(nxt_thread_t *thr, - nxt_devpoll_event_set_t *ds); -static void nxt_devpoll_change_error(nxt_thread_t *thr, - nxt_devpoll_event_set_t *ds, nxt_event_fd_t *ev); -static void nxt_devpoll_remove(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds, - nxt_fd_t fd); -static nxt_int_t nxt_devpoll_write(nxt_thread_t *thr, int devpoll, - struct pollfd *pfd, size_t n); -static void nxt_devpoll_set_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout); - - -const nxt_event_set_ops_t nxt_devpoll_event_set = { - "devpoll", - nxt_devpoll_create, - nxt_devpoll_free, - nxt_devpoll_enable, - nxt_devpoll_disable, - nxt_devpoll_disable, -#if (NXT_HPUX) - nxt_devpoll_close, -#else - nxt_devpoll_disable, -#endif - nxt_devpoll_enable_read, - nxt_devpoll_enable_write, - nxt_devpoll_disable_read, - nxt_devpoll_disable_write, - nxt_devpoll_block_read, - nxt_devpoll_block_write, - nxt_devpoll_oneshot_read, - nxt_devpoll_oneshot_write, - nxt_devpoll_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_devpoll_set_poll, - - &nxt_unix_event_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_event_set_t * -nxt_devpoll_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - nxt_event_set_t *event_set; - nxt_devpoll_event_set_t *ds; - - event_set = nxt_zalloc(sizeof(nxt_devpoll_event_set_t)); - if (event_set == NULL) { - return NULL; - } - - ds = &event_set->devpoll; - - ds->devpoll = -1; - ds->mchanges = mchanges; - ds->mevents = mevents; - - ds->devpoll_changes = nxt_malloc(sizeof(nxt_devpoll_change_t) * mchanges); - if (ds->devpoll_changes == NULL) { - goto fail; - } - - /* - * NXT_DEVPOLL_CHANGE requires two struct pollfd's: - * for POLLREMOVE and subsequent POLLIN or POLLOUT. - */ - ds->changes = nxt_malloc(2 * sizeof(struct pollfd) * mchanges); - if (ds->changes == NULL) { - goto fail; - } - - ds->events = nxt_malloc(sizeof(struct pollfd) * mevents); - if (ds->events == NULL) { - goto fail; - } - - ds->devpoll = open("/dev/poll", O_RDWR); - if (ds->devpoll == -1) { - nxt_main_log_emerg("open(/dev/poll) failed %E", nxt_errno); - goto fail; - } - - nxt_main_log_debug("open(/dev/poll): %d", ds->devpoll); - - return event_set; - -fail: - - nxt_devpoll_free(event_set); - - return NULL; -} - - -static void -nxt_devpoll_free(nxt_event_set_t *event_set) -{ - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - nxt_main_log_debug("devpoll %d free", ds->devpoll); - - if (ds->devpoll != -1) { - if (close(ds->devpoll) != 0) { - nxt_main_log_emerg("devpoll close(%d) failed %E", - ds->devpoll, nxt_errno); - } - } - - nxt_free(ds->events); - nxt_free(ds->changes); - nxt_free(ds->devpoll_changes); - nxt_event_set_fd_hash_destroy(&ds->fd_hash); - nxt_free(ds); -} - - -static void -nxt_devpoll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_DEFAULT; - ev->write = NXT_EVENT_DEFAULT; - - nxt_devpoll_change(event_set, ev, NXT_DEVPOLL_ADD, POLLIN | POLLOUT); -} - - -/* - * Solaris does not automatically remove a closed file descriptor from - * a "/dev/poll" set: ioctl(DP_ISPOLLED) for the descriptor returns 1, - * significative of active descriptor. POLLREMOVE can remove already - * closed file descriptor, so the removal can be batched, Solaris poll(7d): - * - * When using the "/dev/poll" driver, you should remove a closed file - * descriptor from a monitored poll set. Failure to do so may result - * in a POLLNVAL revents being returned for the closed file descriptor. - * When a file descriptor is closed but not removed from the monitored - * set, and is reused in subsequent open of a different device, you - * will be polling the device associated with the reused file descriptor. - * In a multithreaded application, careful coordination among threads - * doing close and DP_POLL ioctl is recommended for consistent results. - * - * Besides Solaris and HP-UX allow to add invalid descriptors to an - * "/dev/poll" set, although the descriptors are not marked as polled, - * that is, ioctl(DP_ISPOLLED) returns 0. - */ - -static void -nxt_devpoll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_devpoll_change(event_set, ev, NXT_DEVPOLL_DELETE, POLLREMOVE); - } -} - - -#if (NXT_HPUX) - -/* - * HP-UX poll(7): - * - * When a polled file descriptor is closed, it is automatically - * deregistered. - */ - -static void -nxt_devpoll_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_devpoll_drop_changes(event_set, ev); -} - - -static void -nxt_devpoll_drop_changes(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_devpoll_change_t *dst, *src, *end; - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - dst = ds->devpoll_changes; - end = dst + ds->nchanges; - - for (src = dst; src < end; src++) { - - if (src->event == ev) { - continue; - } - - if (dst != src) { - *dst = *src; - } - - dst++; - } - - ds->nchanges -= end - dst; -} - -#endif - - -/* - * Solaris poll(7d): - * - * The fd field specifies the file descriptor being polled. The events - * field indicates the interested poll events on the file descriptor. - * If a pollfd array contains multiple pollfd entries with the same fd field, - * the "events" field in each pollfd entry is OR'ed. A special POLLREMOVE - * event in the events field of the pollfd structure removes the fd from - * the monitored set. The revents field is not used. - */ - -static void -nxt_devpoll_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - if (ev->read != NXT_EVENT_BLOCKED) { - - events = POLLIN; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_DEVPOLL_ADD; - - } else if (ev->write == NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_CHANGE; - - } else { - op = NXT_DEVPOLL_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_devpoll_change(event_set, ev, op, events); - } - - ev->read = NXT_EVENT_DEFAULT; -} - - -static void -nxt_devpoll_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - if (ev->write != NXT_EVENT_BLOCKED) { - - events = POLLOUT; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_DEVPOLL_ADD; - - } else if (ev->read == NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_CHANGE; - - } else { - op = NXT_DEVPOLL_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_devpoll_change(event_set, ev, op, events); - } - - ev->write = NXT_EVENT_DEFAULT; -} - - -static void -nxt_devpoll_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write <= NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_DEVPOLL_CHANGE; - events = POLLOUT; - } - - nxt_devpoll_change(event_set, ev, op, events); -} - - -static void -nxt_devpoll_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read <= NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_DEVPOLL_CHANGE; - events = POLLIN; - } - - nxt_devpoll_change(event_set, ev, op, events); -} - - -static void -nxt_devpoll_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_devpoll_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_devpoll_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_devpoll_enable_read(event_set, ev); - - ev->read = NXT_EVENT_ONESHOT; -} - - -static void -nxt_devpoll_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_devpoll_enable_write(event_set, ev); - - ev->write = NXT_EVENT_ONESHOT; -} - - -static void -nxt_devpoll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t op, nxt_uint_t events) -{ - nxt_devpoll_change_t *ch; - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - nxt_log_debug(ev->log, "devpoll %d change fd:%d op:%ui ev:%04Xi", - ds->devpoll, ev->fd, op, events); - - if (ds->nchanges >= ds->mchanges) { - (void) nxt_devpoll_commit_changes(nxt_thread(), ds); - } - - ch = &ds->devpoll_changes[ds->nchanges++]; - ch->op = op; - ch->fd = ev->fd; - ch->events = events; - ch->event = ev; -} - - -static nxt_int_t -nxt_devpoll_commit_changes(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds) -{ - size_t n; - nxt_int_t ret, retval; - struct pollfd *pfd; - nxt_devpoll_change_t *ch, *end; - - nxt_log_debug(thr->log, "devpoll %d changes:%ui", - ds->devpoll, ds->nchanges); - - retval = NXT_OK; - n = 0; - ch = ds->devpoll_changes; - end = ch + ds->nchanges; - - do { - nxt_log_debug(thr->log, "devpoll fd:%d op:%d ev:%04Xd", - ch->fd, ch->op, ch->events); - - if (ch->op == NXT_DEVPOLL_CHANGE) { - pfd = &ds->changes[n++]; - pfd->fd = ch->fd; - pfd->events = POLLREMOVE; - pfd->revents = 0; - } - - pfd = &ds->changes[n++]; - pfd->fd = ch->fd; - pfd->events = ch->events; - pfd->revents = 0; - - ch++; - - } while (ch < end); - - ch = ds->devpoll_changes; - end = ch + ds->nchanges; - - ret = nxt_devpoll_write(thr, ds->devpoll, ds->changes, n); - - if (nxt_slow_path(ret != NXT_OK)) { - do { - nxt_devpoll_change_error(thr, ds, ch->event); - ch++; - } while (ch < end); - - ds->nchanges = 0; - - return NXT_ERROR; - } - - do { - if (ch->op == NXT_DEVPOLL_ADD) { - ret = nxt_event_set_fd_hash_add(&ds->fd_hash, ch->fd, ch->event); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_devpoll_change_error(thr, ds, ch->event); - retval = NXT_ERROR; - } - - } else if (ch->op == NXT_DEVPOLL_DELETE) { - nxt_event_set_fd_hash_delete(&ds->fd_hash, ch->fd, 0); - } - - /* Nothing tp do for NXT_DEVPOLL_UPDATE and NXT_DEVPOLL_CHANGE. */ - - ch++; - - } while (ch < end); - - ds->nchanges = 0; - - return retval; -} - - -static void -nxt_devpoll_change_error(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds, - nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - ev->error_handler, ev, ev->data, ev->log); - - nxt_event_set_fd_hash_delete(&ds->fd_hash, ev->fd, 1); - - nxt_devpoll_remove(thr, ds, ev->fd); -} - - -static void -nxt_devpoll_remove(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds, nxt_fd_t fd) -{ - int n; - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = 0; - pfd.revents = 0; - - n = ioctl(ds->devpoll, DP_ISPOLLED, &pfd); - - nxt_log_debug(thr->log, "ioctl(%d, DP_ISPOLLED, %d): %d", - ds->devpoll, fd, n); - - if (n == 0) { - /* The file descriptor is not in the set. */ - return; - } - - if (n == -1) { - nxt_log_alert(thr->log, "ioctl(%d, DP_ISPOLLED, %d) failed %E", - ds->devpoll, fd, nxt_errno); - /* Fall through. */ - } - - /* n == 1: the file descriptor is in the set. */ - - nxt_log_debug(thr->log, "devpoll %d remove fd:%d", ds->devpoll, fd); - - pfd.fd = fd; - pfd.events = POLLREMOVE; - pfd.revents = 0; - - nxt_devpoll_write(thr, ds->devpoll, &pfd, 1); -} - - -static nxt_int_t -nxt_devpoll_write(nxt_thread_t *thr, int devpoll, struct pollfd *pfd, - size_t n) -{ - nxt_log_debug(thr->log, "devpoll write(%d) changes:%uz", devpoll, n); - - n *= sizeof(struct pollfd); - - if (nxt_slow_path(write(devpoll, pfd, n) == (ssize_t) n)) { - return NXT_OK; - } - - nxt_log_alert(thr->log, "devpoll write(%d) failed %E", - devpoll, nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_devpoll_set_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout) -{ - int nevents; - nxt_fd_t fd; - nxt_int_t i; - nxt_err_t err; - nxt_uint_t events, level; - struct dvpoll dvp; - struct pollfd *pfd; - nxt_event_fd_t *ev; - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - if (ds->nchanges != 0) { - if (nxt_devpoll_commit_changes(thr, ds) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - nxt_log_debug(thr->log, "ioctl(%d, DP_POLL) timeout:%M", - ds->devpoll, timeout); - - dvp.dp_fds = ds->events; - dvp.dp_nfds = ds->mevents; - dvp.dp_timeout = timeout; - - nevents = ioctl(ds->devpoll, DP_POLL, &dvp); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(thr); - - nxt_log_debug(thr->log, "ioctl(%d, DP_POLL): %d", ds->devpoll, nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log_error(level, thr->log, "ioctl(%d, DP_POLL) failed %E", - ds->devpoll, err); - return; - } - - for (i = 0; i < nevents; i++) { - - pfd = &ds->events[i]; - fd = pfd->fd; - events = pfd->revents; - - ev = nxt_event_set_fd_hash_get(&ds->fd_hash, fd); - - if (nxt_slow_path(ev == NULL)) { - nxt_log_alert(thr->log, "ioctl(%d, DP_POLL) returned invalid " - "fd:%d ev:%04Xd rev:%04uXi", - ds->devpoll, fd, pfd->events, events); - - nxt_devpoll_remove(thr, ds, fd); - continue; - } - - nxt_log_debug(ev->log, "devpoll: fd:%d ev:%04uXi rd:%d wr:%d", - fd, events, ev->read, ev->write); - - if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { - nxt_log_alert(ev->log, - "ioctl(%d, DP_POLL) error fd:%d ev:%04Xd rev:%04uXi", - ds->devpoll, fd, pfd->events, events); - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - ev->error_handler, ev, ev->data, ev->log); - continue; - } - - if (events & POLLIN) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - - if (ev->read == NXT_EVENT_ONESHOT) { - nxt_devpoll_disable_read(event_set, ev); - } - - nxt_thread_work_queue_add(thr, ev->read_work_queue, - ev->read_handler, - ev, ev->data, ev->log); - } - } - - if (events & POLLOUT) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - - if (ev->write == NXT_EVENT_ONESHOT) { - nxt_devpoll_disable_write(event_set, ev); - } - - nxt_thread_work_queue_add(thr, ev->write_work_queue, - ev->write_handler, - ev, ev->data, ev->log); - } - } - } -} diff --git a/src/nxt_devpoll_engine.c b/src/nxt_devpoll_engine.c new file mode 100644 index 00000000..37435661 --- /dev/null +++ b/src/nxt_devpoll_engine.c @@ -0,0 +1,665 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* + * "/dev/poll" has been introduced in Solaris 7 (11/99), HP-UX 11.22 (named + * "eventport pseudo driver" internally, not to be confused with Solaris 10 + * event ports), IRIX 6.5.15, and Tru64 UNIX 5.1A. + * + * Although "/dev/poll" descriptor is a file descriptor, nevertheless + * it cannot be added to another poll set, Solaris poll(7d): + * + * The /dev/poll driver does not yet support polling. Polling on a + * /dev/poll file descriptor will result in POLLERR being returned + * in the revents field of pollfd structure. + */ + + +#define NXT_DEVPOLL_ADD 0 +#define NXT_DEVPOLL_UPDATE 1 +#define NXT_DEVPOLL_CHANGE 2 +#define NXT_DEVPOLL_DELETE 3 + + +static nxt_int_t nxt_devpoll_create(nxt_event_engine_t *engine, + nxt_uint_t mchanges, nxt_uint_t mevents); +static void nxt_devpoll_free(nxt_event_engine_t *engine); +static void nxt_devpoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_devpoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static nxt_bool_t nxt_devpoll_close(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_enable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_enable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_disable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_disable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_block_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_block_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_oneshot_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_oneshot_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, + nxt_uint_t op, nxt_uint_t events); +static nxt_int_t nxt_devpoll_commit_changes(nxt_event_engine_t *engine); +static void nxt_devpoll_change_error(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_devpoll_remove(nxt_event_engine_t *engine, nxt_fd_t fd); +static nxt_int_t nxt_devpoll_write(nxt_event_engine_t *engine, + struct pollfd *pfd, size_t n); +static void nxt_devpoll_poll(nxt_event_engine_t *engine, + nxt_msec_t timeout); + + +const nxt_event_interface_t nxt_devpoll_engine = { + "devpoll", + nxt_devpoll_create, + nxt_devpoll_free, + nxt_devpoll_enable, + nxt_devpoll_disable, + nxt_devpoll_disable, + nxt_devpoll_close, + nxt_devpoll_enable_read, + nxt_devpoll_enable_write, + nxt_devpoll_disable_read, + nxt_devpoll_disable_write, + nxt_devpoll_block_read, + nxt_devpoll_block_write, + nxt_devpoll_oneshot_read, + nxt_devpoll_oneshot_write, + nxt_devpoll_enable_read, + NULL, + NULL, + NULL, + NULL, + nxt_devpoll_poll, + + &nxt_unix_event_conn_io, + + NXT_NO_FILE_EVENTS, + NXT_NO_SIGNAL_EVENTS, +}; + + +static nxt_int_t +nxt_devpoll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, + nxt_uint_t mevents) +{ + void *changes; + + engine->u.devpoll.fd = -1; + engine->u.devpoll.mchanges = mchanges; + engine->u.devpoll.mevents = mevents; + + changes = nxt_malloc(sizeof(nxt_devpoll_change_t) * mchanges); + if (changes == NULL) { + goto fail; + } + + engine->u.devpoll.changes = changes; + + /* + * NXT_DEVPOLL_CHANGE requires two struct pollfd's: + * for POLLREMOVE and subsequent POLLIN or POLLOUT. + */ + changes = nxt_malloc(2 * sizeof(struct pollfd) * mchanges); + if (changes == NULL) { + goto fail; + } + + engine->u.devpoll.write_changes = changes; + + engine->u.devpoll.events = nxt_malloc(sizeof(struct pollfd) * mevents); + if (engine->u.devpoll.events == NULL) { + goto fail; + } + + engine->u.devpoll.fd = open("/dev/poll", O_RDWR); + + if (engine->u.devpoll.fd == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, "open(\"/dev/poll\") failed %E", + nxt_errno); + goto fail; + } + + nxt_debug(&engine->task, "open(\"/dev/poll\"): %d", engine->u.devpoll.fd); + + return NXT_OK; + +fail: + + nxt_devpoll_free(engine); + + return NXT_ERROR; +} + + +static void +nxt_devpoll_free(nxt_event_engine_t *engine) +{ + nxt_fd_t fd; + + fd = engine->u.devpoll.fd; + + nxt_debug(&engine->task, "devpoll %d free", fd); + + if (fd != -1 &&close(fd) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "devpoll close(%d) failed %E", + fd, nxt_errno); + } + + nxt_free(engine->u.devpoll.events); + nxt_free(engine->u.devpoll.write_changes); + nxt_free(engine->u.devpoll.changes); + nxt_fd_event_hash_destroy(&engine->u.devpoll.fd_hash); + + nxt_memzero(&engine->u.devpoll, sizeof(nxt_devpoll_engine_t)); +} + + +static void +nxt_devpoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_ACTIVE; + ev->write = NXT_EVENT_ACTIVE; + + nxt_devpoll_change(engine, ev, NXT_DEVPOLL_ADD, POLLIN | POLLOUT); +} + + +static void +nxt_devpoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { + + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + nxt_devpoll_change(engine, ev, NXT_DEVPOLL_DELETE, POLLREMOVE); + } +} + + +/* + * Solaris does not automatically remove a closed file descriptor from + * a "/dev/poll" set: ioctl(DP_ISPOLLED) for the descriptor returns 1, + * significative of active descriptor. POLLREMOVE can remove already + * closed file descriptor, so the removal can be batched, Solaris poll(7d): + * + * When using the "/dev/poll" driver, you should remove a closed file + * descriptor from a monitored poll set. Failure to do so may result + * in a POLLNVAL revents being returned for the closed file descriptor. + * When a file descriptor is closed but not removed from the monitored + * set, and is reused in subsequent open of a different device, you + * will be polling the device associated with the reused file descriptor. + * In a multithreaded application, careful coordination among threads + * doing close and DP_POLL ioctl is recommended for consistent results. + * + * Besides Solaris and HP-UX allow to add invalid descriptors to an + * "/dev/poll" set, although the descriptors are not marked as polled, + * that is, ioctl(DP_ISPOLLED) returns 0. + * + * HP-UX poll(7): + * + * When a polled file descriptor is closed, it is automatically + * deregistered. + */ + +static nxt_bool_t +nxt_devpoll_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_devpoll_disable(engine, ev); + + return ev->changing; +} + + +/* + * Solaris poll(7d): + * + * The fd field specifies the file descriptor being polled. The events + * field indicates the interested poll events on the file descriptor. + * If a pollfd array contains multiple pollfd entries with the same fd field, + * the "events" field in each pollfd entry is OR'ed. A special POLLREMOVE + * event in the events field of the pollfd structure removes the fd from + * the monitored set. The revents field is not used. + */ + +static void +nxt_devpoll_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + if (ev->read != NXT_EVENT_BLOCKED) { + + events = POLLIN; + + if (ev->write == NXT_EVENT_INACTIVE) { + op = NXT_DEVPOLL_ADD; + + } else if (ev->write == NXT_EVENT_BLOCKED) { + ev->write = NXT_EVENT_INACTIVE; + op = NXT_DEVPOLL_CHANGE; + + } else { + op = NXT_DEVPOLL_UPDATE; + events = POLLIN | POLLOUT; + } + + nxt_devpoll_change(engine, ev, op, events); + } + + ev->read = NXT_EVENT_ACTIVE; +} + + +static void +nxt_devpoll_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + if (ev->write != NXT_EVENT_BLOCKED) { + + events = POLLOUT; + + if (ev->read == NXT_EVENT_INACTIVE) { + op = NXT_DEVPOLL_ADD; + + } else if (ev->read == NXT_EVENT_BLOCKED) { + ev->read = NXT_EVENT_INACTIVE; + op = NXT_DEVPOLL_CHANGE; + + } else { + op = NXT_DEVPOLL_UPDATE; + events = POLLIN | POLLOUT; + } + + nxt_devpoll_change(engine, ev, op, events); + } + + ev->write = NXT_EVENT_ACTIVE; +} + + +static void +nxt_devpoll_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->read = NXT_EVENT_INACTIVE; + + if (ev->write <= NXT_EVENT_BLOCKED) { + ev->write = NXT_EVENT_INACTIVE; + op = NXT_DEVPOLL_DELETE; + events = POLLREMOVE; + + } else { + op = NXT_DEVPOLL_CHANGE; + events = POLLOUT; + } + + nxt_devpoll_change(engine, ev, op, events); +} + + +static void +nxt_devpoll_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->write = NXT_EVENT_INACTIVE; + + if (ev->read <= NXT_EVENT_BLOCKED) { + ev->read = NXT_EVENT_INACTIVE; + op = NXT_DEVPOLL_DELETE; + events = POLLREMOVE; + + } else { + op = NXT_DEVPOLL_CHANGE; + events = POLLIN; + } + + nxt_devpoll_change(engine, ev, op, events); +} + + +static void +nxt_devpoll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE) { + ev->read = NXT_EVENT_BLOCKED; + } +} + + +static void +nxt_devpoll_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->write != NXT_EVENT_INACTIVE) { + ev->write = NXT_EVENT_BLOCKED; + } +} + + +static void +nxt_devpoll_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_devpoll_enable_read(engine, ev); + + ev->read = NXT_EVENT_ONESHOT; +} + + +static void +nxt_devpoll_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_devpoll_enable_write(engine, ev); + + ev->write = NXT_EVENT_ONESHOT; +} + + +static void +nxt_devpoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, + nxt_uint_t op, nxt_uint_t events) +{ + nxt_devpoll_change_t *change; + + nxt_debug(ev->task, "devpoll %d change fd:%d op:%ui ev:%04Xi", + engine->u.devpoll.fd, ev->fd, op, events); + + if (engine->u.devpoll.nchanges >= engine->u.devpoll.mchanges) { + (void) nxt_devpoll_commit_changes(engine); + } + + ev->changing = 1; + + change = &engine->u.devpoll.changes[engine->u.devpoll.nchanges++]; + change->op = op; + change->events = events; + change->event = ev; +} + + +static nxt_int_t +nxt_devpoll_commit_changes(nxt_event_engine_t *engine) +{ + size_t n; + nxt_int_t ret, retval; + struct pollfd *pfd, *write_changes; + nxt_fd_event_t *ev; + nxt_devpoll_change_t *change, *end; + + nxt_debug(&engine->task, "devpoll %d changes:%ui", + engine->u.devpoll.fd, engine->u.devpoll.nchanges); + + retval = NXT_OK; + n = 0; + write_changes = engine->u.devpoll.write_changes; + change = engine->u.devpoll.changes; + end = change + engine->u.devpoll.nchanges; + + do { + ev = change->event; + + nxt_debug(&engine->task, "devpoll fd:%d op:%d ev:%04Xd", + ev->fd, change->op, change->events); + + if (change->op == NXT_DEVPOLL_CHANGE) { + pfd = &write_changes[n++]; + pfd->fd = ev->fd; + pfd->events = POLLREMOVE; + pfd->revents = 0; + } + + pfd = &write_changes[n++]; + pfd->fd = ev->fd; + pfd->events = change->events; + pfd->revents = 0; + + ev->changing = 0; + + change++; + + } while (change < end); + + change = engine->u.devpoll.changes; + end = change + engine->u.devpoll.nchanges; + + ret = nxt_devpoll_write(engine, write_changes, n); + + if (nxt_slow_path(ret != NXT_OK)) { + + do { + nxt_devpoll_change_error(engine, change->event); + change++; + } while (change < end); + + engine->u.devpoll.nchanges = 0; + + return NXT_ERROR; + } + + do { + ev = change->event; + + if (change->op == NXT_DEVPOLL_ADD) { + ret = nxt_fd_event_hash_add(&engine->u.devpoll.fd_hash, ev->fd, ev); + + if (nxt_slow_path(ret != NXT_OK)) { + nxt_devpoll_change_error(engine, ev); + retval = NXT_ERROR; + } + + } else if (change->op == NXT_DEVPOLL_DELETE) { + nxt_fd_event_hash_delete(&engine->task, &engine->u.devpoll.fd_hash, + ev->fd, 0); + } + + /* Nothing tp do for NXT_DEVPOLL_UPDATE and NXT_DEVPOLL_CHANGE. */ + + change++; + + } while (change < end); + + engine->u.devpoll.nchanges = 0; + + return retval; +} + + +static void +nxt_devpoll_change_error(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, + ev->task, ev, ev->data); + + nxt_fd_event_hash_delete(ev->task, &engine->u.devpoll.fd_hash, ev->fd, 1); + + nxt_devpoll_remove(engine, ev->fd); +} + + +static void +nxt_devpoll_remove(nxt_event_engine_t *engine, nxt_fd_t fd) +{ + int n; + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = 0; + pfd.revents = 0; + + n = ioctl(engine->u.devpoll.fd, DP_ISPOLLED, &pfd); + + nxt_debug(&engine->task, "ioctl(%d, DP_ISPOLLED, %d): %d", + engine->u.devpoll.fd, fd, n); + + if (n == 0) { + /* The file descriptor is not in the set. */ + return; + } + + if (n == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, + "ioctl(%d, DP_ISPOLLED, %d) failed %E", + engine->u.devpoll.fd, fd, nxt_errno); + /* Fall through. */ + } + + /* n == 1: the file descriptor is in the set. */ + + nxt_debug(&engine->task, "devpoll %d remove fd:%d", + engine->u.devpoll.fd, fd); + + pfd.fd = fd; + pfd.events = POLLREMOVE; + pfd.revents = 0; + + nxt_devpoll_write(engine, &pfd, 1); +} + + +static nxt_int_t +nxt_devpoll_write(nxt_event_engine_t *engine, struct pollfd *pfd, size_t n) +{ + int fd; + + fd = engine->u.devpoll.fd; + + nxt_debug(&engine->task, "devpoll write(%d) changes:%uz", fd, n); + + n *= sizeof(struct pollfd); + + if (nxt_slow_path(write(fd, pfd, n) == (ssize_t) n)) { + return NXT_OK; + } + + nxt_log(&engine->task, NXT_LOG_CRIT, "devpoll write(%d) failed %E", + fd, nxt_errno); + + return NXT_ERROR; +} + + +static void +nxt_devpoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) +{ + int nevents; + nxt_fd_t fd; + nxt_int_t i; + nxt_err_t err; + nxt_uint_t events, level; + struct dvpoll dvp; + struct pollfd *pfd; + nxt_fd_event_t *ev; + + if (engine->u.devpoll.nchanges != 0) { + if (nxt_devpoll_commit_changes(engine) != NXT_OK) { + /* Error handlers have been enqueued on failure. */ + timeout = 0; + } + } + + nxt_debug(&engine->task, "ioctl(%d, DP_POLL) timeout:%M", + engine->u.devpoll.fd, timeout); + + dvp.dp_fds = engine->u.devpoll.events; + dvp.dp_nfds = engine->u.devpoll.mevents; + dvp.dp_timeout = timeout; + + nevents = ioctl(engine->u.devpoll.fd, DP_POLL, &dvp); + + err = (nevents == -1) ? nxt_errno : 0; + + nxt_thread_time_update(engine->task.thread); + + nxt_debug(&engine->task, "ioctl(%d, DP_POLL): %d", + engine->u.devpoll.fd, nevents); + + if (nevents == -1) { + level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT; + + nxt_log(&engine->task, level, "ioctl(%d, DP_POLL) failed %E", + engine->u.devpoll.fd, err); + + return; + } + + for (i = 0; i < nevents; i++) { + + pfd = &engine->u.devpoll.events[i]; + fd = pfd->fd; + events = pfd->revents; + + ev = nxt_fd_event_hash_get(&engine->task, &engine->u.devpoll.fd_hash, + fd); + + if (nxt_slow_path(ev == NULL)) { + nxt_log(&engine->task, NXT_LOG_CRIT, + "ioctl(%d, DP_POLL) returned invalid " + "fd:%d ev:%04Xd rev:%04uXi", + engine->u.devpoll.fd, fd, pfd->events, events); + + nxt_devpoll_remove(engine, fd); + continue; + } + + nxt_debug(ev->task, "devpoll: fd:%d ev:%04uXi rd:%d wr:%d", + fd, events, ev->read, ev->write); + + if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { + nxt_log(ev->task, NXT_LOG_CRIT, + "ioctl(%d, DP_POLL) error fd:%d ev:%04Xd rev:%04uXi", + engine->u.devpoll.fd, fd, pfd->events, events); + + nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, + ev->task, ev, ev->data); + continue; + } + + if (events & POLLIN) { + ev->read_ready = 1; + + if (ev->read != NXT_EVENT_BLOCKED) { + nxt_work_queue_add(ev->read_work_queue, ev->read_handler, + ev->task, ev, ev->data); + } + + if (ev->read == NXT_EVENT_BLOCKED + || ev->read == NXT_EVENT_ONESHOT) + { + nxt_devpoll_disable_read(engine, ev); + } + } + + if (events & POLLOUT) { + ev->write_ready = 1; + + if (ev->write != NXT_EVENT_BLOCKED) { + nxt_work_queue_add(ev->write_work_queue, ev->write_handler, + ev->task, ev, ev->data); + } + + if (ev->write == NXT_EVENT_BLOCKED + || ev->write == NXT_EVENT_ONESHOT) + { + nxt_devpoll_disable_write(engine, ev); + } + } + } +} diff --git a/src/nxt_epoll.c b/src/nxt_epoll_engine.c index 42973e12..19e0389b 100644 --- a/src/nxt_epoll.c +++ b/src/nxt_epoll_engine.c @@ -27,63 +27,60 @@ * eventfd2() Linux 2.6.27, glibc 2.9. * accept4() Linux 2.6.28, glibc 2.10. * eventfd2(EFD_SEMAPHORE) Linux 2.6.30, glibc 2.10. + * EPOLLEXCLUSIVE Linux 4.5. */ #if (NXT_HAVE_EPOLL_EDGE) -static nxt_event_set_t *nxt_epoll_edge_create(nxt_event_signals_t *signals, +static nxt_int_t nxt_epoll_edge_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents); #endif -static nxt_event_set_t *nxt_epoll_level_create(nxt_event_signals_t *signals, +static nxt_int_t nxt_epoll_level_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents); -static nxt_event_set_t *nxt_epoll_create(nxt_event_signals_t *signals, +static nxt_int_t nxt_epoll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents, nxt_event_conn_io_t *io, uint32_t mode); -static void nxt_epoll_test_accept4(nxt_event_conn_io_t *io); -static void nxt_epoll_free(nxt_event_set_t *event_set); -static void nxt_epoll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_epoll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_epoll_delete(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_epoll_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_epoll_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_block_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_enable_accept(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_epoll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, +static void nxt_epoll_test_accept4(nxt_event_engine_t *engine, + nxt_event_conn_io_t *io); +static void nxt_epoll_free(nxt_event_engine_t *engine); +static void nxt_epoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_epoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_epoll_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static nxt_bool_t nxt_epoll_close(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_enable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_enable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_disable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_disable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_block_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_block_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_oneshot_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_oneshot_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_enable_accept(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_epoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, int op, uint32_t events); -static nxt_int_t nxt_epoll_commit_changes(nxt_task_t *task, - nxt_epoll_event_set_t *es); -static void nxt_epoll_error_handler(nxt_task_t *task, void *obj, - void *data); +static nxt_int_t nxt_epoll_commit_changes(nxt_event_engine_t *engine); +static void nxt_epoll_error_handler(nxt_task_t *task, void *obj, void *data); #if (NXT_HAVE_SIGNALFD) -static nxt_int_t nxt_epoll_add_signal(nxt_epoll_event_set_t *es, - nxt_event_signals_t *signals); -static void nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, - void *data); +static nxt_int_t nxt_epoll_add_signal(nxt_event_engine_t *engine); +static void nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, void *data); #endif #if (NXT_HAVE_EVENTFD) -static nxt_int_t nxt_epoll_enable_post(nxt_event_set_t *event_set, +static nxt_int_t nxt_epoll_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler); -static void nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, - void *data); -static void nxt_epoll_signal(nxt_event_set_t *event_set, nxt_uint_t signo); +static void nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, void *data); +static void nxt_epoll_signal(nxt_event_engine_t *engine, nxt_uint_t signo); #endif -static void nxt_epoll_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout); +static void nxt_epoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); #if (NXT_HAVE_ACCEPT4) static void nxt_epoll_event_conn_io_accept4(nxt_task_t *task, void *obj, @@ -125,7 +122,7 @@ static nxt_event_conn_io_t nxt_epoll_edge_event_conn_io = { }; -const nxt_event_set_ops_t nxt_epoll_edge_event_set = { +const nxt_event_interface_t nxt_epoll_edge_engine = { "epoll_edge", nxt_epoll_edge_create, nxt_epoll_free, @@ -171,7 +168,7 @@ const nxt_event_set_ops_t nxt_epoll_edge_event_set = { #endif -const nxt_event_set_ops_t nxt_epoll_level_event_set = { +const nxt_event_interface_t nxt_epoll_level_engine = { "epoll_level", nxt_epoll_level_create, nxt_epoll_free, @@ -217,11 +214,11 @@ const nxt_event_set_ops_t nxt_epoll_level_event_set = { #if (NXT_HAVE_EPOLL_EDGE) -static nxt_event_set_t * -nxt_epoll_edge_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, +static nxt_int_t +nxt_epoll_edge_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents) { - return nxt_epoll_create(signals, mchanges, mevents, + return nxt_epoll_create(engine, mchanges, mevents, &nxt_epoll_edge_event_conn_io, EPOLLET | EPOLLRDHUP); } @@ -229,79 +226,71 @@ nxt_epoll_edge_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, #endif -static nxt_event_set_t * -nxt_epoll_level_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, +static nxt_int_t +nxt_epoll_level_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents) { - return nxt_epoll_create(signals, mchanges, mevents, + return nxt_epoll_create(engine, mchanges, mevents, &nxt_unix_event_conn_io, 0); } -static nxt_event_set_t * -nxt_epoll_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, +static nxt_int_t +nxt_epoll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents, nxt_event_conn_io_t *io, uint32_t mode) { - nxt_event_set_t *event_set; - nxt_epoll_event_set_t *es; - - event_set = nxt_zalloc(sizeof(nxt_epoll_event_set_t)); - if (event_set == NULL) { - return NULL; - } - - es = &event_set->epoll; - - es->epoll = -1; - es->mode = mode; - es->mchanges = mchanges; - es->mevents = mevents; + engine->u.epoll.fd = -1; + engine->u.epoll.mode = mode; + engine->u.epoll.mchanges = mchanges; + engine->u.epoll.mevents = mevents; #if (NXT_HAVE_SIGNALFD) - es->signalfd.fd = -1; + engine->u.epoll.signalfd.fd = -1; #endif - es->changes = nxt_malloc(sizeof(nxt_epoll_change_t) * mchanges); - if (es->changes == NULL) { + engine->u.epoll.changes = nxt_malloc(sizeof(nxt_epoll_change_t) * mchanges); + if (engine->u.epoll.changes == NULL) { goto fail; } - es->events = nxt_malloc(sizeof(struct epoll_event) * mevents); - if (es->events == NULL) { + engine->u.epoll.events = nxt_malloc(sizeof(struct epoll_event) * mevents); + if (engine->u.epoll.events == NULL) { goto fail; } - es->epoll = epoll_create(1); - if (es->epoll == -1) { - nxt_main_log_emerg("epoll_create() failed %E", nxt_errno); + engine->u.epoll.fd = epoll_create(1); + if (engine->u.epoll.fd == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, "epoll_create() failed %E", + nxt_errno); goto fail; } - nxt_main_log_debug("epoll_create(): %d", es->epoll); + nxt_debug(&engine->task, "epoll_create(): %d", engine->u.epoll.fd); + + if (engine->signals != NULL) { #if (NXT_HAVE_SIGNALFD) - if (signals != NULL) { - if (nxt_epoll_add_signal(es, signals) != NXT_OK) { + if (nxt_epoll_add_signal(engine) != NXT_OK) { goto fail; } - } #endif - nxt_epoll_test_accept4(io); + nxt_epoll_test_accept4(engine, io); + } - return event_set; + return NXT_OK; fail: - nxt_epoll_free(event_set); + nxt_epoll_free(engine); - return NULL; + return NXT_ERROR; } static void -nxt_epoll_test_accept4(nxt_event_conn_io_t *io) +nxt_epoll_test_accept4(nxt_event_engine_t *engine, nxt_event_conn_io_t *io) { static nxt_work_handler_t handler; @@ -317,8 +306,8 @@ nxt_epoll_test_accept4(nxt_event_conn_io_t *io) handler = nxt_epoll_event_conn_io_accept4; } else { - nxt_main_log_error(NXT_LOG_NOTICE, "accept4() failed %E", - NXT_ENOSYS); + nxt_log(&engine->task, NXT_LOG_INFO, "accept4() failed %E", + NXT_ENOSYS); } #endif @@ -329,81 +318,80 @@ nxt_epoll_test_accept4(nxt_event_conn_io_t *io) static void -nxt_epoll_free(nxt_event_set_t *event_set) +nxt_epoll_free(nxt_event_engine_t *engine) { - nxt_epoll_event_set_t *es; + int fd; - es = &event_set->epoll; - - nxt_main_log_debug("epoll %d free", es->epoll); + nxt_debug(&engine->task, "epoll %d free", engine->u.epoll.fd); #if (NXT_HAVE_SIGNALFD) - if (es->signalfd.fd != -1) { - if (close(es->signalfd.fd) != 0) { - nxt_main_log_emerg("signalfd close(%d) failed %E", - es->signalfd.fd, nxt_errno); - } + fd = engine->u.epoll.signalfd.fd; + + if (fd != -1 && close(fd) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "signalfd close(%d) failed %E", + fd, nxt_errno); } #endif #if (NXT_HAVE_EVENTFD) - if (es->eventfd.fd != -1) { - if (close(es->eventfd.fd) != 0) { - nxt_main_log_emerg("eventfd close(%d) failed %E", - es->eventfd.fd, nxt_errno); - } + fd = engine->u.epoll.eventfd.fd; + + if (fd != -1 && close(fd) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "eventfd close(%d) failed %E", + fd, nxt_errno); } #endif - if (es->epoll != -1) { - if (close(es->epoll) != 0) { - nxt_main_log_emerg("epoll close(%d) failed %E", - es->epoll, nxt_errno); - } + fd = engine->u.epoll.fd; + + if (fd != -1 && close(fd) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "epoll close(%d) failed %E", + fd, nxt_errno); } - nxt_free(es->events); - nxt_free(es); + nxt_free(engine->u.epoll.events); + + nxt_memzero(&engine->u.epoll, sizeof(nxt_epoll_engine_t)); } static void -nxt_epoll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { - ev->read = NXT_EVENT_DEFAULT; - ev->write = NXT_EVENT_DEFAULT; + ev->read = NXT_EVENT_ACTIVE; + ev->write = NXT_EVENT_ACTIVE; - nxt_epoll_change(event_set, ev, EPOLL_CTL_ADD, - EPOLLIN | EPOLLOUT | event_set->epoll.mode); + nxt_epoll_change(engine, ev, EPOLL_CTL_ADD, + EPOLLIN | EPOLLOUT | engine->u.epoll.mode); } static void -nxt_epoll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->read > NXT_EVENT_DISABLED || ev->write > NXT_EVENT_DISABLED) { ev->read = NXT_EVENT_INACTIVE; ev->write = NXT_EVENT_INACTIVE; - nxt_epoll_change(event_set, ev, EPOLL_CTL_DEL, 0); + nxt_epoll_change(engine, ev, EPOLL_CTL_DEL, 0); } } static void -nxt_epoll_delete(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { ev->read = NXT_EVENT_INACTIVE; ev->write = NXT_EVENT_INACTIVE; - nxt_epoll_change(event_set, ev, EPOLL_CTL_DEL, 0); + nxt_epoll_change(engine, ev, EPOLL_CTL_DEL, 0); } } @@ -417,23 +405,17 @@ nxt_epoll_delete(nxt_event_set_t *event_set, nxt_event_fd_t *ev) * eliminates possible lock contention. */ -static void -nxt_epoll_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +static nxt_bool_t +nxt_epoll_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { - nxt_epoll_event_set_t *es; + nxt_epoll_delete(engine, ev); - nxt_epoll_delete(event_set, ev); - - es = &event_set->epoll; - - if (es->nchanges != 0) { - (void) nxt_epoll_commit_changes(ev->task, &event_set->epoll); - } + return ev->changing; } static void -nxt_epoll_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { int op; uint32_t events; @@ -441,7 +423,7 @@ nxt_epoll_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) if (ev->read != NXT_EVENT_BLOCKED) { op = EPOLL_CTL_MOD; - events = EPOLLIN | event_set->epoll.mode; + events = EPOLLIN | engine->u.epoll.mode; if (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) { op = EPOLL_CTL_ADD; @@ -450,15 +432,15 @@ nxt_epoll_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) events |= EPOLLOUT; } - nxt_epoll_change(event_set, ev, op, events); + nxt_epoll_change(engine, ev, op, events); } - ev->read = NXT_EVENT_DEFAULT; + ev->read = NXT_EVENT_ACTIVE; } static void -nxt_epoll_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { int op; uint32_t events; @@ -466,7 +448,7 @@ nxt_epoll_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) if (ev->write != NXT_EVENT_BLOCKED) { op = EPOLL_CTL_MOD; - events = EPOLLOUT | event_set->epoll.mode; + events = EPOLLOUT | engine->u.epoll.mode; if (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) { op = EPOLL_CTL_ADD; @@ -475,15 +457,15 @@ nxt_epoll_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) events |= EPOLLIN; } - nxt_epoll_change(event_set, ev, op, events); + nxt_epoll_change(engine, ev, op, events); } - ev->write = NXT_EVENT_DEFAULT; + ev->write = NXT_EVENT_ACTIVE; } static void -nxt_epoll_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { int op; uint32_t events; @@ -497,15 +479,15 @@ nxt_epoll_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) } else { op = EPOLL_CTL_MOD; - events = EPOLLOUT | event_set->epoll.mode; + events = EPOLLOUT | engine->u.epoll.mode; } - nxt_epoll_change(event_set, ev, op, events); + nxt_epoll_change(engine, ev, op, events); } static void -nxt_epoll_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { int op; uint32_t events; @@ -519,15 +501,15 @@ nxt_epoll_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) } else { op = EPOLL_CTL_MOD; - events = EPOLLIN | event_set->epoll.mode; + events = EPOLLIN | engine->u.epoll.mode; } - nxt_epoll_change(event_set, ev, op, events); + nxt_epoll_change(engine, ev, op, events); } static void -nxt_epoll_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->read != NXT_EVENT_INACTIVE) { ev->read = NXT_EVENT_BLOCKED; @@ -536,7 +518,7 @@ nxt_epoll_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) static void -nxt_epoll_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->write != NXT_EVENT_INACTIVE) { ev->write = NXT_EVENT_BLOCKED; @@ -558,7 +540,7 @@ nxt_epoll_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) */ static void -nxt_epoll_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { int op; @@ -568,12 +550,12 @@ nxt_epoll_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) ev->read = NXT_EVENT_ONESHOT; ev->write = NXT_EVENT_INACTIVE; - nxt_epoll_change(event_set, ev, op, EPOLLIN | EPOLLONESHOT); + nxt_epoll_change(engine, ev, op, EPOLLIN | EPOLLONESHOT); } static void -nxt_epoll_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { int op; @@ -583,16 +565,16 @@ nxt_epoll_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) ev->read = NXT_EVENT_INACTIVE; ev->write = NXT_EVENT_ONESHOT; - nxt_epoll_change(event_set, ev, op, EPOLLOUT | EPOLLONESHOT); + nxt_epoll_change(engine, ev, op, EPOLLOUT | EPOLLONESHOT); } static void -nxt_epoll_enable_accept(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_epoll_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { - ev->read = NXT_EVENT_DEFAULT; + ev->read = NXT_EVENT_ACTIVE; - nxt_epoll_change(event_set, ev, EPOLL_CTL_ADD, EPOLLIN); + nxt_epoll_change(engine, ev, EPOLL_CTL_ADD, EPOLLIN); } @@ -602,73 +584,76 @@ nxt_epoll_enable_accept(nxt_event_set_t *event_set, nxt_event_fd_t *ev) */ static void -nxt_epoll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, int op, +nxt_epoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, int op, uint32_t events) { - nxt_epoll_change_t *ch; - nxt_epoll_event_set_t *es; + nxt_epoll_change_t *change; - es = &event_set->epoll; + nxt_debug(ev->task, "epoll %d set event: fd:%d op:%d ev:%XD", + engine->u.epoll.fd, ev->fd, op, events); - nxt_log_debug(ev->log, "epoll %d set event: fd:%d op:%d ev:%XD", - es->epoll, ev->fd, op, events); - - if (es->nchanges >= es->mchanges) { - (void) nxt_epoll_commit_changes(ev->task, es); + if (engine->u.epoll.nchanges >= engine->u.epoll.mchanges) { + (void) nxt_epoll_commit_changes(engine); } - ch = &es->changes[es->nchanges++]; - ch->op = op; - ch->fd = ev->fd; - ch->event.events = events; - ch->event.data.ptr = ev; + ev->changing = 1; + + change = &engine->u.epoll.changes[engine->u.epoll.nchanges++]; + change->op = op; + change->event.events = events; + change->event.data.ptr = ev; } static nxt_int_t -nxt_epoll_commit_changes(nxt_task_t *task, nxt_epoll_event_set_t *es) +nxt_epoll_commit_changes(nxt_event_engine_t *engine) { - nxt_int_t ret; - nxt_event_fd_t *ev; - nxt_epoll_change_t *ch, *end; + int ret; + nxt_int_t retval; + nxt_fd_event_t *ev; + nxt_epoll_change_t *change, *end; - nxt_debug(task, "epoll %d changes:%ui", es->epoll, es->nchanges); + nxt_debug(&engine->task, "epoll %d changes:%ui", + engine->u.epoll.fd, engine->u.epoll.nchanges); - ret = NXT_OK; - ch = es->changes; - end = ch + es->nchanges; + retval = NXT_OK; + change = engine->u.epoll.changes; + end = change + engine->u.epoll.nchanges; do { - ev = ch->event.data.ptr; + ev = change->event.data.ptr; + ev->changing = 0; nxt_debug(ev->task, "epoll_ctl(%d): fd:%d op:%d ev:%XD", - es->epoll, ch->fd, ch->op, ch->event.events); + engine->u.epoll.fd, ev->fd, change->op, + change->event.events); - if (epoll_ctl(es->epoll, ch->op, ch->fd, &ch->event) != 0) { + ret = epoll_ctl(engine->u.epoll.fd, change->op, ev->fd, &change->event); + + if (nxt_slow_path(ret != 0)) { nxt_log(ev->task, NXT_LOG_CRIT, "epoll_ctl(%d, %d, %d) failed %E", - es->epoll, ch->op, ch->fd, nxt_errno); + engine->u.epoll.fd, change->op, ev->fd, nxt_errno); - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_epoll_error_handler, - ev->task, ev, ev->data); + nxt_work_queue_add(&engine->fast_work_queue, + nxt_epoll_error_handler, ev->task, ev, ev->data); - ret = NXT_ERROR; + retval = NXT_ERROR; } - ch++; + change++; - } while (ch < end); + } while (change < end); - es->nchanges = 0; + engine->u.epoll.nchanges = 0; - return ret; + return retval; } static void nxt_epoll_error_handler(nxt_task_t *task, void *obj, void *data) { - nxt_event_fd_t *ev; + nxt_fd_event_t *ev; ev = obj; @@ -682,14 +667,14 @@ nxt_epoll_error_handler(nxt_task_t *task, void *obj, void *data) #if (NXT_HAVE_SIGNALFD) static nxt_int_t -nxt_epoll_add_signal(nxt_epoll_event_set_t *es, nxt_event_signals_t *signals) +nxt_epoll_add_signal(nxt_event_engine_t *engine) { int fd; - nxt_thread_t *thr; struct epoll_event ee; - if (sigprocmask(SIG_BLOCK, &signals->sigmask, NULL) != 0) { - nxt_main_log_alert("sigprocmask(SIG_BLOCK) failed %E", nxt_errno); + if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, + "sigprocmask(SIG_BLOCK) failed %E", nxt_errno); return NXT_ERROR; } @@ -702,36 +687,34 @@ nxt_epoll_add_signal(nxt_epoll_event_set_t *es, nxt_event_signals_t *signals) * is set separately. */ - fd = signalfd(-1, &signals->sigmask, 0); + fd = signalfd(-1, &engine->signals->sigmask, 0); if (fd == -1) { - nxt_main_log_emerg("signalfd(%d) failed %E", - es->signalfd.fd, nxt_errno); + nxt_log(&engine->task, NXT_LOG_CRIT, "signalfd(%d) failed %E", + engine->u.epoll.signalfd.fd, nxt_errno); return NXT_ERROR; } - es->signalfd.fd = fd; + engine->u.epoll.signalfd.fd = fd; if (nxt_fd_nonblocking(fd) != NXT_OK) { return NXT_ERROR; } - nxt_main_log_debug("signalfd(): %d", fd); - - thr = nxt_thread(); + nxt_debug(&engine->task, "signalfd(): %d", fd); - es->signalfd.data = signals->handler; - es->signalfd.read_work_queue = &thr->engine->fast_work_queue; - es->signalfd.read_handler = nxt_epoll_signalfd_handler; - es->signalfd.log = &nxt_main_log; - es->signalfd.task = &thr->engine->task; + engine->u.epoll.signalfd.data = engine->signals->handler; + engine->u.epoll.signalfd.read_work_queue = &engine->fast_work_queue; + engine->u.epoll.signalfd.read_handler = nxt_epoll_signalfd_handler; + engine->u.epoll.signalfd.log = engine->task.log; + engine->u.epoll.signalfd.task = &engine->task; ee.events = EPOLLIN; - ee.data.ptr = &es->signalfd; + ee.data.ptr = &engine->u.epoll.signalfd; - if (epoll_ctl(es->epoll, EPOLL_CTL_ADD, fd, &ee) != 0) { - nxt_main_log_alert("epoll_ctl(%d, %d, %d) failed %E", - es->epoll, EPOLL_CTL_ADD, fd, nxt_errno); + if (epoll_ctl(engine->u.epoll.fd, EPOLL_CTL_ADD, fd, &ee) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "epoll_ctl(%d, %d, %d) failed %E", + engine->u.epoll.fd, EPOLL_CTL_ADD, fd, nxt_errno); return NXT_ERROR; } @@ -744,7 +727,7 @@ static void nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, void *data) { int n; - nxt_event_fd_t *ev; + nxt_fd_event_t *ev; nxt_work_handler_t handler; struct signalfd_siginfo sfd; @@ -773,14 +756,12 @@ nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, void *data) #if (NXT_HAVE_EVENTFD) static nxt_int_t -nxt_epoll_enable_post(nxt_event_set_t *event_set, nxt_work_handler_t handler) +nxt_epoll_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler) { - nxt_thread_t *thr; - struct epoll_event ee; - nxt_epoll_event_set_t *es; + int ret; + struct epoll_event ee; - es = &event_set->epoll; - es->post_handler = handler; + engine->u.epoll.post_handler = handler; /* * Glibc eventfd() wrapper always has the flags argument. Glibc 2.7 @@ -791,36 +772,38 @@ nxt_epoll_enable_post(nxt_event_set_t *event_set, nxt_work_handler_t handler) * is set separately. */ - es->eventfd.fd = eventfd(0, 0); + engine->u.epoll.eventfd.fd = eventfd(0, 0); - if (es->eventfd.fd == -1) { - nxt_main_log_emerg("eventfd() failed %E", nxt_errno); + if (engine->u.epoll.eventfd.fd == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, "eventfd() failed %E", nxt_errno); return NXT_ERROR; } - if (nxt_fd_nonblocking(es->eventfd.fd) != NXT_OK) { + if (nxt_fd_nonblocking(engine->u.epoll.eventfd.fd) != NXT_OK) { return NXT_ERROR; } - nxt_main_log_debug("eventfd(): %d", es->eventfd.fd); + nxt_debug(&engine->task, "eventfd(): %d", engine->u.epoll.eventfd.fd); - thr = nxt_thread(); - - es->eventfd.read_work_queue = &thr->engine->fast_work_queue; - es->eventfd.read_handler = nxt_epoll_eventfd_handler; - es->eventfd.data = es; - es->eventfd.log = &nxt_main_log; - es->eventfd.task = &thr->engine->task; + engine->u.epoll.eventfd.read_work_queue = &engine->fast_work_queue; + engine->u.epoll.eventfd.read_handler = nxt_epoll_eventfd_handler; + engine->u.epoll.eventfd.data = engine; + engine->u.epoll.eventfd.log = engine->task.log; + engine->u.epoll.eventfd.task = &engine->task; ee.events = EPOLLIN | EPOLLET; - ee.data.ptr = &es->eventfd; + ee.data.ptr = &engine->u.epoll.eventfd; + + ret = epoll_ctl(engine->u.epoll.fd, EPOLL_CTL_ADD, + engine->u.epoll.eventfd.fd, &ee); - if (epoll_ctl(es->epoll, EPOLL_CTL_ADD, es->eventfd.fd, &ee) == 0) { + if (nxt_fast_path(ret == 0)) { return NXT_OK; } - nxt_main_log_alert("epoll_ctl(%d, %d, %d) failed %E", - es->epoll, EPOLL_CTL_ADD, es->eventfd.fd, nxt_errno); + nxt_log(&engine->task, NXT_LOG_CRIT, "epoll_ctl(%d, %d, %d) failed %E", + engine->u.epoll.fd, EPOLL_CTL_ADD, engine->u.epoll.eventfd.fd, + nxt_errno); return NXT_ERROR; } @@ -829,13 +812,13 @@ nxt_epoll_enable_post(nxt_event_set_t *event_set, nxt_work_handler_t handler) static void nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, void *data) { - int n; - uint64_t events; - nxt_epoll_event_set_t *es; + int n; + uint64_t events; + nxt_event_engine_t *engine; - es = data; + engine = data; - nxt_debug(task, "eventfd handler, times:%ui", es->neventfd); + nxt_debug(task, "eventfd handler, times:%ui", engine->u.epoll.neventfd); /* * The maximum value after write() to a eventfd() descriptor will @@ -846,30 +829,29 @@ nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, void *data) * only the latest write() to the descriptor. */ - if (es->neventfd++ >= 0xfffffffe) { - es->neventfd = 0; + if (engine->u.epoll.neventfd++ >= 0xfffffffe) { + engine->u.epoll.neventfd = 0; - n = read(es->eventfd.fd, &events, sizeof(uint64_t)); + n = read(engine->u.epoll.eventfd.fd, &events, sizeof(uint64_t)); - nxt_debug(task, "read(%d): %d events:%uL", es->eventfd.fd, n, events); + nxt_debug(task, "read(%d): %d events:%uL", + engine->u.epoll.eventfd.fd, n, events); if (n != sizeof(uint64_t)) { nxt_log(task, NXT_LOG_CRIT, "read eventfd(%d) failed %E", - es->eventfd.fd, nxt_errno); + engine->u.epoll.eventfd.fd, nxt_errno); } } - es->post_handler(task, NULL, NULL); + engine->u.epoll.post_handler(task, NULL, NULL); } static void -nxt_epoll_signal(nxt_event_set_t *event_set, nxt_uint_t signo) +nxt_epoll_signal(nxt_event_engine_t *engine, nxt_uint_t signo) { - uint64_t event; - nxt_epoll_event_set_t *es; - - es = &event_set->epoll; + size_t ret; + uint64_t event; /* * eventfd() presents along with signalfd(), so the function @@ -878,9 +860,11 @@ nxt_epoll_signal(nxt_event_set_t *event_set, nxt_uint_t signo) event = 1; - if (write(es->eventfd.fd, &event, sizeof(uint64_t)) != sizeof(uint64_t)) { - nxt_thread_log_alert("write(%d) to eventfd failed %E", - es->eventfd.fd, nxt_errno); + ret = write(engine->u.epoll.eventfd.fd, &event, sizeof(uint64_t)); + + if (nxt_slow_path(ret != sizeof(uint64_t))) { + nxt_log(&engine->task, NXT_LOG_CRIT, "write(%d) to eventfd failed %E", + engine->u.epoll.eventfd.fd, nxt_errno); } } @@ -888,47 +872,48 @@ nxt_epoll_signal(nxt_event_set_t *event_set, nxt_uint_t signo) static void -nxt_epoll_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout) +nxt_epoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) { - int nevents; - uint32_t events; - nxt_int_t i; - nxt_err_t err; - nxt_bool_t error; - nxt_uint_t level; - nxt_event_fd_t *ev; - struct epoll_event *event; - nxt_epoll_event_set_t *es; - - es = &event_set->epoll; - - if (es->nchanges != 0) { - if (nxt_epoll_commit_changes(task, es) != NXT_OK) { + int nevents; + uint32_t events; + nxt_int_t i; + nxt_err_t err; + nxt_bool_t error; + nxt_uint_t level; + nxt_fd_event_t *ev; + struct epoll_event *event; + + if (engine->u.epoll.nchanges != 0) { + if (nxt_epoll_commit_changes(engine) != NXT_OK) { /* Error handlers have been enqueued on failure. */ timeout = 0; } } - nxt_debug(task, "epoll_wait(%d) timeout:%M", es->epoll, timeout); + nxt_debug(&engine->task, "epoll_wait(%d) timeout:%M", + engine->u.epoll.fd, timeout); - nevents = epoll_wait(es->epoll, es->events, es->mevents, timeout); + nevents = epoll_wait(engine->u.epoll.fd, engine->u.epoll.events, + engine->u.epoll.mevents, timeout); err = (nevents == -1) ? nxt_errno : 0; - nxt_thread_time_update(task->thread); + nxt_thread_time_update(engine->task.thread); - nxt_debug(task, "epoll_wait(%d): %d", es->epoll, nevents); + nxt_debug(&engine->task, "epoll_wait(%d): %d", engine->u.epoll.fd, nevents); if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log(task, level, "epoll_wait(%d) failed %E", es->epoll, err); + level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT; + + nxt_log(&engine->task, level, "epoll_wait(%d) failed %E", + engine->u.epoll.fd, err); + return; } for (i = 0; i < nevents; i++) { - event = &es->events[i]; + event = &engine->u.epoll.events[i]; events = event->events; ev = event->data.ptr; @@ -962,9 +947,9 @@ nxt_epoll_poll(nxt_task_t *task, nxt_event_set_t *event_set, nxt_work_queue_add(ev->read_work_queue, ev->read_handler, ev->task, ev, ev->data); - } else if (event_set->epoll.mode == 0) { + } else if (engine->u.epoll.mode == 0) { /* Level-triggered mode. */ - nxt_epoll_disable_read(event_set, ev); + nxt_epoll_disable_read(engine, ev); } } @@ -982,9 +967,9 @@ nxt_epoll_poll(nxt_task_t *task, nxt_event_set_t *event_set, nxt_work_queue_add(ev->write_work_queue, ev->write_handler, ev->task, ev, ev->data); - } else if (event_set->epoll.mode == 0) { + } else if (engine->u.epoll.mode == 0) { /* Level-triggered mode. */ - nxt_epoll_disable_write(event_set, ev); + nxt_epoll_disable_write(engine, ev); } } @@ -1056,6 +1041,7 @@ static void nxt_epoll_edge_event_conn_io_connect(nxt_task_t *task, void *obj, void *data) { nxt_event_conn_t *c; + nxt_event_engine_t *engine; nxt_work_handler_t handler; const nxt_event_conn_state_t *state; @@ -1074,15 +1060,16 @@ nxt_epoll_edge_event_conn_io_connect(nxt_task_t *task, void *obj, void *data) c->socket.write_handler = nxt_epoll_edge_event_conn_connected; c->socket.error_handler = nxt_event_conn_connect_error; - nxt_event_conn_timer(task->thread->engine, c, state, &c->write_timer); + engine = task->thread->engine; + nxt_event_conn_timer(engine, c, state, &c->write_timer); - nxt_epoll_enable(task->thread->engine->event_set, &c->socket); + nxt_epoll_enable(engine, &c->socket); c->socket.read = NXT_EVENT_BLOCKED; return; #if 0 case NXT_AGAIN: - nxt_event_conn_timer(thr->engine, c, state, &c->write_timer); + nxt_event_conn_timer(engine, c, state, &c->write_timer); /* Fall through. */ @@ -1102,7 +1089,7 @@ nxt_epoll_edge_event_conn_io_connect(nxt_task_t *task, void *obj, void *data) c->socket.write_handler = nxt_epoll_edge_event_conn_connected; c->socket.error_handler = state->error_handler; - nxt_epoll_enable(thr->engine->event_set, &c->socket); + nxt_epoll_enable(engine, &c->socket); c->socket.read = NXT_EVENT_BLOCKED; handler = state->ready_handler; diff --git a/src/nxt_event_conn.c b/src/nxt_event_conn.c index d907c238..b78a9251 100644 --- a/src/nxt_event_conn.c +++ b/src/nxt_event_conn.c @@ -7,9 +7,9 @@ #include <nxt_main.h> -static void nxt_event_conn_shutdown_socket(nxt_task_t *task, void *obj, - void *data); -static void nxt_event_conn_close_socket(nxt_task_t *task, void *obj, +static void nxt_conn_shutdown_handler(nxt_task_t *task, void *obj, void *data); +static void nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data); +static void nxt_conn_close_timer_handler(nxt_task_t *task, void *obj, void *data); @@ -81,7 +81,7 @@ nxt_event_conn_create(nxt_mem_pool_t *mp, nxt_log_t *log) c->read_timer.task = &c->task; c->write_timer.task = &c->task; - c->io = thr->engine->event->io; + c->io = thr->engine->event.io; c->max_chunk = NXT_INT32_T_MAX; c->sendfile = NXT_CONN_SENDFILE_UNSET; @@ -132,72 +132,124 @@ nxt_event_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) void -nxt_event_conn_close(nxt_task_t *task, nxt_event_conn_t *c) +nxt_event_conn_close(nxt_event_engine_t *engine, nxt_event_conn_t *c) { - nxt_thread_t *thr; + int ret; + socklen_t len; + struct linger linger; nxt_work_queue_t *wq; - nxt_event_engine_t *engine; nxt_work_handler_t handler; - nxt_debug(task, "event conn close fd:%d", c->socket.fd); + if (c->socket.timedout) { + /* + * Resetting of timed out connection on close + * releases kernel memory associated with socket. + * This also causes sending TCP/IP RST to a peer. + */ + linger.l_onoff = 1; + linger.l_linger = 0; + len = sizeof(struct linger); - thr = task->thread; + ret = setsockopt(c->socket.fd, SOL_SOCKET, SO_LINGER, &linger, len); - engine = thr->engine; + if (nxt_slow_path(ret != 0)) { + nxt_log(c->socket.task, NXT_LOG_CRIT, + "setsockopt(%d, SO_LINGER) failed %E", + c->socket.fd, nxt_socket_errno); + } + } - nxt_timer_delete(engine, &c->read_timer); - nxt_timer_delete(engine, &c->write_timer); + if (c->socket.error == 0 && !c->socket.closed && !c->socket.shutdown) { + wq = &engine->shutdown_work_queue; + handler = nxt_conn_shutdown_handler; - nxt_event_fd_close(engine, &c->socket); - engine->connections--; + } else{ + wq = &engine->close_work_queue; + handler = nxt_conn_close_handler; + } - nxt_debug(task, "event connections: %uD", engine->connections); + nxt_work_queue_add(wq, handler, c->socket.task, c, engine); +} - if (engine->batch != 0) { - if (c->socket.closed || c->socket.error != 0) { - wq = &engine->close_work_queue; - handler = nxt_event_conn_close_socket; +static void +nxt_conn_shutdown_handler(nxt_task_t *task, void *obj, void *data) +{ + nxt_event_conn_t *c; + nxt_event_engine_t *engine; - } else { - wq = &engine->shutdown_work_queue; - handler = nxt_event_conn_shutdown_socket; - } + c = obj; + engine = data; - nxt_work_queue_add(wq, handler, task, - (void *) (uintptr_t) c->socket.fd, NULL); + nxt_debug(task, "event conn shutdown fd:%d", c->socket.fd); - } else { - nxt_socket_close(c->socket.fd); - } + c->socket.shutdown = 1; - c->socket.fd = -1; + nxt_socket_shutdown(c->socket.fd, SHUT_RDWR); + + nxt_work_queue_add(&engine->close_work_queue, nxt_conn_close_handler, + task, c, engine); } static void -nxt_event_conn_shutdown_socket(nxt_task_t *task, void *obj, void *data) +nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data) { - nxt_socket_t s; + nxt_uint_t events_pending, timers_pending; + nxt_event_conn_t *c; + nxt_event_engine_t *engine; + + c = obj; + engine = data; + + nxt_debug(task, "event conn close fd:%d", c->socket.fd); - s = (nxt_socket_t) (uintptr_t) obj; + timers_pending = nxt_timer_delete(engine, &c->read_timer); + timers_pending += nxt_timer_delete(engine, &c->write_timer); + + events_pending = nxt_fd_event_close(engine, &c->socket); + + if (events_pending == 0) { + nxt_socket_close(c->socket.fd); + c->socket.fd = -1; + + if (timers_pending == 0) { + nxt_work_queue_add(&engine->fast_work_queue, + c->write_state->ready_handler, + task, c, c->socket.data); + return; + } + } - nxt_socket_shutdown(s, SHUT_RDWR); + c->write_timer.handler = nxt_conn_close_timer_handler; + c->write_timer.work_queue = &engine->fast_work_queue; - nxt_work_queue_add(&task->thread->engine->close_work_queue, - nxt_event_conn_close_socket, task, - (void *) (uintptr_t) s, NULL); + nxt_timer_add(engine, &c->write_timer, 0); } static void -nxt_event_conn_close_socket(nxt_task_t *task, void *obj, void *data) +nxt_conn_close_timer_handler(nxt_task_t *task, void *obj, void *data) { - nxt_socket_t s; + nxt_timer_t *ev; + nxt_event_conn_t *c; + nxt_event_engine_t *engine; + + ev = obj; + + c = nxt_event_write_timer_conn(ev); + + nxt_debug(task, "event conn close handler fd:%d", c->socket.fd); + + if (c->socket.fd != -1) { + nxt_socket_close(c->socket.fd); + c->socket.fd = -1; + } - s = (nxt_socket_t) (uintptr_t) obj; + engine = task->thread->engine; - nxt_socket_close(s); + nxt_work_queue_add(&engine->fast_work_queue, c->write_state->ready_handler, + task, c, c->socket.data); } @@ -221,18 +273,6 @@ nxt_event_conn_timer(nxt_event_engine_t *engine, nxt_event_conn_t *c, void nxt_event_conn_work_queue_set(nxt_event_conn_t *c, nxt_work_queue_t *wq) { -#if 0 - nxt_thread_t *thr; - nxt_work_queue_t *owq; - - thr = nxt_thread(); - owq = c->socket.work_queue; - - nxt_thread_work_queue_move(thr, owq, wq, c); - nxt_thread_work_queue_move(thr, owq, wq, &c->read_timer); - nxt_thread_work_queue_move(thr, owq, wq, &c->write_timer); -#endif - c->read_work_queue = wq; c->write_work_queue = wq; c->read_timer.work_queue = wq; diff --git a/src/nxt_event_conn.h b/src/nxt_event_conn.h index fdb41549..3f907633 100644 --- a/src/nxt_event_conn.h +++ b/src/nxt_event_conn.h @@ -102,10 +102,10 @@ typedef struct { struct nxt_event_conn_s { /* - * Must be the first field, since nxt_event_fd_t + * Must be the first field, since nxt_fd_event_t * and nxt_event_conn_t are used interchangeably. */ - nxt_event_fd_t socket; + nxt_fd_event_t socket; nxt_buf_t *read; const nxt_event_conn_state_t *read_state; @@ -170,7 +170,7 @@ struct nxt_event_conn_s { */ typedef struct { /* Must be the first field. */ - nxt_event_fd_t socket; + nxt_fd_event_t socket; nxt_task_t task; @@ -254,7 +254,8 @@ nxt_event_conn_tcp_nodelay_on(c) \ NXT_EXPORT nxt_event_conn_t *nxt_event_conn_create(nxt_mem_pool_t *mp, nxt_log_t *log); void nxt_event_conn_io_shutdown(nxt_task_t *task, void *obj, void *data); -NXT_EXPORT void nxt_event_conn_close(nxt_task_t *task, nxt_event_conn_t *c); +NXT_EXPORT void nxt_event_conn_close(nxt_event_engine_t *engine, + nxt_event_conn_t *c); NXT_EXPORT void nxt_event_conn_timer(nxt_event_engine_t *engine, nxt_event_conn_t *c, const nxt_event_conn_state_t *state, nxt_timer_t *tev); @@ -293,6 +294,9 @@ ssize_t nxt_event_conn_io_writev(nxt_event_conn_t *c, nxt_iobuf_t *iob, nxt_uint_t niob); ssize_t nxt_event_conn_io_send(nxt_event_conn_t *c, void *buf, size_t size); +NXT_EXPORT void nxt_event_conn_io_close(nxt_task_t *task, void *obj, + void *data); + NXT_EXPORT void nxt_event_conn_job_sendfile(nxt_task_t *task, nxt_event_conn_t *c); diff --git a/src/nxt_event_conn_accept.c b/src/nxt_event_conn_accept.c index 02659c3f..7b2dce21 100644 --- a/src/nxt_event_conn_accept.c +++ b/src/nxt_event_conn_accept.c @@ -58,7 +58,7 @@ nxt_event_conn_listen(nxt_task_t *task, nxt_listen_socket_t *ls) cls->socket.error_handler = nxt_event_conn_listen_event_error; cls->socket.log = &nxt_main_log; - cls->accept = engine->event->io->accept; + cls->accept = engine->event.io->accept; cls->listen = ls; @@ -73,7 +73,7 @@ nxt_event_conn_listen(nxt_task_t *task, nxt_listen_socket_t *ls) cls->timer.task = &cls->task; if (nxt_event_conn_accept_alloc(task, cls) != NULL) { - nxt_event_fd_enable_accept(engine, &cls->socket); + nxt_fd_event_enable_accept(engine, &cls->socket); nxt_queue_insert_head(&engine->listen_connections, &cls->link); } @@ -255,15 +255,18 @@ nxt_event_conn_accept_next(nxt_task_t *task, nxt_event_conn_listen_t *cls) static nxt_int_t nxt_event_conn_accept_close_idle(nxt_task_t *task, nxt_event_conn_listen_t *cls) { - nxt_queue_t *idle; - nxt_queue_link_t *link; - nxt_event_conn_t *c; + nxt_queue_t *idle; + nxt_queue_link_t *link; + nxt_event_conn_t *c; + nxt_event_engine_t *engine; static nxt_log_moderation_t nxt_idle_close_log_moderation = { NXT_LOG_INFO, 2, "idle connections closed", NXT_LOG_MODERATION }; - idle = &task->thread->engine->idle_connections; + engine = task->thread->engine; + + idle = &engine->idle_connections; for (link = nxt_queue_last(idle); link != nxt_queue_head(idle); @@ -276,15 +279,15 @@ nxt_event_conn_accept_close_idle(nxt_task_t *task, nxt_event_conn_listen_t *cls) task->log, "no available connections, " "close idle connection"); nxt_queue_remove(link); - nxt_event_conn_close(task, c); + nxt_event_conn_close(engine, c); return NXT_OK; } } - nxt_timer_add(task->thread->engine, &cls->timer, 1000); + nxt_timer_add(engine, &cls->timer, 1000); - nxt_event_fd_disable_read(task->thread->engine, &cls->socket); + nxt_fd_event_disable_read(engine, &cls->socket); return NXT_DECLINED; } @@ -352,7 +355,7 @@ nxt_event_conn_listen_timer_handler(nxt_task_t *task, void *obj, void *data) } } - nxt_event_fd_enable_accept(task->thread->engine, &cls->socket); + nxt_fd_event_enable_accept(task->thread->engine, &cls->socket); cls->accept(task, cls, c); } @@ -361,7 +364,7 @@ nxt_event_conn_listen_timer_handler(nxt_task_t *task, void *obj, void *data) static void nxt_event_conn_listen_event_error(nxt_task_t *task, void *obj, void *data) { - nxt_event_fd_t *ev; + nxt_fd_event_t *ev; ev = obj; diff --git a/src/nxt_event_conn_connect.c b/src/nxt_event_conn_connect.c index 1550aa5c..ccd84011 100644 --- a/src/nxt_event_conn_connect.c +++ b/src/nxt_event_conn_connect.c @@ -79,7 +79,7 @@ nxt_event_conn_io_connect(nxt_task_t *task, void *obj, void *data) nxt_event_conn_timer(engine, c, state, &c->write_timer); - nxt_event_fd_enable_write(engine, &c->socket); + nxt_fd_event_enable_write(engine, &c->socket); return; case NXT_DECLINED: @@ -151,7 +151,7 @@ nxt_event_conn_connect_test(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "event connect test fd:%d", c->socket.fd); - nxt_event_fd_block_write(task->thread->engine, &c->socket); + nxt_fd_event_block_write(task->thread->engine, &c->socket); if (c->write_state->autoreset_timer) { nxt_timer_disable(task->thread->engine, &c->write_timer); diff --git a/src/nxt_event_conn_job_sendfile.c b/src/nxt_event_conn_job_sendfile.c index a49e78dd..dd43c16f 100644 --- a/src/nxt_event_conn_job_sendfile.c +++ b/src/nxt_event_conn_job_sendfile.c @@ -31,7 +31,7 @@ static nxt_buf_t *nxt_event_conn_job_sendfile_completion(nxt_task_t *task, void nxt_event_conn_job_sendfile(nxt_task_t *task, nxt_event_conn_t *c) { - nxt_event_fd_disable(task->thread->engine, &c->socket); + nxt_fd_event_disable(task->thread->engine, &c->socket); /* A work item data is not used in nxt_event_conn_job_sendfile_start(). */ nxt_event_conn_job_sendfile_start(task, c, NULL); @@ -215,7 +215,7 @@ nxt_event_conn_job_sendfile_return(nxt_task_t *task, void *obj, void *data) nxt_event_conn_timer(task->thread->engine, c, c->write_state, &c->write_timer); - nxt_event_fd_oneshot_write(task->thread->engine, &c->socket); + nxt_fd_event_oneshot_write(task->thread->engine, &c->socket); } if (sent != 0) { diff --git a/src/nxt_event_conn_proxy.c b/src/nxt_event_conn_proxy.c index d5539070..42b9dd0f 100644 --- a/src/nxt_event_conn_proxy.c +++ b/src/nxt_event_conn_proxy.c @@ -928,14 +928,10 @@ nxt_event_conn_proxy_shutdown(nxt_task_t *task, nxt_event_conn_proxy_t *p, } if (sink->socket.error != 0 || sink->socket.closed) { - /* - * A socket is already closed or half-closed by - * remote side so the shutdown() syscall is surplus - * since the close() syscall also sends FIN. - */ - nxt_event_conn_close(task, sink); + nxt_event_conn_close(task->thread->engine, sink); } else { + sink->socket.shutdown = 1; nxt_socket_shutdown(sink->socket.fd, SHUT_WR); } @@ -984,7 +980,7 @@ nxt_event_conn_proxy_write_error(nxt_task_t *task, void *obj, void *data) /* Block the direction source. */ source = (sink == p->client) ? p->peer : p->client; - nxt_event_fd_block_read(task->thread->engine, &source->socket); + nxt_fd_event_block_read(task->thread->engine, &source->socket); if (source->write == NULL) { /* @@ -999,19 +995,23 @@ nxt_event_conn_proxy_write_error(nxt_task_t *task, void *obj, void *data) static void nxt_event_conn_proxy_complete(nxt_task_t *task, nxt_event_conn_proxy_t *p) { + nxt_event_engine_t *engine; + + engine = task->thread->engine; + nxt_debug(p->client->socket.task, "event conn proxy complete %d:%d", p->client->socket.fd, p->peer->socket.fd); if (p->client->socket.fd != -1) { - nxt_event_conn_close(task, p->client); + nxt_event_conn_close(engine, p->client); } if (p->peer->socket.fd != -1) { - nxt_event_conn_close(task, p->peer); + nxt_event_conn_close(engine, p->peer); } else if (p->delayed) { nxt_queue_remove(&p->peer->link); - nxt_timer_delete(task->thread->engine, &p->peer->write_timer); + nxt_timer_delete(engine, &p->peer->write_timer); } nxt_mem_free(p->client->mem_pool, p->client_buffer); diff --git a/src/nxt_event_conn_read.c b/src/nxt_event_conn_read.c index f17b60d0..20e4d39b 100644 --- a/src/nxt_event_conn_read.c +++ b/src/nxt_event_conn_read.c @@ -85,7 +85,7 @@ nxt_event_conn_io_read(nxt_task_t *task, void *obj, void *data) } if (n != NXT_AGAIN) { - nxt_event_fd_block_read(engine, &c->socket); + nxt_fd_event_block_read(engine, &c->socket); nxt_timer_disable(engine, &c->read_timer); if (n == 0) { @@ -108,13 +108,13 @@ nxt_event_conn_io_read(nxt_task_t *task, void *obj, void *data) c->socket.error_handler = state->error_handler; if (c->read_timer.state == NXT_TIMER_DISABLED - || nxt_event_fd_is_disabled(c->socket.read)) + || nxt_fd_event_is_disabled(c->socket.read)) { /* Timer may be set or reset. */ nxt_event_conn_timer(engine, c, state, &c->read_timer); - if (nxt_event_fd_is_disabled(c->socket.read)) { - nxt_event_fd_enable_read(engine, &c->socket); + if (nxt_fd_event_is_disabled(c->socket.read)) { + nxt_fd_event_enable_read(engine, &c->socket); } } @@ -122,7 +122,7 @@ nxt_event_conn_io_read(nxt_task_t *task, void *obj, void *data) ready: - nxt_event_fd_block_read(engine, &c->socket); + nxt_fd_event_block_read(engine, &c->socket); if (state->autoreset_timer) { nxt_timer_disable(engine, &c->read_timer); diff --git a/src/nxt_event_conn_write.c b/src/nxt_event_conn_write.c index d6c3d354..72d0731b 100644 --- a/src/nxt_event_conn_write.c +++ b/src/nxt_event_conn_write.c @@ -76,7 +76,7 @@ nxt_event_conn_io_write(nxt_task_t *task, void *obj, void *data) } if (b == NULL) { - nxt_event_fd_block_write(engine, &c->socket); + nxt_fd_event_block_write(engine, &c->socket); break; } @@ -129,7 +129,7 @@ nxt_event_conn_io_write(nxt_task_t *task, void *obj, void *data) } if (nxt_slow_path(ret == NXT_ERROR)) { - nxt_event_fd_block_write(engine, &c->socket); + nxt_fd_event_block_write(engine, &c->socket); nxt_event_conn_io_handle(task->thread, c->write_work_queue, c->write_state->error_handler, task, c, data); @@ -201,7 +201,7 @@ nxt_event_conn_write_delayed(nxt_event_engine_t *engine, nxt_event_conn_t *c, if (timer != 0) { c->delayed = 1; - nxt_event_fd_block_write(engine, &c->socket); + nxt_fd_event_block_write(engine, &c->socket); c->write_timer.handler = nxt_event_conn_write_timer_handler; nxt_timer_add(engine, &c->write_timer, timer); @@ -310,9 +310,9 @@ nxt_event_conn_io_write_chunk(nxt_event_conn_t *c, nxt_buf_t *b, size_t limit) ret = c->io->sendbuf(c, b, limit); if ((ret == NXT_AGAIN || !c->socket.write_ready) - && nxt_event_fd_is_disabled(c->socket.write)) + && nxt_fd_event_is_disabled(c->socket.write)) { - nxt_event_fd_enable_write(c->socket.task->thread->engine, &c->socket); + nxt_fd_event_enable_write(c->socket.task->thread->engine, &c->socket); } return ret; diff --git a/src/nxt_event_engine.c b/src/nxt_event_engine.c index ea7fbe62..fbcf2384 100644 --- a/src/nxt_event_engine.c +++ b/src/nxt_event_engine.c @@ -25,8 +25,9 @@ static nxt_work_handler_t nxt_event_engine_queue_pop(nxt_event_engine_t *engine, nxt_event_engine_t * -nxt_event_engine_create(nxt_thread_t *thr, const nxt_event_set_ops_t *event_set, - const nxt_event_sig_t *signals, nxt_uint_t flags, nxt_uint_t batch) +nxt_event_engine_create(nxt_thread_t *thr, + const nxt_event_interface_t *interface, const nxt_sig_event_t *signals, + nxt_uint_t flags, nxt_uint_t batch) { nxt_uint_t events; nxt_event_engine_t *engine; @@ -64,7 +65,6 @@ nxt_event_engine_create(nxt_thread_t *thr, const nxt_event_set_ops_t *event_set, engine->write_work_queue.cache = &engine->work_queue_cache; engine->shutdown_work_queue.cache = &engine->work_queue_cache; engine->close_work_queue.cache = &engine->work_queue_cache; - engine->final_work_queue.cache = &engine->work_queue_cache; nxt_work_queue_name(&engine->fast_work_queue, "fast"); nxt_work_queue_name(&engine->accept_work_queue, "accept"); @@ -74,7 +74,6 @@ nxt_event_engine_create(nxt_thread_t *thr, const nxt_event_set_ops_t *event_set, nxt_work_queue_name(&engine->write_work_queue, "write"); nxt_work_queue_name(&engine->shutdown_work_queue, "shutdown"); nxt_work_queue_name(&engine->close_work_queue, "close"); - nxt_work_queue_name(&engine->final_work_queue, "final"); if (signals != NULL) { engine->signals = nxt_event_engine_signals(signals); @@ -84,7 +83,7 @@ nxt_event_engine_create(nxt_thread_t *thr, const nxt_event_set_ops_t *event_set, engine->signals->handler = nxt_event_engine_signal_handler; - if (!event_set->signal_support) { + if (!interface->signal_support) { if (nxt_event_engine_signals_start(engine) != NXT_OK) { goto signals_fail; } @@ -98,12 +97,11 @@ nxt_event_engine_create(nxt_thread_t *thr, const nxt_event_set_ops_t *event_set, */ events = (batch != 0) ? batch : 32; - engine->event_set = event_set->create(engine->signals, 4 * events, events); - if (engine->event_set == NULL) { + if (interface->create(engine, 4 * events, events) != NXT_OK) { goto event_set_fail; } - engine->event = event_set; + engine->event = *interface; if (nxt_event_engine_post_init(engine) != NXT_OK) { goto post_fail; @@ -121,11 +119,9 @@ nxt_event_engine_create(nxt_thread_t *thr, const nxt_event_set_ops_t *event_set, nxt_queue_init(&engine->listen_connections); nxt_queue_init(&engine->idle_connections); - engine->thread = thr; - #if !(NXT_THREADS) - if (engine->event->signal_support) { + if (interface->signal_support) { thr->time.signal = -1; } @@ -136,7 +132,7 @@ nxt_event_engine_create(nxt_thread_t *thr, const nxt_event_set_ops_t *event_set, timers_fail: post_fail: - event_set->free(engine->event_set); + interface->free(engine); event_set_fail: signals_fail: @@ -155,9 +151,8 @@ fibers_fail: static nxt_int_t nxt_event_engine_post_init(nxt_event_engine_t *engine) { - if (engine->event->enable_post != NULL) { - return engine->event->enable_post(engine->event_set, - nxt_event_engine_post_handler); + if (engine->event.enable_post != NULL) { + return engine->event.enable_post(engine, nxt_event_engine_post_handler); } #if !(NXT_THREADS) @@ -201,13 +196,14 @@ nxt_event_engine_signal_pipe_create(nxt_event_engine_t *engine) } pipe->event.fd = pipe->fds[0]; + pipe->event.task = &engine->task; pipe->event.read_work_queue = &engine->fast_work_queue; pipe->event.read_handler = nxt_event_engine_signal_pipe; pipe->event.write_work_queue = &engine->fast_work_queue; pipe->event.error_handler = nxt_event_engine_signal_pipe_error; - pipe->event.log = &nxt_main_log; + pipe->event.log = engine->task.log; - nxt_event_fd_enable_read(engine, &pipe->event); + nxt_fd_event_enable_read(engine, &pipe->event); return NXT_OK; } @@ -223,7 +219,7 @@ nxt_event_engine_signal_pipe_free(nxt_event_engine_t *engine) if (pipe != NULL) { if (pipe->event.read_work_queue != NULL) { - nxt_event_fd_close(engine, &pipe->event); + nxt_fd_event_close(engine, &pipe->event); nxt_pipe_close(pipe->fds); } @@ -247,7 +243,7 @@ nxt_event_engine_signal_pipe_close(nxt_task_t *task, void *obj, void *data) void nxt_event_engine_post(nxt_event_engine_t *engine, nxt_work_t *work) { - nxt_thread_log_debug("event engine post"); + nxt_debug(&engine->task, "event engine post"); nxt_locked_work_queue_add(&engine->locked_work_queue, work); @@ -260,15 +256,15 @@ nxt_event_engine_signal(nxt_event_engine_t *engine, nxt_uint_t signo) { u_char buf; - nxt_thread_log_debug("event engine signal:%ui", signo); + nxt_debug(&engine->task, "event engine signal:%ui", signo); /* * A signal number may be sent in a signal context, so the signal * information cannot be passed via a locked work queue. */ - if (engine->event->signal != NULL) { - engine->event->signal(engine->event_set, signo); + if (engine->event.signal != NULL) { + engine->event.signal(engine, signo); return; } @@ -283,7 +279,7 @@ nxt_event_engine_signal_pipe(nxt_task_t *task, void *obj, void *data) int i, n; u_char signo; nxt_bool_t post; - nxt_event_fd_t *ev; + nxt_fd_event_t *ev; u_char buf[128]; ev = obj; @@ -342,7 +338,7 @@ nxt_event_engine_signal_pipe_error(nxt_task_t *task, void *obj, void *data) nxt_log(task, NXT_LOG_CRIT, "engine pipe(%FD:%FD) event error", engine->pipe->fds[0], engine->pipe->fds[1]); - nxt_event_fd_close(engine, &engine->pipe->event); + nxt_fd_event_close(engine, &engine->pipe->event); nxt_pipe_close(engine->pipe->fds); } @@ -351,7 +347,7 @@ static void nxt_event_engine_signal_handler(nxt_task_t *task, void *obj, void *data) { uintptr_t signo; - const nxt_event_sig_t *sigev; + const nxt_sig_event_t *sigev; signo = (uintptr_t) obj; @@ -371,7 +367,7 @@ nxt_event_engine_signal_handler(nxt_task_t *task, void *obj, void *data) nxt_int_t nxt_event_engine_change(nxt_thread_t *thr, nxt_task_t *task, - const nxt_event_set_ops_t *event_set, nxt_uint_t batch) + const nxt_event_interface_t *interface, nxt_uint_t batch) { nxt_uint_t events; nxt_event_engine_t *engine; @@ -379,7 +375,7 @@ nxt_event_engine_change(nxt_thread_t *thr, nxt_task_t *task, engine = thr->engine; engine->batch = batch; - if (!engine->event->signal_support && event_set->signal_support) { + if (!engine->event.signal_support && interface->signal_support) { /* * Block signal processing if the current event * facility does not support signal processing. @@ -393,28 +389,27 @@ nxt_event_engine_change(nxt_thread_t *thr, nxt_task_t *task, nxt_event_engine_signal_pipe(task, &engine->pipe->event, NULL); } - if (engine->pipe != NULL && event_set->enable_post != NULL) { + if (engine->pipe != NULL && interface->enable_post != NULL) { /* * An engine pipe must be closed after all signal events * added above to engine fast work queue will be processed. */ - nxt_work_queue_add(&engine->final_work_queue, + nxt_work_queue_add(&engine->fast_work_queue, nxt_event_engine_signal_pipe_close, &engine->task, engine->pipe, NULL); engine->pipe = NULL; } - engine->event->free(engine->event_set); + engine->event.free(engine); events = (batch != 0) ? batch : 32; - engine->event_set = event_set->create(engine->signals, 4 * events, events); - if (engine->event_set == NULL) { + if (interface->create(engine, 4 * events, events) != NXT_OK) { return NXT_ERROR; } - engine->event = event_set; + engine->event = *interface; if (nxt_event_engine_post_init(engine) != NXT_OK) { return NXT_ERROR; @@ -422,7 +417,7 @@ nxt_event_engine_change(nxt_thread_t *thr, nxt_task_t *task, if (engine->signals != NULL) { - if (!engine->event->signal_support) { + if (!engine->event.signal_support) { return nxt_event_engine_signals_start(engine); } @@ -447,7 +442,7 @@ nxt_event_engine_free(nxt_event_engine_t *engine) nxt_work_queue_cache_destroy(&engine->work_queue_cache); - engine->event->free(engine->event_set); + engine->event.free(engine); /* TODO: free timers */ @@ -473,7 +468,7 @@ nxt_event_engine_queue_pop(nxt_event_engine_t *engine, nxt_task_t **task, engine->current_work_queue++; wq = engine->current_work_queue; - if (wq > &engine->final_work_queue) { + if (wq > &engine->close_work_queue) { wq = &engine->fast_work_queue; engine->current_work_queue = wq; } @@ -519,7 +514,7 @@ nxt_event_engine_start(nxt_event_engine_t *engine) /* A return point from fibers. */ } - thr->log = &nxt_main_log; + thr->log = engine->task.log; for ( ;; ) { @@ -537,7 +532,7 @@ nxt_event_engine_start(nxt_event_engine_t *engine) timeout = nxt_timer_find(engine); - engine->event->poll(&engine->task, engine->event_set, timeout); + engine->event.poll(engine, timeout); now = nxt_thread_monotonic_time(thr) / 1000000; diff --git a/src/nxt_event_engine.h b/src/nxt_event_engine.h index 76382e34..c34f8cd7 100644 --- a/src/nxt_event_engine.h +++ b/src/nxt_event_engine.h @@ -7,31 +7,445 @@ #ifndef _NXT_EVENT_ENGINE_H_INCLUDED_ #define _NXT_EVENT_ENGINE_H_INCLUDED_ +/* + * An event interface is kernel interface such as kqueue, epoll, etc. + * intended to get event notifications about file descriptor state, + * signals, etc. + */ + +#define NXT_FILE_EVENTS 1 +#define NXT_NO_FILE_EVENTS 0 + +#define NXT_SIGNAL_EVENTS 1 +#define NXT_NO_SIGNAL_EVENTS 0 + + +typedef struct { + + /* The canonical event set name. */ + const char *name; + + /* + * Create an event set. The mchanges argument is a maximum number of + * changes to send to the kernel. The mevents argument is a maximum + * number of events to retrieve from the kernel at once, if underlying + * event facility supports batch operations. + */ + nxt_int_t (*create)(nxt_event_engine_t *engine, + nxt_uint_t mchanges, nxt_uint_t mevents); + + /* Close and free an event set. */ + void (*free)(nxt_event_engine_t *engine); + + /* + * Add a file descriptor to an event set and enable the most + * effective read and write event notification method provided + * by underlying event facility. + */ + void (*enable)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* Disable file descriptor event notifications. */ + void (*disable)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Delete a file descriptor from an event set. A possible usage + * is a moving of the file descriptor from one event set to another. + */ + void (*delete)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Delete a file descriptor from an event set before closing the + * file descriptor. The most event facilities such as Linux epoll, + * BSD kqueue, Solaris event ports, AIX pollset, and HP-UX /dev/poll + * delete a file descriptor automatically on the file descriptor close. + * Some facilities such as Solaris /dev/poll require to delete a file + * descriptor explicitly. + */ + nxt_bool_t (*close)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Add a file descriptor to an event set and enable the most effective + * read event notification method provided by underlying event facility. + */ + void (*enable_read)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Add a file descriptor to an event set and enable the most effective + * write event notification method provided by underlying event facility. + */ + void (*enable_write)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* Disable file descriptor read event notifications. */ + void (*disable_read)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* Disable file descriptor write event notifications. */ + void (*disable_write)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* Block file descriptor read event notifications. */ + void (*block_read)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* Block file descriptor write event notifications. */ + void (*block_write)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Add a file descriptor to an event set and enable an oneshot + * read event notification method. + */ + void (*oneshot_read)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Add a file descriptor to an event set and enable an oneshot + * write event notification method. + */ + void (*oneshot_write)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Add a listening socket descriptor to an event set and enable + * a level-triggered read event notification method. + */ + void (*enable_accept)(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); + + /* + * Add a file to an event set and enable a file change notification + * events. + */ + void (*enable_file)(nxt_event_engine_t *engine, + nxt_event_file_t *fev); + + /* + * Delete a file from an event set before closing the file descriptor. + */ + void (*close_file)(nxt_event_engine_t *engine, + nxt_event_file_t *fev); + + /* + * Enable post event notifications and set a post handler to handle + * the zero signal. + */ + nxt_int_t (*enable_post)(nxt_event_engine_t *engine, + nxt_work_handler_t handler); + + /* + * Signal an event set. If a signal number is non-zero then + * a signal handler added to the event set is called. This is + * a way to route Unix signals to an event engine if underlying + * event facility does not support signal events. + * + * If a signal number is zero, then the post_handler of the event + * set is called. This has no relation to Unix signals but is + * a way to wake up the event set to process works posted to + * the event engine locked work queue. + */ + void (*signal)(nxt_event_engine_t *engine, + nxt_uint_t signo); + + /* Poll an event set for new event notifications. */ + void (*poll)(nxt_event_engine_t *engine, + nxt_msec_t timeout); + + /* I/O operations suitable to underlying event facility. */ + nxt_event_conn_io_t *io; + + /* True if an event facility supports file change event notifications. */ + uint8_t file_support; /* 1 bit */ + + /* True if an event facility supports signal event notifications. */ + uint8_t signal_support; /* 1 bit */ +} nxt_event_interface_t; + + +#if (NXT_HAVE_KQUEUE) + +typedef struct { + int fd; + int nchanges; + int mchanges; + int mevents; + nxt_pid_t pid; + + nxt_work_handler_t post_handler; + + struct kevent *changes; + struct kevent *events; +} nxt_kqueue_engine_t; + +extern const nxt_event_interface_t nxt_kqueue_engine; + +#endif + + +#if (NXT_HAVE_EPOLL) + +typedef struct { + int op; + struct epoll_event event; +} nxt_epoll_change_t; + + +typedef struct { + int fd; + uint32_t mode; + nxt_uint_t nchanges; + nxt_uint_t mchanges; + int mevents; + + nxt_epoll_change_t *changes; + struct epoll_event *events; + +#if (NXT_HAVE_EVENTFD) + nxt_work_handler_t post_handler; + nxt_fd_event_t eventfd; + uint32_t neventfd; +#endif + +#if (NXT_HAVE_SIGNALFD) + nxt_fd_event_t signalfd; +#endif +} nxt_epoll_engine_t; + + +extern const nxt_event_interface_t nxt_epoll_edge_engine; +extern const nxt_event_interface_t nxt_epoll_level_engine; + +#endif + + +#if (NXT_HAVE_EVENTPORT) + +typedef struct { + int events; + nxt_fd_event_t *event; +} nxt_eventport_change_t; + + +typedef struct { + int fd; + nxt_uint_t nchanges; + nxt_uint_t mchanges; + u_int mevents; + + nxt_eventport_change_t *changes; + port_event_t *events; + + nxt_work_handler_t post_handler; + nxt_work_handler_t signal_handler; +} nxt_eventport_engine_t; + +extern const nxt_event_interface_t nxt_eventport_engine; + +#endif + + +#if (NXT_HAVE_DEVPOLL) + +typedef struct { + uint8_t op; + short events; + nxt_fd_event_t *event; +} nxt_devpoll_change_t; + + +typedef struct { + int fd; + int nchanges; + int mchanges; + int mevents; + + nxt_devpoll_change_t *changes; + struct pollfd *write_changes; + struct pollfd *events; + nxt_lvlhsh_t fd_hash; +} nxt_devpoll_engine_t; + +extern const nxt_event_interface_t nxt_devpoll_engine; + +#endif + + +#if (NXT_HAVE_POLLSET) + +typedef struct { + uint8_t op; + uint8_t cmd; + short events; + nxt_fd_event_t *event; +} nxt_pollset_change_t; + + +typedef struct { + pollset_t ps; + int nchanges; + int mchanges; + int mevents; + + nxt_pollset_change_t *changes; + struct poll_ctl *write_changes; + struct pollfd *events; + nxt_lvlhsh_t fd_hash; +} nxt_pollset_engine_t; + +extern const nxt_event_interface_t nxt_pollset_engine; + +#endif + + +typedef struct { + uint8_t op; + short events; + nxt_fd_event_t *event; +} nxt_poll_change_t; + + +typedef struct { + nxt_uint_t max_nfds; + nxt_uint_t nfds; + + nxt_uint_t nchanges; + nxt_uint_t mchanges; + + nxt_poll_change_t *changes; + struct pollfd *set; + + nxt_lvlhsh_t fd_hash; +} nxt_poll_engine_t; + +extern const nxt_event_interface_t nxt_poll_engine; + + +typedef struct { + int nfds; + uint32_t update_nfds; /* 1 bit */ + + nxt_fd_event_t **events; + + fd_set main_read_fd_set; + fd_set main_write_fd_set; + fd_set work_read_fd_set; + fd_set work_write_fd_set; +} nxt_select_engine_t; + +extern const nxt_event_interface_t nxt_select_engine; + + +nxt_int_t nxt_fd_event_hash_add(nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd, + nxt_fd_event_t *ev); +void *nxt_fd_event_hash_get(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, + nxt_fd_t fd); +void nxt_fd_event_hash_delete(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, + nxt_fd_t fd, nxt_bool_t ignore); +void nxt_fd_event_hash_destroy(nxt_lvlhsh_t *lvlhsh); + + +#define \ +nxt_fd_event_disable(engine, ev) \ + (engine)->event.disable(engine, ev) + + +#define \ +nxt_fd_event_close(engine, ev) \ + (engine)->event.close(engine, ev) + + +#define \ +nxt_fd_event_enable_read(engine, ev) \ + (engine)->event.enable_read(engine, ev) + + +#define \ +nxt_fd_event_enable_write(engine, ev) \ + (engine)->event.enable_write(engine, ev) + + +#define \ +nxt_fd_event_disable_read(engine, ev) \ + (engine)->event.disable_read(engine, ev) + + +#define \ +nxt_fd_event_disable_write(engine, ev) \ + (engine)->event.disable_write(engine, ev) + + +#define \ +nxt_fd_event_block_read(engine, ev) \ + do { \ + if (nxt_fd_event_is_active((ev)->read)) { \ + (engine)->event.block_read(engine, ev); \ + } \ + } while (0) + + +#define \ +nxt_fd_event_block_write(engine, ev) \ + do { \ + if (nxt_fd_event_is_active((ev)->write)) { \ + (engine)->event.block_write(engine, ev); \ + } \ + } while (0) + + +#define \ +nxt_fd_event_oneshot_read(engine, ev) \ + (engine)->event.oneshot_read(engine, ev) + + +#define \ +nxt_fd_event_oneshot_write(engine, ev) \ + (engine)->event.oneshot_write(engine, ev) + + +#define \ +nxt_fd_event_enable_accept(engine, ev) \ + (engine)->event.enable_accept(engine, ev) + #define NXT_ENGINE_FIBERS 1 typedef struct { nxt_fd_t fds[2]; - nxt_event_fd_t event; + nxt_fd_event_t event; } nxt_event_engine_pipe_t; struct nxt_event_engine_s { - const nxt_event_set_ops_t *event; - nxt_event_set_t *event_set; + nxt_task_t task; - nxt_timers_t timers; + union { + nxt_poll_engine_t poll; + nxt_select_engine_t select; - nxt_task_t task; - /* The engine ID, the main engine has ID 0. */ - uint32_t id; +#if (NXT_HAVE_KQUEUE) + nxt_kqueue_engine_t kqueue; +#endif +#if (NXT_HAVE_EPOLL) + nxt_epoll_engine_t epoll; +#endif +#if (NXT_HAVE_EVENTPORT) + nxt_eventport_engine_t eventport; +#endif +#if (NXT_HAVE_DEVPOLL) + nxt_devpoll_engine_t devpoll; +#endif +#if (NXT_HAVE_POLLSET) + nxt_pollset_engine_t pollset; +#endif + } u; - /* - * A pipe to pass event signals to the engine, if the engine's - * underlying event facility does not support user events. - */ - nxt_event_engine_pipe_t *pipe; + nxt_timers_t timers; nxt_work_queue_cache_t work_queue_cache; nxt_work_queue_t *current_work_queue; @@ -43,15 +457,24 @@ struct nxt_event_engine_s { nxt_work_queue_t write_work_queue; nxt_work_queue_t shutdown_work_queue; nxt_work_queue_t close_work_queue; - nxt_work_queue_t final_work_queue; nxt_locked_work_queue_t locked_work_queue; + nxt_event_interface_t event; + + /* + * A pipe to pass event signals to the engine, if the engine's + * underlying event facility does not support user events. + */ + nxt_event_engine_pipe_t *pipe; + nxt_event_signals_t *signals; - nxt_thread_t *thread; nxt_fiber_main_t *fibers; + /* The engine ID, the main engine has ID 0. */ + uint32_t id; + uint8_t shutdown; /* 1 bit */ uint32_t batch; @@ -64,10 +487,10 @@ struct nxt_event_engine_s { NXT_EXPORT nxt_event_engine_t *nxt_event_engine_create(nxt_thread_t *thr, - const nxt_event_set_ops_t *event_set, const nxt_event_sig_t *signals, + const nxt_event_interface_t *interface, const nxt_sig_event_t *signals, nxt_uint_t flags, nxt_uint_t batch); NXT_EXPORT nxt_int_t nxt_event_engine_change(nxt_thread_t *thr, - nxt_task_t *task, const nxt_event_set_ops_t *event_set, nxt_uint_t batch); + nxt_task_t *task, const nxt_event_interface_t *interface, nxt_uint_t batch); NXT_EXPORT void nxt_event_engine_free(nxt_event_engine_t *engine); NXT_EXPORT void nxt_event_engine_start(nxt_event_engine_t *engine); diff --git a/src/nxt_event_set.c b/src/nxt_event_set.c deleted file mode 100644 index 2e75267b..00000000 --- a/src/nxt_event_set.c +++ /dev/null @@ -1,107 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -static nxt_int_t nxt_event_set_fd_hash_test(nxt_lvlhsh_query_t *lhq, - void *data); - - -static const nxt_lvlhsh_proto_t nxt_event_set_fd_hash_proto nxt_aligned(64) = -{ - NXT_LVLHSH_LARGE_MEMALIGN, - 0, - nxt_event_set_fd_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -/* nxt_murmur_hash2() is unique for 4 bytes. */ - -static nxt_int_t -nxt_event_set_fd_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - return NXT_OK; -} - - -nxt_int_t -nxt_event_set_fd_hash_add(nxt_lvlhsh_t *lh, nxt_fd_t fd, nxt_event_fd_t *ev) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.replace = 0; - lhq.value = ev; - lhq.proto = &nxt_event_set_fd_hash_proto; - - if (nxt_lvlhsh_insert(lh, &lhq) == NXT_OK) { - return NXT_OK; - } - - nxt_log_alert(ev->log, "event fd %d is already in hash", ev->fd); - return NXT_ERROR; -} - - -void * -nxt_event_set_fd_hash_get(nxt_lvlhsh_t *lh, nxt_fd_t fd) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.proto = &nxt_event_set_fd_hash_proto; - - if (nxt_lvlhsh_find(lh, &lhq) == NXT_OK) { - return lhq.value; - } - - nxt_thread_log_alert("event fd %d not found in hash", fd); - return NULL; -} - - -void -nxt_event_set_fd_hash_delete(nxt_lvlhsh_t *lh, nxt_fd_t fd, nxt_bool_t ignore) -{ - nxt_lvlhsh_query_t lhq; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.proto = &nxt_event_set_fd_hash_proto; - - if (nxt_lvlhsh_delete(lh, &lhq) != NXT_OK && !ignore) { - nxt_thread_log_alert("event fd %d not found in hash", fd); - } -} - - -void -nxt_event_set_fd_hash_destroy(nxt_lvlhsh_t *lh) -{ - nxt_event_fd_t *ev; - nxt_lvlhsh_each_t lhe; - nxt_lvlhsh_query_t lhq; - - nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t)); - lhe.proto = &nxt_event_set_fd_hash_proto; - lhq.proto = &nxt_event_set_fd_hash_proto; - - for ( ;; ) { - ev = nxt_lvlhsh_each(lh, &lhe); - - if (ev == NULL) { - return; - } - - lhq.key_hash = nxt_murmur_hash2(&ev->fd, sizeof(nxt_fd_t)); - - if (nxt_lvlhsh_delete(lh, &lhq) != NXT_OK) { - nxt_thread_log_alert("event fd %d not found in hash", ev->fd); - } - } -} diff --git a/src/nxt_event_set.h b/src/nxt_event_set.h deleted file mode 100644 index 01c36ea1..00000000 --- a/src/nxt_event_set.h +++ /dev/null @@ -1,473 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_EVENT_SET_H_INCLUDED_ -#define _NXT_EVENT_SET_H_INCLUDED_ - - -/* - * An event facility is kernel interface such as kqueue, epoll, etc. - * intended to get event notifications about file descriptor state, - * signals, etc. - * - * An event set provides generic interface to underlying event facility. - * Although event set and event facility are closely coupled with an event - * engine, nevertheless they are separated from an event engine to allow - * to add one event facility to another if underlying event facility allows - * this (Linux epoll, BSD kqueue, Solaris eventport). - */ - -typedef union nxt_event_set_u nxt_event_set_t; - - -#define NXT_FILE_EVENTS 1 -#define NXT_NO_FILE_EVENTS 0 - -#define NXT_SIGNAL_EVENTS 1 -#define NXT_NO_SIGNAL_EVENTS 0 - - -typedef struct { - - /* The canonical event set name. */ - const char *name; - - /* - * Create an event set. The mchanges argument is a maximum number of - * changes to send to the kernel. The mevents argument is a maximum - * number of events to retrieve from the kernel at once, if underlying - * event facility supports batch operations. - */ - nxt_event_set_t *(*create)(nxt_event_signals_t *signals, - nxt_uint_t mchanges, nxt_uint_t mevents); - - /* Close and free an event set. */ - void (*free)(nxt_event_set_t *data); - - /* - * Add a file descriptor to an event set and enable the most - * effective read and write event notification method provided - * by underlying event facility. - */ - void (*enable)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* Disable file descriptor event notifications. */ - void (*disable)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Delete a file descriptor from an event set. A possible usage - * is a moving of the file descriptor from one event set to another. - */ - void (*delete)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Delete a file descriptor from an event set before closing the - * file descriptor. The most event facilities such as Linux epoll, - * BSD kqueue, Solaris event ports, AIX pollset, and HP-UX /dev/poll - * delete a file descriptor automatically on the file descriptor close. - * Some facilities such as Solaris /dev/poll require to delete a file - * descriptor explicitly. - */ - void (*close)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Add a file descriptor to an event set and enable the most effective - * read event notification method provided by underlying event facility. - */ - void (*enable_read)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Add a file descriptor to an event set and enable the most effective - * write event notification method provided by underlying event facility. - */ - void (*enable_write)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* Disable file descriptor read event notifications. */ - void (*disable_read)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* Disable file descriptor write event notifications. */ - void (*disable_write)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* Block file descriptor read event notifications. */ - void (*block_read)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* Block file descriptor write event notifications. */ - void (*block_write)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Add a file descriptor to an event set and enable an oneshot - * read event notification method. - */ - void (*oneshot_read)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Add a file descriptor to an event set and enable an oneshot - * write event notification method. - */ - void (*oneshot_write)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Add a listening socket descriptor to an event set and enable - * a level-triggered read event notification method. - */ - void (*enable_accept)(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); - - /* - * Add a file to an event set and enable a file change notification - * events. - */ - void (*enable_file)(nxt_event_set_t *event_set, - nxt_event_file_t *fev); - - /* - * Delete a file from an event set before closing the file descriptor. - */ - void (*close_file)(nxt_event_set_t *event_set, - nxt_event_file_t *fev); - - /* - * Enable post event notifications and set a post handler to handle - * the zero signal. - */ - nxt_int_t (*enable_post)(nxt_event_set_t *event_set, - nxt_work_handler_t handler); - - /* - * Signal an event set. If a signal number is non-zero then - * a signal handler added to the event set is called. This is - * a way to route Unix signals to an event engine if underlying - * event facility does not support signal events. - * - * If a signal number is zero, then the post_handler of the event - * set is called. This has no relation to Unix signals but is - * a way to wake up the event set to process works posted to - * the event engine locked work queue. - */ - void (*signal)(nxt_event_set_t *event_set, - nxt_uint_t signo); - - /* Poll an event set for new event notifications. */ - void (*poll)(nxt_task_t *task, - nxt_event_set_t *event_set, - nxt_msec_t timeout); - - /* I/O operations suitable to underlying event facility. */ - nxt_event_conn_io_t *io; - - /* True if an event facility supports file change event notifications. */ - uint8_t file_support; /* 1 bit */ - - /* True if an event facility supports signal event notifications. */ - uint8_t signal_support; /* 1 bit */ -} nxt_event_set_ops_t; - - -#if (NXT_HAVE_KQUEUE) - -typedef struct { - int kqueue; - int nchanges; - int mchanges; - int mevents; - nxt_pid_t pid; - - nxt_work_handler_t post_handler; - - struct kevent *changes; - struct kevent *events; -} nxt_kqueue_event_set_t; - -extern const nxt_event_set_ops_t nxt_kqueue_event_set; - -#endif - - -#if (NXT_HAVE_EPOLL) - -typedef struct { - int op; - /* - * Although file descriptor can be obtained using pointer to a - * nxt_event_fd_t stored in event.data.ptr, nevertheless storing - * the descriptor right here avoid cache miss. Besides this costs - * no space because event.data must be anyway aligned to 64 bits. - */ - nxt_socket_t fd; - - struct epoll_event event; -} nxt_epoll_change_t; - - -typedef struct { - int epoll; - uint32_t mode; - nxt_uint_t nchanges; - nxt_uint_t mchanges; - int mevents; - - nxt_epoll_change_t *changes; - struct epoll_event *events; - -#if (NXT_HAVE_EVENTFD) - nxt_work_handler_t post_handler; - nxt_event_fd_t eventfd; - uint32_t neventfd; -#endif - -#if (NXT_HAVE_SIGNALFD) - nxt_event_fd_t signalfd; -#endif -} nxt_epoll_event_set_t; - - -extern const nxt_event_set_ops_t nxt_epoll_edge_event_set; -extern const nxt_event_set_ops_t nxt_epoll_level_event_set; - -#endif - - -#if (NXT_HAVE_EVENTPORT) - -typedef struct { - /* - * Although file descriptor can be obtained using pointer to a - * nxt_event_fd_t, nevertheless storing the descriptor right here - * avoid cache miss. Besides this costs no space on 64-bit platform. - */ - nxt_socket_t fd; - - int events; - nxt_event_fd_t *event; -} nxt_eventport_change_t; - - -typedef struct { - int port; - nxt_uint_t nchanges; - nxt_uint_t mchanges; - u_int mevents; - - nxt_eventport_change_t *changes; - port_event_t *events; - - nxt_work_handler_t post_handler; - nxt_work_handler_t signal_handler; -} nxt_eventport_event_set_t; - -extern const nxt_event_set_ops_t nxt_eventport_event_set; - -#endif - - -#if (NXT_HAVE_DEVPOLL) - -typedef struct { - uint8_t op; - short events; - - /* A file descriptor stored because nxt_event_fd_t may be already freed. */ - nxt_socket_t fd; - - nxt_event_fd_t *event; -} nxt_devpoll_change_t; - - -typedef struct { - int devpoll; - int nchanges; - int mchanges; - int mevents; - - nxt_devpoll_change_t *devpoll_changes; - struct pollfd *changes; - struct pollfd *events; - nxt_lvlhsh_t fd_hash; -} nxt_devpoll_event_set_t; - -extern const nxt_event_set_ops_t nxt_devpoll_event_set; - -#endif - - -#if (NXT_HAVE_POLLSET) - -typedef struct { - uint8_t op; - uint8_t cmd; - short events; - - /* A file descriptor stored because nxt_event_fd_t may be already freed. */ - nxt_socket_t fd; - - nxt_event_fd_t *event; -} nxt_pollset_change_t; - - -typedef struct { - pollset_t pollset; - int nchanges; - int mchanges; - int mevents; - - nxt_pollset_change_t *pollset_changes; - struct poll_ctl *changes; - struct pollfd *events; - nxt_lvlhsh_t fd_hash; -} nxt_pollset_event_set_t; - -extern const nxt_event_set_ops_t nxt_pollset_event_set; - -#endif - - -typedef struct { - uint8_t op; - short events; - - /* A file descriptor stored because nxt_event_fd_t may be already freed. */ - nxt_socket_t fd; - - nxt_event_fd_t *event; -} nxt_poll_change_t; - - -typedef struct { - nxt_uint_t max_nfds; - nxt_uint_t nfds; - - nxt_uint_t nchanges; - nxt_uint_t mchanges; - - nxt_poll_change_t *changes; - struct pollfd *poll_set; - - nxt_lvlhsh_t fd_hash; -} nxt_poll_event_set_t; - -extern const nxt_event_set_ops_t nxt_poll_event_set; - - -typedef struct { - int nfds; - uint32_t update_nfds; /* 1 bit */ - - nxt_event_fd_t **events; - - fd_set main_read_fd_set; - fd_set main_write_fd_set; - fd_set work_read_fd_set; - fd_set work_write_fd_set; -} nxt_select_event_set_t; - -extern const nxt_event_set_ops_t nxt_select_event_set; - - -union nxt_event_set_u { -#if (NXT_HAVE_KQUEUE) - nxt_kqueue_event_set_t kqueue; -#endif -#if (NXT_HAVE_EPOLL) - nxt_epoll_event_set_t epoll; -#endif -#if (NXT_HAVE_EVENTPORT) - nxt_eventport_event_set_t eventport; -#endif -#if (NXT_HAVE_DEVPOLL) - nxt_devpoll_event_set_t devpoll; -#endif -#if (NXT_HAVE_POLLSET) - nxt_pollset_event_set_t pollset; -#endif - nxt_poll_event_set_t poll; - nxt_select_event_set_t select; -}; - - -nxt_int_t nxt_event_set_fd_hash_add(nxt_lvlhsh_t *lh, nxt_fd_t fd, - nxt_event_fd_t *ev); -void *nxt_event_set_fd_hash_get(nxt_lvlhsh_t *lh, nxt_fd_t fd); -void nxt_event_set_fd_hash_delete(nxt_lvlhsh_t *lh, nxt_fd_t fd, - nxt_bool_t ignore); -void nxt_event_set_fd_hash_destroy(nxt_lvlhsh_t *lh); - - -#define \ -nxt_event_fd_disable(engine, ev) \ - (engine)->event->disable((engine)->event_set, ev) - - -#define \ -nxt_event_fd_close(engine, ev) \ - (engine)->event->close((engine)->event_set, ev) - - -#define \ -nxt_event_fd_enable_read(engine, ev) \ - (engine)->event->enable_read((engine)->event_set, ev) - - -#define \ -nxt_event_fd_enable_write(engine, ev) \ - (engine)->event->enable_write((engine)->event_set, ev) - - -#define \ -nxt_event_fd_disable_read(engine, ev) \ - (engine)->event->disable_read((engine)->event_set, ev) - - -#define \ -nxt_event_fd_disable_write(engine, ev) \ - (engine)->event->disable_write((engine)->event_set, ev) - - -#define \ -nxt_event_fd_block_read(engine, ev) \ - do { \ - if (nxt_event_fd_is_active((ev)->read)) { \ - (engine)->event->block_read((engine)->event_set, ev); \ - } \ - } while (0) - - -#define \ -nxt_event_fd_block_write(engine, ev) \ - do { \ - if (nxt_event_fd_is_active((ev)->write)) { \ - (engine)->event->block_write((engine)->event_set, ev); \ - } \ - } while (0) - - -#define \ -nxt_event_fd_oneshot_read(engine, ev) \ - (engine)->event->oneshot_read((engine)->event_set, ev) - - -#define \ -nxt_event_fd_oneshot_write(engine, ev) \ - (engine)->event->oneshot_write((engine)->event_set, ev) - - -#define \ -nxt_event_fd_enable_accept(engine, ev) \ - (engine)->event->enable_accept((engine)->event_set, ev) - - -#endif /* _NXT_EVENT_SET_H_INCLUDED_ */ diff --git a/src/nxt_eventport.c b/src/nxt_eventport.c deleted file mode 100644 index 02984573..00000000 --- a/src/nxt_eventport.c +++ /dev/null @@ -1,646 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -/* - * The event ports have been introduced in Solaris 10. - * The PORT_SOURCE_MQ and PORT_SOURCE_FILE sources have - * been added in OpenSolaris. - */ - - -static nxt_event_set_t *nxt_eventport_create(nxt_event_signals_t *signals, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_eventport_free(nxt_event_set_t *event_set); -static void nxt_eventport_enable(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_disable(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_eventport_drop_changes(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_enable_event(nxt_event_set_t *event_set, - nxt_event_fd_t *ev, nxt_uint_t events); -static void nxt_eventport_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_disable_event(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static nxt_int_t nxt_eventport_commit_changes(nxt_thread_t *thr, - nxt_eventport_event_set_t *es); -static void nxt_eventport_error_handler(nxt_thread_t *thr, void *obj, - void *data); -static void nxt_eventport_block_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_eventport_enable_accept(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static nxt_int_t nxt_eventport_enable_post(nxt_event_set_t *event_set, - nxt_work_handler_t handler); -static void nxt_eventport_signal(nxt_event_set_t *event_set, nxt_uint_t signo); -static void nxt_eventport_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout); - - -const nxt_event_set_ops_t nxt_eventport_event_set = { - "eventport", - nxt_eventport_create, - nxt_eventport_free, - nxt_eventport_enable, - nxt_eventport_disable, - nxt_eventport_disable, - nxt_eventport_close, - nxt_eventport_enable_read, - nxt_eventport_enable_write, - nxt_eventport_disable_read, - nxt_eventport_disable_write, - nxt_eventport_block_read, - nxt_eventport_block_write, - nxt_eventport_oneshot_read, - nxt_eventport_oneshot_write, - nxt_eventport_enable_accept, - NULL, - NULL, - nxt_eventport_enable_post, - nxt_eventport_signal, - nxt_eventport_poll, - - &nxt_unix_event_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_event_set_t * -nxt_eventport_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - nxt_event_set_t *event_set; - nxt_eventport_event_set_t *es; - - event_set = nxt_zalloc(sizeof(nxt_eventport_event_set_t)); - if (event_set == NULL) { - return NULL; - } - - es = &event_set->eventport; - - es->port = -1; - es->mchanges = mchanges; - es->mevents = mevents; - - es->changes = nxt_malloc(sizeof(nxt_eventport_change_t) * mchanges); - if (es->changes == NULL) { - goto fail; - } - - es->events = nxt_malloc(sizeof(port_event_t) * mevents); - if (es->events == NULL) { - goto fail; - } - - es->port = port_create(); - if (es->port == -1) { - nxt_main_log_emerg("port_create() failed %E", nxt_errno); - goto fail; - } - - nxt_main_log_debug("port_create(): %d", es->port); - - if (signals != NULL) { - es->signal_handler = signals->handler; - } - - return event_set; - -fail: - - nxt_eventport_free(event_set); - - return NULL; -} - - -static void -nxt_eventport_free(nxt_event_set_t *event_set) -{ - nxt_eventport_event_set_t *es; - - es = &event_set->eventport; - - nxt_main_log_debug("eventport %d free", es->port); - - if (es->port != -1) { - if (close(es->port) != 0) { - nxt_main_log_emerg("eventport close(%d) failed %E", - es->port, nxt_errno); - } - } - - nxt_free(es->events); - nxt_free(es); -} - - -static void -nxt_eventport_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_DEFAULT; - ev->write = NXT_EVENT_DEFAULT; - - nxt_eventport_enable_event(event_set, ev, POLLIN | POLLOUT); -} - - -static void -nxt_eventport_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_eventport_disable_event(event_set, ev); - } -} - - -static void -nxt_eventport_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_eventport_drop_changes(event_set, ev); -} - - -static void -nxt_eventport_drop_changes(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_eventport_change_t *dst, *src, *end; - nxt_eventport_event_set_t *es; - - es = &event_set->eventport; - - dst = es->changes; - end = dst + es->nchanges; - - for (src = dst; src < end; src++) { - - if (src->event == ev) { - continue; - } - - if (dst != src) { - *dst = *src; - } - - dst++; - } - - es->nchanges -= end - dst; -} - - -static void -nxt_eventport_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t events; - - if (ev->read != NXT_EVENT_BLOCKED) { - events = (ev->write == NXT_EVENT_INACTIVE) ? POLLIN: - (POLLIN | POLLOUT); - nxt_eventport_enable_event(event_set, ev, events); - } - - ev->read = NXT_EVENT_DEFAULT; -} - - -static void -nxt_eventport_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t events; - - if (ev->write != NXT_EVENT_BLOCKED) { - events = (ev->read == NXT_EVENT_INACTIVE) ? POLLOUT: - (POLLIN | POLLOUT); - nxt_eventport_enable_event(event_set, ev, events); - } - - ev->write = NXT_EVENT_DEFAULT; -} - - -/* - * eventport changes are batched to improve instruction and data - * cache locality of several port_associate() and port_dissociate() - * calls followed by port_getn() call. - */ - -static void -nxt_eventport_enable_event(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t events) -{ - nxt_eventport_change_t *ch; - nxt_eventport_event_set_t *es; - - es = &event_set->eventport; - - nxt_log_debug(ev->log, "port %d set event: fd:%d ev:%04XD u:%p", - es->port, ev->fd, events, ev); - - if (es->nchanges >= es->mchanges) { - (void) nxt_eventport_commit_changes(nxt_thread(), es); - } - - ch = &es->changes[es->nchanges++]; - ch->fd = ev->fd; - ch->events = events; - ch->event = ev; -} - - -static void -nxt_eventport_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write == NXT_EVENT_INACTIVE) { - nxt_eventport_disable_event(event_set, ev); - - } else { - nxt_eventport_enable_event(event_set, ev, POLLOUT); - } -} - - -static void -nxt_eventport_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read == NXT_EVENT_INACTIVE) { - nxt_eventport_disable_event(event_set, ev); - - } else { - nxt_eventport_enable_event(event_set, ev, POLLIN); - } -} - - -static void -nxt_eventport_disable_event(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_eventport_change_t *ch; - nxt_eventport_event_set_t *es; - - es = &event_set->eventport; - - nxt_log_debug(ev->log, "port %d disable event : fd:%d", es->port, ev->fd); - - if (es->nchanges >= es->mchanges) { - (void) nxt_eventport_commit_changes(nxt_thread(), es); - } - - ch = &es->changes[es->nchanges++]; - ch->fd = ev->fd; - ch->events = 0; - ch->event = ev; -} - - -static nxt_int_t -nxt_eventport_commit_changes(nxt_thread_t *thr, nxt_eventport_event_set_t *es) -{ - int ret; - nxt_int_t retval; - nxt_event_fd_t *ev; - nxt_eventport_change_t *ch, *end; - - nxt_log_debug(thr->log, "eventport %d changes:%ui", es->port, es->nchanges); - - retval = NXT_OK; - ch = es->changes; - end = ch + es->nchanges; - - do { - ev = ch->event; - - if (ch->events != 0) { - nxt_log_debug(ev->log, "port_associate(%d): fd:%d ev:%04XD u:%p", - es->port, ch->fd, ch->events, ev); - - ret = port_associate(es->port, PORT_SOURCE_FD, ch->fd, - ch->events, ev); - if (ret == 0) { - goto next; - } - - nxt_log_alert(ev->log, - "port_associate(%d, %d, %d, %04XD) failed %E", - es->port, PORT_SOURCE_FD, ch->fd, ch->events, - nxt_errno); - - } else { - nxt_log_debug(ev->log, "port_dissociate(%d): fd:%d", - es->port, ch->fd); - - if (port_dissociate(es->port, PORT_SOURCE_FD, ch->fd) == 0) { - goto next; - } - - nxt_log_alert(ev->log, "port_dissociate(%d, %d, %d) failed %E", - es->port, PORT_SOURCE_FD, ch->fd, nxt_errno); - } - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - nxt_eventport_error_handler, - ev, ev->data, ev->log); - - retval = NXT_ERROR; - - next: - - ch++; - - } while (ch < end); - - es->nchanges = 0; - - return retval; -} - - -static void -nxt_eventport_error_handler(nxt_thread_t *thr, void *obj, void *data) -{ - nxt_event_fd_t *ev; - - ev = obj; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - ev->error_handler(thr, ev, data); -} - - -static void -nxt_eventport_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_eventport_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_eventport_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read == NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_DEFAULT; - - nxt_eventport_enable_event(event_set, ev, POLLIN); - } -} - - -static void -nxt_eventport_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->write == NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_DEFAULT; - - nxt_eventport_enable_event(event_set, ev, POLLOUT); - } -} - - -static void -nxt_eventport_enable_accept(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_LEVEL; - - nxt_eventport_enable_event(event_set, ev, POLLIN); -} - - -static nxt_int_t -nxt_eventport_enable_post(nxt_event_set_t *event_set, - nxt_work_handler_t handler) -{ - event_set->eventport.post_handler = handler; - - return NXT_OK; -} - - -static void -nxt_eventport_signal(nxt_event_set_t *event_set, nxt_uint_t signo) -{ - nxt_eventport_event_set_t *es; - - es = &event_set->eventport; - - nxt_thread_log_debug("port_send(%d, %ui)", es->port, signo); - - if (port_send(es->port, signo, NULL) != 0) { - nxt_thread_log_alert("port_send(%d) failed %E", es->port, nxt_errno); - } -} - - -static void -nxt_eventport_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout) -{ - int n, events, signo; - uint_t nevents; - nxt_err_t err; - nxt_uint_t i, level; - timespec_t ts, *tp; - port_event_t *event; - nxt_event_fd_t *ev; - nxt_work_handler_t handler; - nxt_eventport_event_set_t *es; - - es = &event_set->eventport; - - if (es->nchanges != 0) { - if (nxt_eventport_commit_changes(thr, es) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - if (timeout == NXT_INFINITE_MSEC) { - tp = NULL; - - } else { - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - tp = &ts; - } - - nxt_log_debug(thr->log, "port_getn(%d) timeout: %M", es->port, timeout); - - /* - * A trap for possible error when Solaris does not update nevents - * if ETIME or EINTR is returned. This issue will be logged as - * "unexpected port_getn() event". - * - * The details are in OpenSolaris mailing list thread "port_getn() - * and timeouts - is this a bug or an undocumented feature?" - */ - event = &es->events[0]; - event->portev_events = -1; /* invalid port events */ - event->portev_source = -1; /* invalid port source */ - event->portev_object = -1; - event->portev_user = (void *) -1; - - nevents = 1; - n = port_getn(es->port, es->events, es->mevents, &nevents, tp); - - /* - * 32-bit port_getn() on Solaris 10 x86 returns large negative - * values instead of 0 when returning immediately. - */ - err = (n < 0) ? nxt_errno : 0; - - nxt_thread_time_update(thr); - - if (n == -1) { - if (err == NXT_ETIME || err == NXT_EINTR) { - if (nevents != 0) { - nxt_log_alert(thr->log, "port_getn(%d) failed %E, events:%ud", - es->port, err, nevents); - } - } - - if (err != NXT_ETIME) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log_error(level, thr->log, "port_getn(%d) failed %E", - es->port, err); - - if (err != NXT_EINTR) { - return; - } - } - } - - nxt_log_debug(thr->log, "port_getn(%d) events: %d", es->port, nevents); - - for (i = 0; i < nevents; i++) { - event = &es->events[i]; - - switch (event->portev_source) { - - case PORT_SOURCE_FD: - ev = event->portev_user; - events = event->portev_events; - - nxt_log_debug(ev->log, "eventport: fd:%d ev:%04Xd u:%p rd:%d wr:%d", - event->portev_object, events, ev, - ev->read, ev->write); - - if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { - nxt_log_alert(ev->log, - "port_getn(%d) error fd:%d events:%04Xud", - es->port, ev->fd, events); - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - nxt_eventport_error_handler, - ev, ev->data, ev->log); - continue; - } - - if (events & POLLIN) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - nxt_thread_work_queue_add(thr, ev->read_work_queue, - ev->read_handler, - ev, ev->data, ev->log); - - } - - if (ev->read != NXT_EVENT_LEVEL) { - ev->read = NXT_EVENT_INACTIVE; - } - } - - if (events & POLLOUT) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - nxt_thread_work_queue_add(thr, ev->write_work_queue, - ev->write_handler, - ev, ev->data, ev->log); - } - - ev->write = NXT_EVENT_INACTIVE; - } - - /* - * Reactivate counterpart direction, because the - * eventport is oneshot notification facility. - */ - events = (ev->read == NXT_EVENT_INACTIVE) ? 0 : POLLIN; - events |= (ev->write == NXT_EVENT_INACTIVE) ? 0 : POLLOUT; - - if (events != 0) { - nxt_eventport_enable_event(event_set, ev, events); - } - - break; - - case PORT_SOURCE_USER: - nxt_log_debug(thr->log, "eventport: user ev:%d u:%p", - event->portev_events, event->portev_user); - - signo = event->portev_events; - - handler = (signo == 0) ? es->post_handler : es->signal_handler; - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, handler, - (void *) (uintptr_t) signo, NULL, - thr->log); - - break; - - default: - nxt_log_alert(thr->log, "unexpected port_getn(%d) event: " - "ev:%d src:%d obj:%p u:%p", - es->port, event->portev_events, - event->portev_source, event->portev_object, - event->portev_user); - } - } -} diff --git a/src/nxt_eventport_engine.c b/src/nxt_eventport_engine.c new file mode 100644 index 00000000..7dc0ffa8 --- /dev/null +++ b/src/nxt_eventport_engine.c @@ -0,0 +1,618 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* + * The event ports have been introduced in Solaris 10. + * The PORT_SOURCE_MQ and PORT_SOURCE_FILE sources have + * been added in OpenSolaris. + */ + + +static nxt_int_t nxt_eventport_create(nxt_event_engine_t *engine, + nxt_uint_t mchanges, nxt_uint_t mevents); +static void nxt_eventport_free(nxt_event_engine_t *engine); +static void nxt_eventport_enable(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_disable(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static nxt_bool_t nxt_eventport_close(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_enable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_enable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_enable_event(nxt_event_engine_t *engine, + nxt_fd_event_t *ev, nxt_uint_t events); +static void nxt_eventport_disable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_disable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_disable_event(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static nxt_int_t nxt_eventport_commit_changes(nxt_event_engine_t *engine); +static void nxt_eventport_error_handler(nxt_task_t *task, void *obj, + void *data); +static void nxt_eventport_block_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_block_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_oneshot_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_oneshot_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_eventport_enable_accept(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static nxt_int_t nxt_eventport_enable_post(nxt_event_engine_t *engine, + nxt_work_handler_t handler); +static void nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo); +static void nxt_eventport_poll(nxt_event_engine_t *engine, + nxt_msec_t timeout); + + +const nxt_event_interface_t nxt_eventport_engine = { + "eventport", + nxt_eventport_create, + nxt_eventport_free, + nxt_eventport_enable, + nxt_eventport_disable, + nxt_eventport_disable, + nxt_eventport_close, + nxt_eventport_enable_read, + nxt_eventport_enable_write, + nxt_eventport_disable_read, + nxt_eventport_disable_write, + nxt_eventport_block_read, + nxt_eventport_block_write, + nxt_eventport_oneshot_read, + nxt_eventport_oneshot_write, + nxt_eventport_enable_accept, + NULL, + NULL, + nxt_eventport_enable_post, + nxt_eventport_signal, + nxt_eventport_poll, + + &nxt_unix_event_conn_io, + + NXT_NO_FILE_EVENTS, + NXT_NO_SIGNAL_EVENTS, +}; + + +static nxt_int_t +nxt_eventport_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, + nxt_uint_t mevents) +{ + nxt_eventport_change_t *changes; + + engine->u.eventport.fd = -1; + engine->u.eventport.mchanges = mchanges; + engine->u.eventport.mevents = mevents; + + changes = nxt_malloc(sizeof(nxt_eventport_change_t) * mchanges); + if (changes == NULL) { + goto fail; + } + + engine->u.eventport.changes = changes; + + engine->u.eventport.events = nxt_malloc(sizeof(port_event_t) * mevents); + if (engine->u.eventport.events == NULL) { + goto fail; + } + + engine->u.eventport.fd = port_create(); + if (engine->u.eventport.fd == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, "port_create() failed %E", + nxt_errno); + goto fail; + } + + nxt_debug(&engine->task, "port_create(): %d", engine->u.eventport.fd); + + if (engine->signals != NULL) { + engine->u.eventport.signal_handler = engine->signals->handler; + } + + return NXT_OK; + +fail: + + nxt_eventport_free(engine); + + return NXT_ERROR; +} + + +static void +nxt_eventport_free(nxt_event_engine_t *engine) +{ + int port; + + port = engine->u.eventport.fd; + + nxt_debug(&engine->task, "eventport %d free", port); + + if (port != -1 && close(port) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "eventport close(%d) failed %E", + port, nxt_errno); + } + + nxt_free(engine->u.eventport.events); + + nxt_memzero(&engine->u.eventport, sizeof(nxt_eventport_engine_t)); +} + + +static void +nxt_eventport_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_ACTIVE; + ev->write = NXT_EVENT_ACTIVE; + + nxt_eventport_enable_event(engine, ev, POLLIN | POLLOUT); +} + + +static void +nxt_eventport_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { + + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + nxt_eventport_disable_event(engine, ev); + } +} + + +/* + * port_dissociate(3): + * + * The association is removed if the owner of the association closes the port. + */ + +static nxt_bool_t +nxt_eventport_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + return ev->changing; +} + + +static void +nxt_eventport_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t events; + + if (ev->read != NXT_EVENT_BLOCKED) { + events = (ev->write == NXT_EVENT_INACTIVE) ? POLLIN + : (POLLIN | POLLOUT); + nxt_eventport_enable_event(engine, ev, events); + } + + ev->read = NXT_EVENT_ACTIVE; +} + + +static void +nxt_eventport_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t events; + + if (ev->write != NXT_EVENT_BLOCKED) { + events = (ev->read == NXT_EVENT_INACTIVE) ? POLLOUT + : (POLLIN | POLLOUT); + nxt_eventport_enable_event(engine, ev, events); + } + + ev->write = NXT_EVENT_ACTIVE; +} + + +/* + * eventport changes are batched to improve instruction and data + * cache locality of several port_associate() and port_dissociate() + * calls followed by port_getn() call. + */ + +static void +nxt_eventport_enable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev, + nxt_uint_t events) +{ + nxt_eventport_change_t *change; + + nxt_debug(ev->task, "port %d set event: fd:%d ev:%04XD u:%p", + engine->u.eventport.fd, ev->fd, events, ev); + + if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) { + (void) nxt_eventport_commit_changes(engine); + } + + ev->changing = 1; + + change = &engine->u.eventport.changes[engine->u.eventport.nchanges++]; + change->events = events; + change->event = ev; +} + + +static void +nxt_eventport_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_INACTIVE; + + if (ev->write == NXT_EVENT_INACTIVE) { + nxt_eventport_disable_event(engine, ev); + + } else { + nxt_eventport_enable_event(engine, ev, POLLOUT); + } +} + + +static void +nxt_eventport_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->write = NXT_EVENT_INACTIVE; + + if (ev->read == NXT_EVENT_INACTIVE) { + nxt_eventport_disable_event(engine, ev); + + } else { + nxt_eventport_enable_event(engine, ev, POLLIN); + } +} + + +static void +nxt_eventport_disable_event(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_eventport_change_t *change; + + nxt_debug(ev->task, "port %d disable event : fd:%d", + engine->u.eventport.fd, ev->fd); + + if (engine->u.eventport.nchanges >= engine->u.eventport.mchanges) { + (void) nxt_eventport_commit_changes(engine); + } + + ev->changing = 1; + + change = &engine->u.eventport.changes[engine->u.eventport.nchanges++]; + change->events = 0; + change->event = ev; +} + + +static nxt_int_t +nxt_eventport_commit_changes(nxt_event_engine_t *engine) +{ + int ret, port; + nxt_int_t retval; + nxt_fd_event_t *ev; + nxt_eventport_change_t *change, *end; + + port = engine->u.eventport.fd; + + nxt_debug(&engine->task, "eventport %d changes:%ui", + port, engine->u.eventport.nchanges); + + retval = NXT_OK; + change = engine->u.eventport.changes; + end = change + engine->u.eventport.nchanges; + + do { + ev = change->event; + ev->changing = 0; + + if (change->events != 0) { + nxt_debug(ev->task, "port_associate(%d): fd:%d ev:%04XD u:%p", + port, ev->fd, change->events, ev); + + ret = port_associate(port, PORT_SOURCE_FD, + ev->fd, change->events, ev); + + if (nxt_fast_path(ret == 0)) { + goto next; + } + + nxt_log(ev->task, NXT_LOG_CRIT, + "port_associate(%d, %d, %d, %04XD) failed %E", + port, PORT_SOURCE_FD, ev->fd, change->events, nxt_errno); + + } else { + nxt_debug(ev->task, "port_dissociate(%d): fd:%d", port, ev->fd); + + ret = port_dissociate(port, PORT_SOURCE_FD, ev->fd); + + if (nxt_fast_path(ret == 0)) { + goto next; + } + + nxt_log(ev->task, NXT_LOG_CRIT, + "port_dissociate(%d, %d, %d) failed %E", + port, PORT_SOURCE_FD, ev->fd, nxt_errno); + } + + nxt_work_queue_add(&engine->fast_work_queue, + nxt_eventport_error_handler, + ev->task, ev, ev->data); + + retval = NXT_ERROR; + + next: + + change++; + + } while (change < end); + + engine->u.eventport.nchanges = 0; + + return retval; +} + + +static void +nxt_eventport_error_handler(nxt_task_t *task, void *obj, void *data) +{ + nxt_fd_event_t *ev; + + ev = obj; + + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + ev->error_handler(task, ev, data); +} + + +static void +nxt_eventport_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE) { + ev->read = NXT_EVENT_BLOCKED; + } +} + + +static void +nxt_eventport_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->write != NXT_EVENT_INACTIVE) { + ev->write = NXT_EVENT_BLOCKED; + } +} + + +static void +nxt_eventport_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read == NXT_EVENT_INACTIVE) { + ev->read = NXT_EVENT_ACTIVE; + + nxt_eventport_enable_event(engine, ev, POLLIN); + } +} + + +static void +nxt_eventport_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->write == NXT_EVENT_INACTIVE) { + ev->write = NXT_EVENT_ACTIVE; + + nxt_eventport_enable_event(engine, ev, POLLOUT); + } +} + + +static void +nxt_eventport_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_LEVEL; + + nxt_eventport_enable_event(engine, ev, POLLIN); +} + + +static nxt_int_t +nxt_eventport_enable_post(nxt_event_engine_t *engine, + nxt_work_handler_t handler) +{ + engine->u.eventport.post_handler = handler; + + return NXT_OK; +} + + +static void +nxt_eventport_signal(nxt_event_engine_t *engine, nxt_uint_t signo) +{ + int port; + + port = engine->u.eventport.fd; + + nxt_debug(&engine->task, "port_send(%d, %ui)", port, signo); + + if (port_send(port, signo, NULL) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "port_send(%d) failed %E", + port, nxt_errno); + } +} + + +static void +nxt_eventport_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) +{ + int n, events, signo; + uint_t nevents; + nxt_err_t err; + nxt_uint_t i, level; + timespec_t ts, *tp; + port_event_t *event; + nxt_fd_event_t *ev; + nxt_work_handler_t handler; + + if (engine->u.eventport.nchanges != 0) { + if (nxt_eventport_commit_changes(engine) != NXT_OK) { + /* Error handlers have been enqueued on failure. */ + timeout = 0; + } + } + + if (timeout == NXT_INFINITE_MSEC) { + tp = NULL; + + } else { + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + tp = &ts; + } + + nxt_debug(&engine->task, "port_getn(%d) timeout: %M", + engine->u.eventport.fd, timeout); + + /* + * A trap for possible error when Solaris does not update nevents + * if ETIME or EINTR is returned. This issue will be logged as + * "unexpected port_getn() event". + * + * The details are in OpenSolaris mailing list thread "port_getn() + * and timeouts - is this a bug or an undocumented feature?" + */ + event = &engine->u.eventport.events[0]; + event->portev_events = -1; /* invalid port events */ + event->portev_source = -1; /* invalid port source */ + event->portev_object = -1; + event->portev_user = (void *) -1; + + nevents = 1; + n = port_getn(engine->u.eventport.fd, engine->u.eventport.events, + engine->u.eventport.mevents, &nevents, tp); + + /* + * 32-bit port_getn() on Solaris 10 x86 returns large negative + * values instead of 0 when returning immediately. + */ + err = (n < 0) ? nxt_errno : 0; + + nxt_thread_time_update(engine->task.thread); + + if (n == -1) { + if (err == NXT_ETIME || err == NXT_EINTR) { + if (nevents != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, + "port_getn(%d) failed %E, events:%ud", + engine->u.eventport.fd, err, nevents); + } + } + + if (err != NXT_ETIME) { + level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT; + + nxt_log(&engine->task, level, "port_getn(%d) failed %E", + engine->u.eventport.fd, err); + + if (err != NXT_EINTR) { + return; + } + } + } + + nxt_debug(&engine->task, "port_getn(%d) events: %d", + engine->u.eventport.fd, nevents); + + for (i = 0; i < nevents; i++) { + event = &engine->u.eventport.events[i]; + + switch (event->portev_source) { + + case PORT_SOURCE_FD: + ev = event->portev_user; + events = event->portev_events; + + nxt_debug(ev->task, "eventport: fd:%d ev:%04Xd u:%p rd:%d wr:%d", + event->portev_object, events, ev, ev->read, ev->write); + + if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { + nxt_log(ev->task, NXT_LOG_CRIT, + "port_getn(%d) error fd:%d events:%04Xud", + engine->u.eventport.fd, ev->fd, events); + + nxt_work_queue_add(&engine->fast_work_queue, + nxt_eventport_error_handler, + ev->task, ev, ev->data); + continue; + } + + if (events & POLLIN) { + ev->read_ready = 1; + + if (ev->read != NXT_EVENT_BLOCKED) { + nxt_work_queue_add(ev->read_work_queue, ev->read_handler, + ev->task, ev, ev->data); + + } + + if (ev->read != NXT_EVENT_LEVEL) { + ev->read = NXT_EVENT_INACTIVE; + } + } + + if (events & POLLOUT) { + ev->write_ready = 1; + + if (ev->write != NXT_EVENT_BLOCKED) { + nxt_work_queue_add(ev->write_work_queue, ev->write_handler, + ev->task, ev, ev->data); + } + + ev->write = NXT_EVENT_INACTIVE; + } + + /* + * Reactivate counterpart direction, because the + * eventport is oneshot notification facility. + */ + events = (ev->read == NXT_EVENT_INACTIVE) ? 0 : POLLIN; + events |= (ev->write == NXT_EVENT_INACTIVE) ? 0 : POLLOUT; + + if (events != 0) { + nxt_eventport_enable_event(engine, ev, events); + } + + break; + + case PORT_SOURCE_USER: + nxt_debug(&engine->task, "eventport: user ev:%d u:%p", + event->portev_events, event->portev_user); + + signo = event->portev_events; + + handler = (signo == 0) ? engine->u.eventport.post_handler + : engine->u.eventport.signal_handler; + + nxt_work_queue_add(&engine->fast_work_queue, handler, + &engine->task, (void *) (uintptr_t) signo, NULL); + + break; + + default: + nxt_log(&engine->task, NXT_LOG_CRIT, + "unexpected port_getn(%d) event: ev:%d src:%d obj:%p u:%p", + engine->u.eventport.fd, event->portev_events, + event->portev_source, event->portev_object, + event->portev_user); + } + } +} diff --git a/src/nxt_fd_event.c b/src/nxt_fd_event.c new file mode 100644 index 00000000..98144203 --- /dev/null +++ b/src/nxt_fd_event.c @@ -0,0 +1,131 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +static nxt_int_t nxt_fd_event_hash_test(nxt_lvlhsh_query_t *lhq, void *data); +static void nxt_fd_event_hash_error(nxt_task_t *task, nxt_fd_t fd); + + +static const nxt_lvlhsh_proto_t nxt_event_set_fd_hash_proto nxt_aligned(64) = +{ + NXT_LVLHSH_LARGE_MEMALIGN, + 0, + nxt_fd_event_hash_test, + nxt_lvlhsh_alloc, + nxt_lvlhsh_free, +}; + + +/* nxt_murmur_hash2() is unique for 4 bytes. */ + +static nxt_int_t +nxt_fd_event_hash_test(nxt_lvlhsh_query_t *lhq, void *data) +{ + return NXT_OK; +} + + +nxt_int_t +nxt_fd_event_hash_add(nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd, nxt_fd_event_t *ev) +{ + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + + lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); + lhq.replace = 0; + lhq.value = ev; + lhq.proto = &nxt_event_set_fd_hash_proto; + + ret = nxt_lvlhsh_insert(lvlhsh, &lhq); + + if (nxt_fast_path(ret == NXT_OK)) { + return NXT_OK; + } + + nxt_log(ev->task, NXT_LOG_CRIT, "fd event %d is already in hash", ev->fd); + + return NXT_ERROR; +} + + +void * +nxt_fd_event_hash_get(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd) +{ + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + + lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); + lhq.proto = &nxt_event_set_fd_hash_proto; + + ret = nxt_lvlhsh_find(lvlhsh, &lhq); + + if (nxt_fast_path(ret == NXT_OK)) { + return lhq.value; + } + + nxt_fd_event_hash_error(task, fd); + + return NULL; +} + + +void +nxt_fd_event_hash_delete(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd, + nxt_bool_t ignore) +{ + nxt_int_t ret; + nxt_lvlhsh_query_t lhq; + + lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); + lhq.proto = &nxt_event_set_fd_hash_proto; + + ret = nxt_lvlhsh_delete(lvlhsh, &lhq); + + if (nxt_slow_path(ret != NXT_OK)) { + if (!ignore) { + nxt_fd_event_hash_error(task, fd); + } + } +} + + +void +nxt_fd_event_hash_destroy(nxt_lvlhsh_t *lvlhsh) +{ + nxt_int_t ret; + nxt_fd_event_t *ev; + nxt_lvlhsh_each_t lhe; + nxt_lvlhsh_query_t lhq; + + nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t)); + lhe.proto = &nxt_event_set_fd_hash_proto; + lhq.proto = &nxt_event_set_fd_hash_proto; + + for ( ;; ) { + ev = nxt_lvlhsh_each(lvlhsh, &lhe); + + if (ev == NULL) { + return; + } + + lhq.key_hash = nxt_murmur_hash2(&ev->fd, sizeof(nxt_fd_t)); + + ret = nxt_lvlhsh_delete(lvlhsh, &lhq); + + if (nxt_slow_path(ret != NXT_OK)) { + nxt_fd_event_hash_error(ev->task, ev->fd); + } + } +} + + +static void +nxt_fd_event_hash_error(nxt_task_t *task, nxt_fd_t fd) +{ + nxt_log(task, NXT_LOG_CRIT, "fd event %d not found in hash", fd); +} diff --git a/src/nxt_event_fd.h b/src/nxt_fd_event.h index 20cb7a92..ff989394 100644 --- a/src/nxt_event_fd.h +++ b/src/nxt_fd_event.h @@ -4,8 +4,8 @@ * Copyright (C) NGINX, Inc. */ -#ifndef _NXT_EVENT_FD_H_INCLUDED_ -#define _NXT_EVENT_FD_H_INCLUDED_ +#ifndef _NXT_FD_EVENT_H_INCLUDED_ +#define _NXT_FD_EVENT_H_INCLUDED_ typedef enum { @@ -33,22 +33,28 @@ typedef enum { /* An active level-triggered event. Used by eventport. */ NXT_EVENT_LEVEL, - /* An active event. */ + /* + * An active default event. The event type depends on interface: + * edge-triggered for kqueue, and modern epoll; + * level-triggered for old epoll, devpoll, pollset, poll, and select; + * oneshot for kqueue and eventport. + */ NXT_EVENT_DEFAULT, -} nxt_event_fd_state_t; + NXT_EVENT_ACTIVE = NXT_EVENT_DEFAULT, +} nxt_fd_event_state_t; #define \ -nxt_event_fd_is_disabled(state) \ +nxt_fd_event_is_disabled(state) \ ((state) < NXT_EVENT_ONESHOT) #define \ -nxt_event_fd_is_active(state) \ +nxt_fd_event_is_active(state) \ ((state) >= NXT_EVENT_ONESHOT) -struct nxt_event_fd_s { +struct nxt_fd_event_s { void *data; /* Both are int's. */ @@ -58,12 +64,14 @@ struct nxt_event_fd_s { /* The flags should also be prefetched by nxt_work_queue_pop(). */ #if (NXT_64BIT) - uint8_t read; - uint8_t write; - uint8_t log_error; + nxt_fd_event_state_t read:8; /* 3 bits. */ + nxt_fd_event_state_t write:8; /* 3 bits. */ + nxt_socket_error_level_t log_error:8; /* 3 bits. */ uint8_t read_ready; uint8_t write_ready; + uint8_t changing; uint8_t closed; + uint8_t shutdown; uint8_t timedout; #if (NXT_HAVE_EPOLL) uint8_t epoll_eof:1; @@ -74,19 +82,21 @@ struct nxt_event_fd_s { #endif #else /* NXT_32BIT */ - nxt_event_fd_state_t read:3; - nxt_event_fd_state_t write:3; + nxt_fd_event_state_t read:3; + nxt_fd_event_state_t write:3; nxt_socket_error_level_t log_error:3; - unsigned read_ready:1; - unsigned write_ready:1; - unsigned closed:1; - unsigned timedout:1; + uint8_t read_ready:1; + uint8_t write_ready:1; + uint8_t changing:1; + uint8_t closed:1; + uint8_t shutdown:1; + uint8_t timedout:1; #if (NXT_HAVE_EPOLL) - unsigned epoll_eof:1; - unsigned epoll_error:1; + uint8_t epoll_eof:1; + uint8_t epoll_error:1; #endif #if (NXT_HAVE_KQUEUE) - unsigned kq_eof:1; + uint8_t kq_eof:1; #endif #endif /* NXT_64BIT */ @@ -109,4 +119,4 @@ struct nxt_event_fd_s { }; -#endif /* _NXT_EVENT_FD_H_INCLUDED_ */ +#endif /* _NXT_FD_EVENT_H_INCLUDED_ */ diff --git a/src/nxt_kqueue.c b/src/nxt_kqueue_engine.c index a5a596b9..b4057389 100644 --- a/src/nxt_kqueue.c +++ b/src/nxt_kqueue_engine.c @@ -51,55 +51,52 @@ #endif -static nxt_event_set_t *nxt_kqueue_create(nxt_event_signals_t *signals, +static nxt_int_t nxt_kqueue_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_kqueue_free(nxt_event_set_t *event_set); -static void nxt_kqueue_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_kqueue_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_kqueue_delete(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_kqueue_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_kqueue_drop_changes(nxt_event_set_t *event_set, - uintptr_t ident); -static void nxt_kqueue_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_block_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_enable_accept(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_kqueue_enable_file(nxt_event_set_t *event_set, +static void nxt_kqueue_free(nxt_event_engine_t *engine); +static void nxt_kqueue_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_kqueue_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_kqueue_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static nxt_bool_t nxt_kqueue_close(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_enable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_enable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_disable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_disable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_block_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_block_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_oneshot_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_oneshot_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_enable_accept(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_kqueue_enable_file(nxt_event_engine_t *engine, nxt_event_file_t *ev); -static void nxt_kqueue_close_file(nxt_event_set_t *event_set, +static void nxt_kqueue_close_file(nxt_event_engine_t *engine, nxt_event_file_t *ev); -static void nxt_kqueue_fd_set(nxt_event_set_t *event_set, nxt_event_fd_t *ev, +static void nxt_kqueue_fd_set(nxt_event_engine_t *engine, nxt_fd_event_t *ev, nxt_int_t filter, nxt_uint_t flags); -static struct kevent *nxt_kqueue_get_kevent(nxt_kqueue_event_set_t *ks); -static void nxt_kqueue_commit_changes(nxt_kqueue_event_set_t *ks); -static void nxt_kqueue_error(nxt_kqueue_event_set_t *ks); +static struct kevent *nxt_kqueue_get_kevent(nxt_event_engine_t *engine); +static void nxt_kqueue_error(nxt_event_engine_t *engine); static void nxt_kqueue_fd_error_handler(nxt_task_t *task, void *obj, void *data); static void nxt_kqueue_file_error_handler(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_kqueue_add_signal(nxt_kqueue_event_set_t *kq, - const nxt_event_sig_t *sigev); +static nxt_int_t nxt_kqueue_add_signal(nxt_event_engine_t *engine, + const nxt_sig_event_t *sigev); #if (NXT_HAVE_EVFILT_USER) -static nxt_int_t nxt_kqueue_enable_post(nxt_event_set_t *event_set, +static nxt_int_t nxt_kqueue_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler); -static void nxt_kqueue_signal(nxt_event_set_t *event_set, nxt_uint_t signo); +static void nxt_kqueue_signal(nxt_event_engine_t *engine, nxt_uint_t signo); #endif -static void nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout); +static void nxt_kqueue_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); static void nxt_kqueue_event_conn_io_connect(nxt_task_t *task, void *obj, void *data); @@ -140,7 +137,7 @@ static nxt_event_conn_io_t nxt_kqueue_event_conn_io = { }; -const nxt_event_set_ops_t nxt_kqueue_event_set = { +const nxt_event_interface_t nxt_kqueue_engine = { "kqueue", nxt_kqueue_create, nxt_kqueue_free, @@ -175,91 +172,83 @@ const nxt_event_set_ops_t nxt_kqueue_event_set = { }; -static nxt_event_set_t * -nxt_kqueue_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, +static nxt_int_t +nxt_kqueue_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, nxt_uint_t mevents) { - nxt_event_set_t *event_set; - const nxt_event_sig_t *sigev; - nxt_kqueue_event_set_t *ks; - - event_set = nxt_zalloc(sizeof(nxt_kqueue_event_set_t)); - if (event_set == NULL) { - return NULL; - } + const nxt_sig_event_t *sigev; - ks = &event_set->kqueue; + engine->u.kqueue.fd = -1; + engine->u.kqueue.mchanges = mchanges; + engine->u.kqueue.mevents = mevents; + engine->u.kqueue.pid = nxt_pid; - ks->kqueue = -1; - ks->mchanges = mchanges; - ks->mevents = mevents; - ks->pid = nxt_pid; - - ks->changes = nxt_malloc(sizeof(struct kevent) * mchanges); - if (ks->changes == NULL) { + engine->u.kqueue.changes = nxt_malloc(sizeof(struct kevent) * mchanges); + if (engine->u.kqueue.changes == NULL) { goto fail; } - ks->events = nxt_malloc(sizeof(struct kevent) * mevents); - if (ks->events == NULL) { + engine->u.kqueue.events = nxt_malloc(sizeof(struct kevent) * mevents); + if (engine->u.kqueue.events == NULL) { goto fail; } - ks->kqueue = kqueue(); - if (ks->kqueue == -1) { - nxt_main_log_emerg("kqueue() failed %E", nxt_errno); + engine->u.kqueue.fd = kqueue(); + if (engine->u.kqueue.fd == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, "kqueue() failed %E", nxt_errno); goto fail; } - nxt_main_log_debug("kqueue(): %d", ks->kqueue); + nxt_debug(&engine->task, "kqueue(): %d", engine->u.kqueue.fd); - if (signals != NULL) { - for (sigev = signals->sigev; sigev->signo != 0; sigev++) { - if (nxt_kqueue_add_signal(ks, sigev) != NXT_OK) { + if (engine->signals != NULL) { + for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { + if (nxt_kqueue_add_signal(engine, sigev) != NXT_OK) { goto fail; } } } - return event_set; + return NXT_OK; fail: - nxt_kqueue_free(event_set); + nxt_kqueue_free(engine); - return NULL; + return NXT_ERROR; } static void -nxt_kqueue_free(nxt_event_set_t *event_set) +nxt_kqueue_free(nxt_event_engine_t *engine) { - nxt_kqueue_event_set_t *ks; + nxt_fd_t fd; - ks = &event_set->kqueue; + fd = engine->u.kqueue.fd; - nxt_main_log_debug("kqueue %d free", ks->kqueue); + nxt_debug(&engine->task, "kqueue %d free", fd); - if (ks->kqueue != -1 && ks->pid == nxt_pid) { + if (fd != -1 && engine->u.kqueue.pid == nxt_pid) { /* kqueue is not inherited by fork() */ - if (close(ks->kqueue) != 0) { - nxt_main_log_emerg("kqueue close(%d) failed %E", - ks->kqueue, nxt_errno); + if (close(fd) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "kqueue close(%d) failed %E", + fd, nxt_errno); } } - nxt_free(ks->events); - nxt_free(ks->changes); - nxt_free(ks); + nxt_free(engine->u.kqueue.events); + nxt_free(engine->u.kqueue.changes); + + nxt_memzero(&engine->u.kqueue, sizeof(nxt_kqueue_engine_t)); } static void -nxt_kqueue_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { - nxt_kqueue_enable_read(event_set, ev); - nxt_kqueue_enable_write(event_set, ev); + nxt_kqueue_enable_read(engine, ev); + nxt_kqueue_enable_write(engine, ev); } @@ -269,31 +258,31 @@ nxt_kqueue_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) */ static void -nxt_kqueue_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->read != NXT_EVENT_INACTIVE) { ev->read = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_READ, EV_DISABLE); + nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); } if (ev->write != NXT_EVENT_INACTIVE) { ev->write = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_WRITE, EV_DISABLE); + nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); } } static void -nxt_kqueue_delete(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->read != NXT_EVENT_INACTIVE) { ev->read = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_READ, EV_DELETE); + nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DELETE); } if (ev->write != NXT_EVENT_INACTIVE) { ev->write = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_WRITE, EV_DELETE); + nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DELETE); } } @@ -303,104 +292,72 @@ nxt_kqueue_delete(nxt_event_set_t *event_set, nxt_event_fd_t *ev) * * Calling close() on a file descriptor will remove any kevents that * reference the descriptor. + * + * nxt_kqueue_close() always returns true as there are pending events on + * closing file descriptor because kevent() passes whole change list at once. */ -static void -nxt_kqueue_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +static nxt_bool_t +nxt_kqueue_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { ev->read = NXT_EVENT_INACTIVE; ev->write = NXT_EVENT_INACTIVE; - nxt_kqueue_drop_changes(event_set, ev->fd); -} - - -static void -nxt_kqueue_drop_changes(nxt_event_set_t *event_set, uintptr_t ident) -{ - struct kevent *dst, *src, *end; - nxt_kqueue_event_set_t *ks; - - ks = &event_set->kqueue; - - dst = ks->changes; - end = dst + ks->nchanges; - - for (src = dst; src < end; src++) { - - if (src->ident == ident) { - - switch (src->filter) { - - case EVFILT_READ: - case EVFILT_WRITE: - case EVFILT_VNODE: - continue; - } - } - - if (dst != src) { - *dst = *src; - } - - dst++; - } - - ks->nchanges -= end - dst; + return 1; } /* - * The kqueue event set uses only three states: inactive, blocked, and - * default. An active oneshot event is marked as it is in the default - * state. The event will eventually be converted to the default EV_CLEAR + * The kqueue event engine uses only three states: inactive, blocked, and + * active. An active oneshot event is marked as it is in the default + * state. The event will be converted eventually to the default EV_CLEAR * mode after it will become inactive after delivery. */ static void -nxt_kqueue_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->read == NXT_EVENT_INACTIVE) { - nxt_kqueue_fd_set(event_set, ev, EVFILT_READ, + nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR); } - ev->read = NXT_EVENT_DEFAULT; + ev->read = NXT_EVENT_ACTIVE; } static void -nxt_kqueue_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->write == NXT_EVENT_INACTIVE) { - nxt_kqueue_fd_set(event_set, ev, EVFILT_WRITE, + nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_CLEAR); } - ev->write = NXT_EVENT_DEFAULT; + ev->write = NXT_EVENT_ACTIVE; } static void -nxt_kqueue_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { ev->read = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_READ, EV_DISABLE); + nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); } static void -nxt_kqueue_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { ev->write = NXT_EVENT_INACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_WRITE, EV_DISABLE); + nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); } static void -nxt_kqueue_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->read != NXT_EVENT_INACTIVE) { ev->read = NXT_EVENT_BLOCKED; @@ -409,7 +366,7 @@ nxt_kqueue_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) static void -nxt_kqueue_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { if (ev->write != NXT_EVENT_INACTIVE) { ev->write = NXT_EVENT_BLOCKED; @@ -418,79 +375,75 @@ nxt_kqueue_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) static void -nxt_kqueue_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { - ev->write = NXT_EVENT_DEFAULT; + ev->write = NXT_EVENT_ACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_WRITE, + nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); } static void -nxt_kqueue_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { - ev->write = NXT_EVENT_DEFAULT; + ev->write = NXT_EVENT_ACTIVE; - nxt_kqueue_fd_set(event_set, ev, EVFILT_WRITE, + nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); } static void -nxt_kqueue_enable_accept(nxt_event_set_t *event_set, nxt_event_fd_t *ev) +nxt_kqueue_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) { - ev->read = NXT_EVENT_DEFAULT; + ev->read = NXT_EVENT_ACTIVE; ev->read_handler = nxt_kqueue_listen_handler; - nxt_kqueue_fd_set(event_set, ev, EVFILT_READ, EV_ADD | EV_ENABLE); + nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_ADD | EV_ENABLE); } static void -nxt_kqueue_enable_file(nxt_event_set_t *event_set, nxt_event_file_t *ev) +nxt_kqueue_enable_file(nxt_event_engine_t *engine, nxt_event_file_t *ev) { - struct kevent *kev; - nxt_kqueue_event_set_t *ks; + struct kevent *kev; + + const nxt_int_t flags = EV_ADD | EV_ENABLE | EV_ONESHOT; + const nxt_uint_t fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND + | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE; - ks = &event_set->kqueue; + nxt_debug(&engine->task, "kevent(%d) set: id:%d ft:%i fl:%04Xd, ff:%04XuD", + engine->u.kqueue.fd, ev->file->fd, EVFILT_VNODE, flags, fflags); - kev = nxt_kqueue_get_kevent(ks); + kev = nxt_kqueue_get_kevent(engine); kev->ident = ev->file->fd; kev->filter = EVFILT_VNODE; - kev->flags = EV_ADD | EV_ENABLE | EV_ONESHOT; - kev->fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND - | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE; + kev->flags = flags; + kev->fflags = fflags; kev->data = 0; kev->udata = nxt_kevent_set_udata(ev); - - nxt_thread_log_debug("kevent(%d) set: id:%d ft:%i fl:%04Xd, ff:%04XuD", - ks->kqueue, ev->file->fd, EVFILT_VNODE, - kev->flags, kev->fflags); } static void -nxt_kqueue_close_file(nxt_event_set_t *event_set, nxt_event_file_t *ev) +nxt_kqueue_close_file(nxt_event_engine_t *engine, nxt_event_file_t *ev) { - nxt_kqueue_drop_changes(event_set, ev->file->fd); + /* TODO: pending event. */ } static void -nxt_kqueue_fd_set(nxt_event_set_t *event_set, nxt_event_fd_t *ev, +nxt_kqueue_fd_set(nxt_event_engine_t *engine, nxt_fd_event_t *ev, nxt_int_t filter, nxt_uint_t flags) { - struct kevent *kev; - nxt_kqueue_event_set_t *ks; - - ks = &event_set->kqueue; + struct kevent *kev; - nxt_log_debug(ev->log, "kevent(%d) set event: id:%d ft:%i fl:%04Xui", - ks->kqueue, ev->fd, filter, flags); + nxt_debug(ev->task, "kevent(%d) set event: id:%d ft:%i fl:%04Xui", + engine->u.kqueue.fd, ev->fd, filter, flags); - kev = nxt_kqueue_get_kevent(ks); + kev = nxt_kqueue_get_kevent(engine); kev->ident = ev->fd; kev->filter = filter; @@ -502,45 +455,46 @@ nxt_kqueue_fd_set(nxt_event_set_t *event_set, nxt_event_fd_t *ev, static struct kevent * -nxt_kqueue_get_kevent(nxt_kqueue_event_set_t *ks) +nxt_kqueue_get_kevent(nxt_event_engine_t *engine) { - if (nxt_slow_path(ks->nchanges >= ks->mchanges)) { - nxt_kqueue_commit_changes(ks); - } + int ret, nchanges; - return &ks->changes[ks->nchanges++]; -} + nchanges = engine->u.kqueue.nchanges; + if (nxt_slow_path(nchanges >= engine->u.kqueue.mchanges)) { -static void -nxt_kqueue_commit_changes(nxt_kqueue_event_set_t *ks) -{ - nxt_thread_log_debug("kevent(%d) changes:%d", ks->kqueue, ks->nchanges); + nxt_debug(&engine->task, "kevent(%d) changes:%d", + engine->u.kqueue.fd, nchanges); + + ret = kevent(engine->u.kqueue.fd, engine->u.kqueue.changes, nchanges, + NULL, 0, NULL); + + if (nxt_slow_path(ret != 0)) { + nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", + engine->u.kqueue.fd, nxt_errno); - if (kevent(ks->kqueue, ks->changes, ks->nchanges, NULL, 0, NULL) != 0) { - nxt_thread_log_alert("kevent(%d) failed %E", ks->kqueue, nxt_errno); + nxt_kqueue_error(engine); + } - nxt_kqueue_error(ks); + engine->u.kqueue.nchanges = 0; } - ks->nchanges = 0; + return &engine->u.kqueue.changes[engine->u.kqueue.nchanges++]; } static void -nxt_kqueue_error(nxt_kqueue_event_set_t *ks) +nxt_kqueue_error(nxt_event_engine_t *engine) { struct kevent *kev, *end; - nxt_thread_t *thread; - nxt_event_fd_t *ev; + nxt_fd_event_t *ev; nxt_event_file_t *fev; nxt_work_queue_t *wq; - thread = nxt_thread(); - wq = &thread->engine->fast_work_queue; - end = &ks->changes[ks->nchanges]; + wq = &engine->fast_work_queue; + end = &engine->u.kqueue.changes[engine->u.kqueue.nchanges]; - for (kev = ks->changes; kev < end; kev++) { + for (kev = engine->u.kqueue.changes; kev < end; kev++) { switch (kev->filter) { @@ -564,7 +518,7 @@ nxt_kqueue_error(nxt_kqueue_event_set_t *ks) static void nxt_kqueue_fd_error_handler(nxt_task_t *task, void *obj, void *data) { - nxt_event_fd_t *ev; + nxt_fd_event_t *ev; ev = obj; @@ -595,7 +549,7 @@ nxt_kqueue_file_error_handler(nxt_task_t *task, void *obj, void *data) static nxt_int_t -nxt_kqueue_add_signal(nxt_kqueue_event_set_t *ks, const nxt_event_sig_t *sigev) +nxt_kqueue_add_signal(nxt_event_engine_t *engine, const nxt_sig_event_t *sigev) { int signo; struct kevent kev; @@ -615,12 +569,14 @@ nxt_kqueue_add_signal(nxt_kqueue_event_set_t *ks, const nxt_event_sig_t *sigev) sa.sa_handler = (signo == SIGCHLD) ? SIG_DFL : SIG_IGN; if (sigaction(signo, &sa, NULL) != 0) { - nxt_main_log_alert("sigaction(%d) failed %E", signo, nxt_errno); + nxt_log(&engine->task, NXT_LOG_CRIT, "sigaction(%d) failed %E", + signo, nxt_errno); + return NXT_ERROR; } - nxt_main_log_debug("kevent(%d) signo:%d (%s)", - ks->kqueue, signo, sigev->name); + nxt_debug(&engine->task, "kevent(%d) signo:%d (%s)", + engine->u.kqueue.fd, signo, sigev->name); kev.ident = signo; kev.filter = EVFILT_SIGNAL; @@ -629,11 +585,13 @@ nxt_kqueue_add_signal(nxt_kqueue_event_set_t *ks, const nxt_event_sig_t *sigev) kev.data = 0; kev.udata = nxt_kevent_set_udata(sigev); - if (kevent(ks->kqueue, &kev, 1, NULL, 0, NULL) == 0) { + if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { return NXT_OK; } - nxt_main_log_alert("kevent(%d) failed %E", ks->kqueue, nxt_errno); + nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", + kqueue, nxt_errno); + return NXT_ERROR; } @@ -641,10 +599,9 @@ nxt_kqueue_add_signal(nxt_kqueue_event_set_t *ks, const nxt_event_sig_t *sigev) #if (NXT_HAVE_EVFILT_USER) static nxt_int_t -nxt_kqueue_enable_post(nxt_event_set_t *event_set, nxt_work_handler_t handler) +nxt_kqueue_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler) { - struct kevent kev; - nxt_kqueue_event_set_t *ks; + struct kevent kev; /* EVFILT_USER must be added to a kqueue before it can be triggered. */ @@ -655,23 +612,23 @@ nxt_kqueue_enable_post(nxt_event_set_t *event_set, nxt_work_handler_t handler) kev.data = 0; kev.udata = NULL; - ks = &event_set->kqueue; - ks->post_handler = handler; + engine->u.kqueue.post_handler = handler; - if (kevent(ks->kqueue, &kev, 1, NULL, 0, NULL) == 0) { + if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { return NXT_OK; } - nxt_main_log_alert("kevent(%d) failed %E", ks->kqueue, nxt_errno); + nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", + engine->u.kqueue.fd, nxt_errno); + return NXT_ERROR; } static void -nxt_kqueue_signal(nxt_event_set_t *event_set, nxt_uint_t signo) +nxt_kqueue_signal(nxt_event_engine_t *engine, nxt_uint_t signo) { - struct kevent kev; - nxt_kqueue_event_set_t *ks; + struct kevent kev; /* * kqueue has a builtin signal processing support, so the function @@ -685,10 +642,9 @@ nxt_kqueue_signal(nxt_event_set_t *event_set, nxt_uint_t signo) kev.data = 0; kev.udata = NULL; - ks = &event_set->kqueue; - - if (kevent(ks->kqueue, &kev, 1, NULL, 0, NULL) != 0) { - nxt_thread_log_alert("kevent(%d) failed %E", ks->kqueue, nxt_errno); + if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", + engine->u.kqueue.fd, nxt_errno); } } @@ -696,24 +652,22 @@ nxt_kqueue_signal(nxt_event_set_t *event_set, nxt_uint_t signo) static void -nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout) -{ - int nevents; - void *obj, *data; - nxt_int_t i; - nxt_err_t err; - nxt_uint_t level; - nxt_bool_t error, eof; - nxt_task_t *event_task; - struct kevent *kev; - nxt_event_fd_t *ev; - nxt_event_sig_t *sigev; - struct timespec ts, *tp; - nxt_event_file_t *fev; - nxt_work_queue_t *wq; - nxt_work_handler_t handler; - nxt_kqueue_event_set_t *ks; +nxt_kqueue_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) +{ + int nevents; + void *obj, *data; + nxt_int_t i; + nxt_err_t err; + nxt_uint_t level; + nxt_bool_t error, eof; + nxt_task_t *task; + struct kevent *kev; + nxt_fd_event_t *ev; + nxt_sig_event_t *sigev; + struct timespec ts, *tp; + nxt_event_file_t *fev; + nxt_work_queue_t *wq; + nxt_work_handler_t handler; if (timeout == NXT_INFINITE_MSEC) { tp = NULL; @@ -724,35 +678,36 @@ nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, tp = &ts; } - ks = &event_set->kqueue; + nxt_debug(&engine->task, "kevent(%d) changes:%d timeout:%M", + engine->u.kqueue.fd, engine->u.kqueue.nchanges, timeout); - nxt_debug(task, "kevent(%d) changes:%d timeout:%M", - ks->kqueue, ks->nchanges, timeout); - - nevents = kevent(ks->kqueue, ks->changes, ks->nchanges, - ks->events, ks->mevents, tp); + nevents = kevent(engine->u.kqueue.fd, + engine->u.kqueue.changes, engine->u.kqueue.nchanges, + engine->u.kqueue.events, engine->u.kqueue.mevents, tp); err = (nevents == -1) ? nxt_errno : 0; - nxt_thread_time_update(task->thread); + nxt_thread_time_update(engine->task.thread); - nxt_debug(task, "kevent(%d): %d", ks->kqueue, nevents); + nxt_debug(&engine->task, "kevent(%d): %d", engine->u.kqueue.fd, nevents); if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log(task, level, "kevent(%d) failed %E", ks->kqueue, err); + level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT; + + nxt_log(&engine->task, level, "kevent(%d) failed %E", + engine->u.kqueue.fd, err); - nxt_kqueue_error(ks); + nxt_kqueue_error(engine); return; } - ks->nchanges = 0; + engine->u.kqueue.nchanges = 0; for (i = 0; i < nevents; i++) { - kev = &ks->events[i]; + kev = &engine->u.kqueue.events[i]; - nxt_debug(task, + nxt_debug(&engine->task, (kev->ident > 0x8000000 && kev->ident != (uintptr_t) -1) ? "kevent: id:%p ft:%d fl:%04Xd ff:%d d:%d ud:%p": "kevent: id:%d ft:%d fl:%04Xd ff:%d d:%d ud:%p", @@ -762,13 +717,13 @@ nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, error = (kev->flags & EV_ERROR); if (nxt_slow_path(error)) { - nxt_log(task, NXT_LOG_CRIT, + nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) error %E on ident:%d filter:%d", - ks->kqueue, kev->data, kev->ident, kev->filter); + engine->u.kqueue.fd, kev->data, kev->ident, kev->filter); } - event_task = task; - wq = &task->thread->engine->fast_work_queue; + task = &engine->task; + wq = &engine->fast_work_queue; handler = nxt_kqueue_fd_error_handler; obj = nxt_kevent_get_udata(kev->udata); @@ -801,7 +756,7 @@ nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, wq = ev->read_work_queue; } - event_task = ev->task; + task = ev->task; data = ev->data; break; @@ -832,7 +787,7 @@ nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, wq = ev->write_work_queue; } - event_task = ev->task; + task = ev->task; data = ev->data; break; @@ -840,7 +795,7 @@ nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, case EVFILT_VNODE: fev = obj; handler = fev->handler; - event_task = fev->task; + task = fev->task; data = fev->data; break; @@ -854,7 +809,7 @@ nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, #if (NXT_HAVE_EVFILT_USER) case EVFILT_USER: - handler = ks->post_handler; + handler = engine->u.kqueue.post_handler; data = NULL; break; @@ -863,15 +818,15 @@ nxt_kqueue_poll(nxt_task_t *task, nxt_event_set_t *event_set, default: #if (NXT_DEBUG) - nxt_log(task, NXT_LOG_CRIT, + nxt_log(&engine->task, NXT_LOG_CRIT, "unexpected kevent(%d) filter %d on ident %d", - ks->kqueue, kev->filter, kev->ident); + engine->u.kqueue.fd, kev->filter, kev->ident); #endif continue; } - nxt_work_queue_add(wq, handler, event_task, obj, data); + nxt_work_queue_add(wq, handler, task, obj, data); } } @@ -885,6 +840,7 @@ static void nxt_kqueue_event_conn_io_connect(nxt_task_t *task, void *obj, void *data) { nxt_event_conn_t *c; + nxt_event_engine_t *engine; nxt_work_handler_t handler; const nxt_event_conn_state_t *state; @@ -903,9 +859,10 @@ nxt_kqueue_event_conn_io_connect(nxt_task_t *task, void *obj, void *data) c->socket.write_handler = nxt_kqueue_event_conn_connected; c->socket.error_handler = nxt_event_conn_connect_error; - nxt_event_conn_timer(task->thread->engine, c, state, &c->write_timer); + engine = task->thread->engine; + nxt_event_conn_timer(engine, c, state, &c->write_timer); - nxt_kqueue_enable_write(task->thread->engine->event_set, &c->socket); + nxt_kqueue_enable_write(engine, &c->socket); return; case NXT_DECLINED: @@ -1053,8 +1010,8 @@ nxt_kqueue_event_conn_io_recvbuf(nxt_event_conn_t *c, nxt_buf_t *b) c->socket.kq_available = 0; } - nxt_log_debug(c->socket.log, "kevent fd:%d avail:%D eof:%d", - c->socket.fd, c->socket.kq_available, c->socket.kq_eof); + nxt_debug(c->socket.task, "kevent fd:%d avail:%D eof:%d", + c->socket.fd, c->socket.kq_available, c->socket.kq_eof); c->socket.read_ready = (c->socket.kq_available != 0 || c->socket.kq_eof); diff --git a/src/nxt_main.h b/src/nxt_main.h index 54e414d4..22f39a59 100644 --- a/src/nxt_main.h +++ b/src/nxt_main.h @@ -43,7 +43,7 @@ typedef struct nxt_log_s nxt_log_t; /* TODO: remove unused */ -typedef struct nxt_event_fd_s nxt_event_fd_t; +typedef struct nxt_fd_event_s nxt_fd_event_t; typedef struct nxt_sockaddr_s nxt_sockaddr_t; @@ -118,7 +118,7 @@ nxt_thread_extern_data(nxt_thread_t, nxt_thread_context); #include <nxt_thread_log.h> -#include <nxt_event_fd.h> +#include <nxt_fd_event.h> #include <nxt_port_socket.h> #if (NXT_THREADS) @@ -131,10 +131,7 @@ typedef void (*nxt_event_conn_handler_t)(nxt_thread_t *thr, #include <nxt_listen_socket.h> #include <nxt_event_conn.h> - #include <nxt_event_file.h> - -#include <nxt_event_set.h> #include <nxt_event_engine.h> #include <nxt_job.h> diff --git a/src/nxt_master_process.c b/src/nxt_master_process.c index 781020e6..4fd7e164 100644 --- a/src/nxt_master_process.c +++ b/src/nxt_master_process.c @@ -37,7 +37,7 @@ static void nxt_master_process_sigchld_handler(nxt_task_t *task, void *obj, static void nxt_master_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid); -const nxt_event_sig_t nxt_master_process_signals[] = { +const nxt_sig_event_t nxt_master_process_signals[] = { nxt_event_signal(SIGHUP, nxt_master_process_sighup_handler), nxt_event_signal(SIGINT, nxt_master_process_sigterm_handler), nxt_event_signal(SIGQUIT, nxt_master_process_sigquit_handler), diff --git a/src/nxt_master_process.h b/src/nxt_master_process.h index ce40455e..8c40b5b3 100644 --- a/src/nxt_master_process.h +++ b/src/nxt_master_process.h @@ -14,7 +14,7 @@ void nxt_master_stop_worker_processes(nxt_task_t *task, nxt_cycle_t *cycle); void nxt_worker_process_start(void *data); -extern const nxt_event_sig_t nxt_master_process_signals[]; +extern const nxt_sig_event_t nxt_master_process_signals[]; #endif /* _NXT_UNIX_MASTER_PROCESS_H_INCLUDED_ */ diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index a0eec258..fbf08b24 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -606,25 +606,25 @@ nxt_openssl_conn_test_error(nxt_task_t *task, nxt_event_conn_t *c, int ret, switch (ssltls->ssl_error) { case SSL_ERROR_WANT_READ: - nxt_event_fd_block_write(task->thread->engine, &c->socket); + nxt_fd_event_block_write(task->thread->engine, &c->socket); c->socket.read_ready = 0; c->socket.read_handler = handler; - if (nxt_event_fd_is_disabled(c->socket.read)) { - nxt_event_fd_enable_read(task->thread->engine, &c->socket); + if (nxt_fd_event_is_disabled(c->socket.read)) { + nxt_fd_event_enable_read(task->thread->engine, &c->socket); } return NXT_AGAIN; case SSL_ERROR_WANT_WRITE: - nxt_event_fd_block_read(task->thread->engine, &c->socket); + nxt_fd_event_block_read(task->thread->engine, &c->socket); c->socket.write_ready = 0; c->socket.write_handler = handler; - if (nxt_event_fd_is_disabled(c->socket.write)) { - nxt_event_fd_enable_write(task->thread->engine, &c->socket); + if (nxt_fd_event_is_disabled(c->socket.write)) { + nxt_fd_event_enable_write(task->thread->engine, &c->socket); } return NXT_AGAIN; diff --git a/src/nxt_poll.c b/src/nxt_poll.c deleted file mode 100644 index fd195261..00000000 --- a/src/nxt_poll.c +++ /dev/null @@ -1,752 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -#define NXT_POLL_ADD 0 -#define NXT_POLL_CHANGE 1 -#define NXT_POLL_DELETE 2 - - -typedef struct { - /* - * A file descriptor is stored in hash entry to allow - * nxt_poll_fd_hash_test() to not dereference a pointer to - * nxt_event_fd_t which may be invalid if the file descriptor has - * been already closed and the nxt_event_fd_t's memory has been freed. - */ - nxt_socket_t fd; - - uint32_t index; - void *event; -} nxt_poll_hash_entry_t; - - -static nxt_event_set_t *nxt_poll_create(nxt_event_signals_t *signals, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_poll_free(nxt_event_set_t *event_set); -static void nxt_poll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_poll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_poll_drop_changes(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_poll_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_poll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t op, nxt_uint_t events); -static nxt_int_t nxt_poll_commit_changes(nxt_thread_t *thr, - nxt_poll_event_set_t *ps); -static nxt_int_t nxt_poll_set_add(nxt_thread_t *thr, nxt_poll_event_set_t *ps, - nxt_poll_change_t *ch); -static nxt_int_t nxt_poll_set_change(nxt_thread_t *thr, - nxt_poll_event_set_t *ps, nxt_poll_change_t *ch); -static nxt_int_t nxt_poll_set_delete(nxt_thread_t *thr, - nxt_poll_event_set_t *ps, nxt_poll_change_t *ch); -static void nxt_poll_set_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout); -static nxt_poll_hash_entry_t *nxt_poll_fd_hash_get(nxt_poll_event_set_t *ps, - nxt_fd_t fd); -static nxt_int_t nxt_poll_fd_hash_test(nxt_lvlhsh_query_t *lhq, void *data); -static void nxt_poll_fd_hash_destroy(nxt_lvlhsh_t *lh); - - -const nxt_event_set_ops_t nxt_poll_event_set = { - "poll", - nxt_poll_create, - nxt_poll_free, - nxt_poll_enable, - nxt_poll_disable, - nxt_poll_disable, - nxt_poll_disable, - nxt_poll_enable_read, - nxt_poll_enable_write, - nxt_poll_disable_read, - nxt_poll_disable_write, - nxt_poll_block_read, - nxt_poll_block_write, - nxt_poll_oneshot_read, - nxt_poll_oneshot_write, - nxt_poll_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_poll_set_poll, - - &nxt_unix_event_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static const nxt_lvlhsh_proto_t nxt_poll_fd_hash_proto nxt_aligned(64) = -{ - NXT_LVLHSH_LARGE_MEMALIGN, - 0, - nxt_poll_fd_hash_test, - nxt_lvlhsh_alloc, - nxt_lvlhsh_free, -}; - - -static nxt_event_set_t * -nxt_poll_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - nxt_event_set_t *event_set; - nxt_poll_event_set_t *ps; - - event_set = nxt_zalloc(sizeof(nxt_poll_event_set_t)); - if (event_set == NULL) { - return NULL; - } - - ps = &event_set->poll; - - ps->mchanges = mchanges; - - ps->changes = nxt_malloc(sizeof(nxt_poll_change_t) * mchanges); - if (ps->changes == NULL) { - nxt_free(event_set); - return NULL; - } - - return event_set; -} - - -static void -nxt_poll_free(nxt_event_set_t *event_set) -{ - nxt_poll_event_set_t *ps; - - ps = &event_set->poll; - - nxt_main_log_debug("poll free"); - - nxt_free(ps->poll_set); - nxt_free(ps->changes); - nxt_poll_fd_hash_destroy(&ps->fd_hash); - nxt_free(ps); -} - - -static void -nxt_poll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_DEFAULT; - ev->write = NXT_EVENT_DEFAULT; - - nxt_poll_change(event_set, ev, NXT_POLL_ADD, POLLIN | POLLOUT); -} - - -static void -nxt_poll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_poll_drop_changes(event_set, ev); - /* - * A simple non-zero value POLLHUP is a flag to ignore error handling - * if the event is not present in poll set, because the event may be - * freed at the time when the NXT_POLL_DELETE change will be processed - * and correct event error_handler will not be available. - */ - nxt_poll_change(event_set, ev, NXT_POLL_DELETE, POLLHUP); -} - - -static void -nxt_poll_drop_changes(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_poll_change_t *dst, *src, *end; - nxt_poll_event_set_t *ps; - - ps = &event_set->poll; - - dst = ps->changes; - end = dst + ps->nchanges; - - for (src = dst; src < end; src++) { - - if (src->event == ev) { - continue; - } - - if (dst != src) { - *dst = *src; - } - - dst++; - } - - ps->nchanges -= end - dst; -} - - -static void -nxt_poll_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_DEFAULT; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_POLL_ADD; - events = POLLIN; - - } else { - op = NXT_POLL_CHANGE; - events = POLLIN | POLLOUT; - } - - nxt_poll_change(event_set, ev, op, events); -} - - -static void -nxt_poll_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_DEFAULT; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_POLL_ADD; - events = POLLOUT; - - } else { - op = NXT_POLL_CHANGE; - events = POLLIN | POLLOUT; - } - - nxt_poll_change(event_set, ev, op, events); -} - - -static void -nxt_poll_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_POLL_DELETE; - events = 0; - - } else { - op = NXT_POLL_CHANGE; - events = POLLOUT; - } - - nxt_poll_change(event_set, ev, op, events); -} - - -static void -nxt_poll_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_POLL_DELETE; - events = 0; - - } else { - op = NXT_POLL_CHANGE; - events = POLLIN; - } - - nxt_poll_change(event_set, ev, op, events); -} - - -static void -nxt_poll_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - nxt_poll_disable_read(event_set, ev); - } -} - - -static void -nxt_poll_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - nxt_poll_disable_write(event_set, ev); - } -} - - -static void -nxt_poll_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op; - - op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? - NXT_POLL_ADD : NXT_POLL_CHANGE; - - ev->read = NXT_EVENT_ONESHOT; - ev->write = NXT_EVENT_INACTIVE; - - nxt_poll_change(event_set, ev, op, POLLIN); -} - - -static void -nxt_poll_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op; - - op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? - NXT_POLL_ADD : NXT_POLL_CHANGE; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_ONESHOT; - - nxt_poll_change(event_set, ev, op, POLLOUT); -} - - -/* - * poll changes are batched to improve instruction and data cache - * locality of several lvlhsh operations followed by poll() call. - */ - -static void -nxt_poll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, nxt_uint_t op, - nxt_uint_t events) -{ - nxt_poll_change_t *ch; - nxt_poll_event_set_t *ps; - - nxt_log_debug(ev->log, "poll change: fd:%d op:%d ev:%XD", - ev->fd, op, events); - - ps = &event_set->poll; - - if (ps->nchanges >= ps->mchanges) { - (void) nxt_poll_commit_changes(nxt_thread(), ps); - } - - ch = &ps->changes[ps->nchanges++]; - ch->op = op; - ch->fd = ev->fd; - ch->events = events; - ch->event = ev; -} - - -static nxt_int_t -nxt_poll_commit_changes(nxt_thread_t *thr, nxt_poll_event_set_t *ps) -{ - nxt_int_t ret; - nxt_event_fd_t *ev; - nxt_poll_change_t *ch, *end; - - nxt_log_debug(thr->log, "poll changes:%ui", ps->nchanges); - - ret = NXT_OK; - ch = ps->changes; - end = ch + ps->nchanges; - - do { - ev = ch->event; - - switch (ch->op) { - - case NXT_POLL_ADD: - if (nxt_fast_path(nxt_poll_set_add(thr, ps, ch) == NXT_OK)) { - goto next; - } - break; - - case NXT_POLL_CHANGE: - if (nxt_fast_path(nxt_poll_set_change(thr, ps, ch) == NXT_OK)) { - goto next; - } - break; - - case NXT_POLL_DELETE: - if (nxt_fast_path(nxt_poll_set_delete(thr, ps, ch) == NXT_OK)) { - goto next; - } - break; - } - - nxt_work_queue_add(&thr->engine->fast_work_queue, ev->error_handler, - ev->task, ev, ev->data); - - ret = NXT_ERROR; - - next: - - ch++; - - } while (ch < end); - - ps->nchanges = 0; - - return ret; -} - - -static nxt_int_t -nxt_poll_set_add(nxt_thread_t *thr, nxt_poll_event_set_t *ps, - nxt_poll_change_t *ch) -{ - nxt_uint_t max_nfds; - struct pollfd *pfd; - nxt_lvlhsh_query_t lhq; - nxt_poll_hash_entry_t *phe; - - nxt_log_debug(thr->log, "poll add event: fd:%d ev:%04Xi", - ch->fd, ch->events); - - if (ps->nfds >= ps->max_nfds) { - max_nfds = ps->max_nfds + 512; /* 4K */ - - pfd = nxt_realloc(ps->poll_set, sizeof(struct pollfd) * max_nfds); - if (nxt_slow_path(pfd == NULL)) { - return NXT_ERROR; - } - - ps->poll_set = pfd; - ps->max_nfds = max_nfds; - } - - phe = nxt_malloc(sizeof(nxt_poll_hash_entry_t)); - if (nxt_slow_path(phe == NULL)) { - return NXT_ERROR; - } - - phe->fd = ch->fd; - phe->index = ps->nfds; - phe->event = ch->event; - - pfd = &ps->poll_set[ps->nfds++]; - pfd->fd = ch->fd; - pfd->events = ch->events; - pfd->revents = 0; - - lhq.key_hash = nxt_murmur_hash2(&ch->fd, sizeof(nxt_fd_t)); - lhq.replace = 0; - lhq.key.length = sizeof(nxt_fd_t); - lhq.key.start = (u_char *) &ch->fd; - lhq.value = phe; - lhq.proto = &nxt_poll_fd_hash_proto; - lhq.data = ps->poll_set; - - if (nxt_fast_path(nxt_lvlhsh_insert(&ps->fd_hash, &lhq) == NXT_OK)) { - return NXT_OK; - } - - nxt_free(phe); - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_poll_set_change(nxt_thread_t *thr, nxt_poll_event_set_t *ps, - nxt_poll_change_t *ch) -{ - nxt_poll_hash_entry_t *phe; - - nxt_log_debug(thr->log, "poll change event: fd:%d ev:%04Xi", - ch->fd, ch->events); - - phe = nxt_poll_fd_hash_get(ps, ch->fd); - - if (nxt_fast_path(phe != NULL)) { - ps->poll_set[phe->index].events = ch->events; - return NXT_OK; - } - - return NXT_ERROR; -} - - -static nxt_int_t -nxt_poll_set_delete(nxt_thread_t *thr, nxt_poll_event_set_t *ps, - nxt_poll_change_t *ch) -{ - nxt_uint_t index; - nxt_lvlhsh_query_t lhq; - nxt_poll_hash_entry_t *phe; - - nxt_log_debug(thr->log, "poll delete event: fd:%d", ch->fd); - - lhq.key_hash = nxt_murmur_hash2(&ch->fd, sizeof(nxt_fd_t)); - lhq.key.length = sizeof(nxt_fd_t); - lhq.key.start = (u_char *) &ch->fd; - lhq.proto = &nxt_poll_fd_hash_proto; - lhq.data = ps->poll_set; - - if (nxt_slow_path(nxt_lvlhsh_delete(&ps->fd_hash, &lhq) != NXT_OK)) { - /* - * Ignore NXT_DECLINED error if ch->events - * has the special value POLLHUP. - */ - return (ch->events != 0) ? NXT_OK : NXT_ERROR; - } - - phe = lhq.value; - - index = phe->index; - ps->nfds--; - - if (index != ps->nfds) { - ps->poll_set[index] = ps->poll_set[ps->nfds]; - - phe = nxt_poll_fd_hash_get(ps, ps->poll_set[ps->nfds].fd); - - phe->index = index; - } - - nxt_free(lhq.value); - - return NXT_OK; -} - - -static void -nxt_poll_set_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout) -{ - int nevents; - nxt_fd_t fd; - nxt_err_t err; - nxt_bool_t error; - nxt_uint_t i, events, level; - struct pollfd *pfd; - nxt_event_fd_t *ev; - nxt_poll_event_set_t *ps; - nxt_poll_hash_entry_t *phe; - - ps = &event_set->poll; - - if (ps->nchanges != 0) { - if (nxt_poll_commit_changes(nxt_thread(), ps) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - nxt_debug(task, "poll() events:%ui timeout:%M", ps->nfds, timeout); - - nevents = poll(ps->poll_set, ps->nfds, timeout); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(task->thread); - - nxt_debug(task, "poll(): %d", nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log(task, level, "poll() failed %E", err); - return; - } - - for (i = 0; i < ps->nfds && nevents != 0; i++) { - - pfd = &ps->poll_set[i]; - events = pfd->revents; - - if (events == 0) { - continue; - } - - fd = pfd->fd; - - phe = nxt_poll_fd_hash_get(ps, fd); - - if (nxt_slow_path(phe == NULL)) { - nxt_log(task, NXT_LOG_CRIT, - "poll() returned invalid fd:%d ev:%04Xd rev:%04uXi", - fd, pfd->events, events); - - /* Mark the poll entry to ignore it by the kernel. */ - pfd->fd = -1; - goto next; - } - - ev = phe->event; - - nxt_debug(ev->task, "poll: fd:%d ev:%04uXi rd:%d %wr:%d", - fd, events, ev->read, ev->write); - - if (nxt_slow_path((events & POLLNVAL) != 0)) { - nxt_log(ev->task, NXT_LOG_CRIT, - "poll() error fd:%d ev:%04Xd rev:%04uXi", - fd, pfd->events, events); - - /* Mark the poll entry to ignore it by the kernel. */ - pfd->fd = -1; - - nxt_work_queue_add(&ev->task->thread->engine->fast_work_queue, - ev->error_handler, - ev->task, ev, ev->data); - goto next; - } - - /* - * On a socket's remote end close: - * - * Linux, FreeBSD, and Solaris set POLLIN; - * MacOSX sets POLLIN and POLLHUP; - * NetBSD sets POLLIN, and poll(2) claims this explicitly: - * - * If the remote end of a socket is closed, poll() - * returns a POLLIN event, rather than a POLLHUP. - * - * On error: - * - * Linux sets POLLHUP and POLLERR only; - * FreeBSD adds POLLHUP to POLLIN or POLLOUT, although poll(2) - * claims the opposite: - * - * Note that POLLHUP and POLLOUT should never be - * present in the revents bitmask at the same time. - * - * Solaris and NetBSD do not add POLLHUP or POLLERR; - * MacOSX sets POLLHUP only. - * - * If an implementation sets POLLERR or POLLHUP only without POLLIN - * or POLLOUT, the "error" variable enqueues only one active handler. - */ - - error = (((events & (POLLERR | POLLHUP)) != 0) - && ((events & (POLLIN | POLLOUT)) == 0)); - - if ((events & POLLIN) || (error && ev->read_handler != NULL)) { - error = 0; - ev->read_ready = 1; - - if (ev->read == NXT_EVENT_ONESHOT) { - ev->read = NXT_EVENT_INACTIVE; - nxt_poll_change(event_set, ev, NXT_POLL_DELETE, 0); - } - - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - } - - if ((events & POLLOUT) || (error && ev->write_handler != NULL)) { - ev->write_ready = 1; - - if (ev->write == NXT_EVENT_ONESHOT) { - ev->write = NXT_EVENT_INACTIVE; - nxt_poll_change(event_set, ev, NXT_POLL_DELETE, 0); - } - - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - } - - next: - - nevents--; - } -} - - -static nxt_poll_hash_entry_t * -nxt_poll_fd_hash_get(nxt_poll_event_set_t *ps, nxt_fd_t fd) -{ - nxt_lvlhsh_query_t lhq; - nxt_poll_hash_entry_t *phe; - - lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); - lhq.key.length = sizeof(nxt_fd_t); - lhq.key.start = (u_char *) &fd; - lhq.proto = &nxt_poll_fd_hash_proto; - lhq.data = ps->poll_set; - - if (nxt_lvlhsh_find(&ps->fd_hash, &lhq) == NXT_OK) { - phe = lhq.value; - return phe; - } - - nxt_thread_log_alert("fd %d not found in hash", fd); - - return NULL; -} - - -static nxt_int_t -nxt_poll_fd_hash_test(nxt_lvlhsh_query_t *lhq, void *data) -{ - struct pollfd *poll_set; - nxt_poll_hash_entry_t *phe; - - phe = data; - - if (*(nxt_fd_t *) lhq->key.start == phe->fd) { - poll_set = lhq->data; - - if (nxt_fast_path(phe->fd == poll_set[phe->index].fd)) { - return NXT_OK; - } - - nxt_thread_log_alert("fd %d in hash mismatches fd %d in poll set", - phe->fd, poll_set[phe->index].fd); - } - - return NXT_DECLINED; -} - - -static void -nxt_poll_fd_hash_destroy(nxt_lvlhsh_t *lh) -{ - nxt_lvlhsh_each_t lhe; - nxt_lvlhsh_query_t lhq; - nxt_poll_hash_entry_t *phe; - - nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t)); - lhe.proto = &nxt_poll_fd_hash_proto; - lhq.proto = &nxt_poll_fd_hash_proto; - - for ( ;; ) { - phe = nxt_lvlhsh_each(lh, &lhe); - - if (phe == NULL) { - return; - } - - lhq.key_hash = nxt_murmur_hash2(&phe->fd, sizeof(nxt_fd_t)); - lhq.key.length = sizeof(nxt_fd_t); - lhq.key.start = (u_char *) &phe->fd; - - if (nxt_lvlhsh_delete(lh, &lhq) != NXT_OK) { - nxt_thread_log_alert("event fd %d not found in hash", phe->fd); - } - - nxt_free(phe); - } -} diff --git a/src/nxt_poll_engine.c b/src/nxt_poll_engine.c new file mode 100644 index 00000000..90a8176e --- /dev/null +++ b/src/nxt_poll_engine.c @@ -0,0 +1,710 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +#define NXT_POLL_ADD 0 +#define NXT_POLL_CHANGE 1 +#define NXT_POLL_DELETE 2 + + +typedef struct { + /* + * A file descriptor is stored in hash entry to allow + * nxt_poll_fd_hash_test() to not dereference a pointer to + * nxt_fd_event_t which may be invalid if the file descriptor has + * been already closed and the nxt_fd_event_t's memory has been freed. + */ + nxt_socket_t fd; + + uint32_t index; + void *event; +} nxt_poll_hash_entry_t; + + +static nxt_int_t nxt_poll_create(nxt_event_engine_t *engine, + nxt_uint_t mchanges, nxt_uint_t mevents); +static void nxt_poll_free(nxt_event_engine_t *engine); +static void nxt_poll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_poll_disable(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static nxt_bool_t nxt_poll_close(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_enable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_enable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_disable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_disable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_poll_block_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_oneshot_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_oneshot_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_poll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, + nxt_uint_t op, nxt_uint_t events); +static nxt_int_t nxt_poll_commit_changes(nxt_event_engine_t *engine); +static nxt_int_t nxt_poll_set_add(nxt_event_engine_t *engine, + nxt_fd_event_t *ev, int events); +static nxt_int_t nxt_poll_set_change(nxt_event_engine_t *engine, + nxt_fd_t fd, int events); +static nxt_int_t nxt_poll_set_delete(nxt_event_engine_t *engine, nxt_fd_t fd); +static void nxt_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); +static nxt_poll_hash_entry_t *nxt_poll_fd_hash_get(nxt_event_engine_t *engine, + nxt_fd_t fd); +static nxt_int_t nxt_poll_fd_hash_test(nxt_lvlhsh_query_t *lhq, void *data); +static void nxt_poll_fd_hash_destroy(nxt_event_engine_t *engine, + nxt_lvlhsh_t *lh); + + +const nxt_event_interface_t nxt_poll_engine = { + "poll", + nxt_poll_create, + nxt_poll_free, + nxt_poll_enable, + nxt_poll_disable, + nxt_poll_disable, + nxt_poll_close, + nxt_poll_enable_read, + nxt_poll_enable_write, + nxt_poll_disable_read, + nxt_poll_disable_write, + nxt_poll_block_read, + nxt_poll_block_write, + nxt_poll_oneshot_read, + nxt_poll_oneshot_write, + nxt_poll_enable_read, + NULL, + NULL, + NULL, + NULL, + nxt_poll, + + &nxt_unix_event_conn_io, + + NXT_NO_FILE_EVENTS, + NXT_NO_SIGNAL_EVENTS, +}; + + +static const nxt_lvlhsh_proto_t nxt_poll_fd_hash_proto nxt_aligned(64) = +{ + NXT_LVLHSH_LARGE_MEMALIGN, + 0, + nxt_poll_fd_hash_test, + nxt_lvlhsh_alloc, + nxt_lvlhsh_free, +}; + + +static nxt_int_t +nxt_poll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, + nxt_uint_t mevents) +{ + engine->u.poll.mchanges = mchanges; + + engine->u.poll.changes = nxt_malloc(sizeof(nxt_poll_change_t) * mchanges); + + if (engine->u.poll.changes != NULL) { + return NXT_OK; + } + + return NXT_ERROR; +} + + +static void +nxt_poll_free(nxt_event_engine_t *engine) +{ + nxt_debug(&engine->task, "poll free"); + + nxt_free(engine->u.poll.set); + nxt_free(engine->u.poll.changes); + nxt_poll_fd_hash_destroy(engine, &engine->u.poll.fd_hash); + + nxt_memzero(&engine->u.poll, sizeof(nxt_poll_engine_t)); +} + + +static void +nxt_poll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_ACTIVE; + ev->write = NXT_EVENT_ACTIVE; + + nxt_poll_change(engine, ev, NXT_POLL_ADD, POLLIN | POLLOUT); +} + + +static void +nxt_poll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE && ev->write != NXT_EVENT_INACTIVE) { + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + nxt_poll_change(engine, ev, NXT_POLL_DELETE, 0); + } +} + + +static nxt_bool_t +nxt_poll_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_poll_disable(engine, ev); + + return ev->changing; +} + + +static void +nxt_poll_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->read = NXT_EVENT_ACTIVE; + + if (ev->write == NXT_EVENT_INACTIVE) { + op = NXT_POLL_ADD; + events = POLLIN; + + } else { + op = NXT_POLL_CHANGE; + events = POLLIN | POLLOUT; + } + + nxt_poll_change(engine, ev, op, events); +} + + +static void +nxt_poll_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->write = NXT_EVENT_ACTIVE; + + if (ev->read == NXT_EVENT_INACTIVE) { + op = NXT_POLL_ADD; + events = POLLOUT; + + } else { + op = NXT_POLL_CHANGE; + events = POLLIN | POLLOUT; + } + + nxt_poll_change(engine, ev, op, events); +} + + +static void +nxt_poll_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->read = NXT_EVENT_INACTIVE; + + if (ev->write == NXT_EVENT_INACTIVE) { + op = NXT_POLL_DELETE; + events = 0; + + } else { + op = NXT_POLL_CHANGE; + events = POLLOUT; + } + + nxt_poll_change(engine, ev, op, events); +} + + +static void +nxt_poll_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->write = NXT_EVENT_INACTIVE; + + if (ev->read == NXT_EVENT_INACTIVE) { + op = NXT_POLL_DELETE; + events = 0; + + } else { + op = NXT_POLL_CHANGE; + events = POLLIN; + } + + nxt_poll_change(engine, ev, op, events); +} + + +static void +nxt_poll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE) { + nxt_poll_disable_read(engine, ev); + } +} + + +static void +nxt_poll_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->write != NXT_EVENT_INACTIVE) { + nxt_poll_disable_write(engine, ev); + } +} + + +static void +nxt_poll_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op; + + op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? + NXT_POLL_ADD : NXT_POLL_CHANGE; + + ev->read = NXT_EVENT_ONESHOT; + ev->write = NXT_EVENT_INACTIVE; + + nxt_poll_change(engine, ev, op, POLLIN); +} + + +static void +nxt_poll_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op; + + op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ? + NXT_POLL_ADD : NXT_POLL_CHANGE; + + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_ONESHOT; + + nxt_poll_change(engine, ev, op, POLLOUT); +} + + +/* + * poll changes are batched to improve instruction and data cache + * locality of several lvlhsh operations followed by poll() call. + */ + +static void +nxt_poll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, nxt_uint_t op, + nxt_uint_t events) +{ + nxt_poll_change_t *change; + + nxt_debug(ev->task, "poll change: fd:%d op:%d ev:%XD", ev->fd, op, events); + + if (engine->u.poll.nchanges >= engine->u.poll.mchanges) { + (void) nxt_poll_commit_changes(engine); + } + + ev->changing = 1; + + change = &engine->u.poll.changes[engine->u.poll.nchanges++]; + change->op = op; + change->events = events; + change->event = ev; +} + + +static nxt_int_t +nxt_poll_commit_changes(nxt_event_engine_t *engine) +{ + nxt_int_t ret, retval; + nxt_fd_event_t *ev; + nxt_poll_change_t *change, *end; + + nxt_debug(&engine->task, "poll changes:%ui", engine->u.poll.nchanges); + + retval = NXT_OK; + change = engine->u.poll.changes; + end = change + engine->u.poll.nchanges; + + do { + ev = change->event; + ev->changing = 0; + + switch (change->op) { + + case NXT_POLL_ADD: + ret = nxt_poll_set_add(engine, ev, change->events); + + if (nxt_fast_path(ret == NXT_OK)) { + goto next; + } + + break; + + case NXT_POLL_CHANGE: + ret = nxt_poll_set_change(engine, ev->fd, change->events); + + if (nxt_fast_path(ret == NXT_OK)) { + goto next; + } + + break; + + case NXT_POLL_DELETE: + ret = nxt_poll_set_delete(engine, ev->fd); + + if (nxt_fast_path(ret == NXT_OK)) { + goto next; + } + + break; + } + + nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, + ev->task, ev, ev->data); + + retval = NXT_ERROR; + + next: + + change++; + + } while (change < end); + + engine->u.poll.nchanges = 0; + + return retval; +} + + +static nxt_int_t +nxt_poll_set_add(nxt_event_engine_t *engine, nxt_fd_event_t *ev, int events) +{ + nxt_int_t ret; + nxt_uint_t max_nfds; + struct pollfd *pfd; + nxt_lvlhsh_query_t lhq; + nxt_poll_hash_entry_t *phe; + + nxt_debug(&engine->task, "poll add event: fd:%d ev:%04Xi", ev->fd, events); + + if (engine->u.poll.nfds >= engine->u.poll.max_nfds) { + max_nfds = engine->u.poll.max_nfds + 512; /* 4K */ + + pfd = nxt_realloc(engine->u.poll.set, sizeof(struct pollfd) * max_nfds); + if (nxt_slow_path(pfd == NULL)) { + return NXT_ERROR; + } + + engine->u.poll.set = pfd; + engine->u.poll.max_nfds = max_nfds; + } + + phe = nxt_malloc(sizeof(nxt_poll_hash_entry_t)); + if (nxt_slow_path(phe == NULL)) { + return NXT_ERROR; + } + + phe->fd = ev->fd; + phe->index = engine->u.poll.nfds; + phe->event = ev; + + pfd = &engine->u.poll.set[engine->u.poll.nfds++]; + pfd->fd = ev->fd; + pfd->events = events; + pfd->revents = 0; + + lhq.key_hash = nxt_murmur_hash2(&ev->fd, sizeof(nxt_fd_t)); + lhq.replace = 0; + lhq.value = phe; + lhq.proto = &nxt_poll_fd_hash_proto; + lhq.data = engine; + + ret = nxt_lvlhsh_insert(&engine->u.poll.fd_hash, &lhq); + + if (nxt_fast_path(ret == NXT_OK)) { + return NXT_OK; + } + + nxt_free(phe); + + return NXT_ERROR; +} + + +static nxt_int_t +nxt_poll_set_change(nxt_event_engine_t *engine, nxt_fd_t fd, int events) +{ + nxt_poll_hash_entry_t *phe; + + nxt_debug(&engine->task, "poll change event: fd:%d ev:%04Xi", + fd, events); + + phe = nxt_poll_fd_hash_get(engine, fd); + + if (nxt_fast_path(phe != NULL)) { + engine->u.poll.set[phe->index].events = events; + return NXT_OK; + } + + return NXT_ERROR; +} + + +static nxt_int_t +nxt_poll_set_delete(nxt_event_engine_t *engine, nxt_fd_t fd) +{ + nxt_int_t ret; + nxt_uint_t index, nfds; + nxt_lvlhsh_query_t lhq; + nxt_poll_hash_entry_t *phe; + + nxt_debug(&engine->task, "poll delete event: fd:%d", fd); + + lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); + lhq.proto = &nxt_poll_fd_hash_proto; + lhq.data = engine; + + ret = nxt_lvlhsh_delete(&engine->u.poll.fd_hash, &lhq); + + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + phe = lhq.value; + + index = phe->index; + engine->u.poll.nfds--; + nfds = engine->u.poll.nfds; + + if (index != nfds) { + engine->u.poll.set[index] = engine->u.poll.set[nfds]; + + phe = nxt_poll_fd_hash_get(engine, engine->u.poll.set[nfds].fd); + + phe->index = index; + } + + nxt_free(lhq.value); + + return NXT_OK; +} + + +static void +nxt_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) +{ + int nevents; + nxt_fd_t fd; + nxt_err_t err; + nxt_bool_t error; + nxt_uint_t i, events, level; + struct pollfd *pfd; + nxt_fd_event_t *ev; + nxt_poll_hash_entry_t *phe; + + if (engine->u.poll.nchanges != 0) { + if (nxt_poll_commit_changes(engine) != NXT_OK) { + /* Error handlers have been enqueued on failure. */ + timeout = 0; + } + } + + nxt_debug(&engine->task, "poll() events:%ui timeout:%M", + engine->u.poll.nfds, timeout); + + nevents = poll(engine->u.poll.set, engine->u.poll.nfds, timeout); + + err = (nevents == -1) ? nxt_errno : 0; + + nxt_thread_time_update(engine->task.thread); + + nxt_debug(&engine->task, "poll(): %d", nevents); + + if (nevents == -1) { + level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; + nxt_log(&engine->task, level, "poll() failed %E", err); + return; + } + + for (i = 0; i < engine->u.poll.nfds && nevents != 0; i++) { + + pfd = &engine->u.poll.set[i]; + events = pfd->revents; + + if (events == 0) { + continue; + } + + fd = pfd->fd; + + phe = nxt_poll_fd_hash_get(engine, fd); + + if (nxt_slow_path(phe == NULL)) { + nxt_log(&engine->task, NXT_LOG_CRIT, + "poll() returned invalid fd:%d ev:%04Xd rev:%04uXi", + fd, pfd->events, events); + + /* Mark the poll entry to ignore it by the kernel. */ + pfd->fd = -1; + goto next; + } + + ev = phe->event; + + nxt_debug(ev->task, "poll: fd:%d ev:%04uXi rd:%d %wr:%d", + fd, events, ev->read, ev->write); + + if (nxt_slow_path((events & POLLNVAL) != 0)) { + nxt_log(ev->task, NXT_LOG_CRIT, + "poll() error fd:%d ev:%04Xd rev:%04uXi", + fd, pfd->events, events); + + /* Mark the poll entry to ignore it by the kernel. */ + pfd->fd = -1; + + nxt_work_queue_add(&engine->fast_work_queue, + ev->error_handler, ev->task, ev, ev->data); + goto next; + } + + /* + * On a socket's remote end close: + * + * Linux, FreeBSD, and Solaris set POLLIN; + * MacOSX sets POLLIN and POLLHUP; + * NetBSD sets POLLIN, and poll(2) claims this explicitly: + * + * If the remote end of a socket is closed, poll() + * returns a POLLIN event, rather than a POLLHUP. + * + * On error: + * + * Linux sets POLLHUP and POLLERR only; + * FreeBSD adds POLLHUP to POLLIN or POLLOUT, although poll(2) + * claims the opposite: + * + * Note that POLLHUP and POLLOUT should never be + * present in the revents bitmask at the same time. + * + * Solaris and NetBSD do not add POLLHUP or POLLERR; + * MacOSX sets POLLHUP only. + * + * If an implementation sets POLLERR or POLLHUP only without POLLIN + * or POLLOUT, the "error" variable enqueues only one active handler. + */ + + error = (((events & (POLLERR | POLLHUP)) != 0) + && ((events & (POLLIN | POLLOUT)) == 0)); + + if ((events & POLLIN) || (error && ev->read_handler != NULL)) { + error = 0; + ev->read_ready = 1; + + if (ev->read == NXT_EVENT_ONESHOT) { + ev->read = NXT_EVENT_INACTIVE; + nxt_poll_change(engine, ev, NXT_POLL_DELETE, 0); + } + + nxt_work_queue_add(ev->read_work_queue, ev->read_handler, + ev->task, ev, ev->data); + } + + if ((events & POLLOUT) || (error && ev->write_handler != NULL)) { + ev->write_ready = 1; + + if (ev->write == NXT_EVENT_ONESHOT) { + ev->write = NXT_EVENT_INACTIVE; + nxt_poll_change(engine, ev, NXT_POLL_DELETE, 0); + } + + nxt_work_queue_add(ev->write_work_queue, ev->write_handler, + ev->task, ev, ev->data); + } + + next: + + nevents--; + } +} + + +static nxt_poll_hash_entry_t * +nxt_poll_fd_hash_get(nxt_event_engine_t *engine, nxt_fd_t fd) +{ + nxt_lvlhsh_query_t lhq; + nxt_poll_hash_entry_t *phe; + + lhq.key_hash = nxt_murmur_hash2(&fd, sizeof(nxt_fd_t)); + lhq.proto = &nxt_poll_fd_hash_proto; + lhq.data = engine; + + if (nxt_lvlhsh_find(&engine->u.poll.fd_hash, &lhq) == NXT_OK) { + phe = lhq.value; + return phe; + } + + nxt_log(&engine->task, NXT_LOG_CRIT, "fd %d not found in hash", fd); + + return NULL; +} + + +static nxt_int_t +nxt_poll_fd_hash_test(nxt_lvlhsh_query_t *lhq, void *data) +{ + nxt_event_engine_t *engine; + nxt_poll_hash_entry_t *phe; + + phe = data; + + /* nxt_murmur_hash2() is unique for 4 bytes. */ + + engine = lhq->data; + + if (nxt_fast_path(phe->fd == engine->u.poll.set[phe->index].fd)) { + return NXT_OK; + } + + nxt_log(&engine->task, NXT_LOG_CRIT, + "fd %d in hash mismatches fd %d in poll set", + phe->fd, engine->u.poll.set[phe->index].fd); + + return NXT_DECLINED; +} + + +static void +nxt_poll_fd_hash_destroy(nxt_event_engine_t *engine, nxt_lvlhsh_t *lh) +{ + nxt_lvlhsh_each_t lhe; + nxt_lvlhsh_query_t lhq; + nxt_poll_hash_entry_t *phe; + + nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t)); + lhe.proto = &nxt_poll_fd_hash_proto; + lhq.proto = &nxt_poll_fd_hash_proto; + + for ( ;; ) { + phe = nxt_lvlhsh_each(lh, &lhe); + + if (phe == NULL) { + return; + } + + lhq.key_hash = nxt_murmur_hash2(&phe->fd, sizeof(nxt_fd_t)); + + if (nxt_lvlhsh_delete(lh, &lhq) != NXT_OK) { + nxt_log(&engine->task, NXT_LOG_CRIT, + "event fd %d not found in hash", phe->fd); + } + + nxt_free(phe); + } +} diff --git a/src/nxt_pollset.c b/src/nxt_pollset.c deleted file mode 100644 index 8d05e560..00000000 --- a/src/nxt_pollset.c +++ /dev/null @@ -1,627 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -/* - * pollset has been introduced in AIX 5L 5.3. - * - * pollset_create() returns a pollset_t descriptor which is not - * a file descriptor, so it cannot be added to another pollset. - * The first pollset_create() call returns 0. - */ - - -#define NXT_POLLSET_ADD 0 -#define NXT_POLLSET_UPDATE 1 -#define NXT_POLLSET_CHANGE 2 -#define NXT_POLLSET_DELETE 3 - - -static nxt_event_set_t *nxt_pollset_create(nxt_event_signals_t *signals, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_pollset_free(nxt_event_set_t *event_set); -static void nxt_pollset_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_pollset_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_pollset_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_block_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_pollset_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t op, nxt_uint_t events); -static nxt_int_t nxt_pollset_commit_changes(nxt_thread_t *thr, - nxt_pollset_event_set_t *ps); -static void nxt_pollset_change_error(nxt_thread_t *thr, - nxt_pollset_event_set_t *ps, nxt_event_fd_t *ev); -static void nxt_pollset_remove(nxt_thread_t *thr, nxt_pollset_event_set_t *ps, - nxt_fd_t fd); -static nxt_int_t nxt_pollset_write(nxt_thread_t *thr, int pollset, - struct poll_ctl *ctl, int n); -static void nxt_pollset_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout); - - -const nxt_event_set_ops_t nxt_pollset_event_set = { - "pollset", - nxt_pollset_create, - nxt_pollset_free, - nxt_pollset_enable, - nxt_pollset_disable, - nxt_pollset_disable, - nxt_pollset_disable, - nxt_pollset_enable_read, - nxt_pollset_enable_write, - nxt_pollset_disable_read, - nxt_pollset_disable_write, - nxt_pollset_block_read, - nxt_pollset_block_write, - nxt_pollset_oneshot_read, - nxt_pollset_oneshot_write, - nxt_pollset_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_pollset_poll, - - &nxt_unix_event_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_event_set_t * -nxt_pollset_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - nxt_event_set_t *event_set; - nxt_pollset_event_set_t *ps; - - event_set = nxt_zalloc(sizeof(nxt_pollset_event_set_t)); - if (event_set == NULL) { - return NULL; - } - - ps = &event_set->pollset; - - ps->pollset = -1; - ps->mchanges = mchanges; - ps->mevents = mevents; - - ps->pollset_changes = nxt_malloc(sizeof(nxt_pollset_change_t) * mchanges); - if (ps->pollset_changes == NULL) { - goto fail; - } - - /* - * NXT_POLLSET_CHANGE requires two struct poll_ctl's - * for PS_DELETE and subsequent PS_ADD. - */ - ps->changes = nxt_malloc(2 * sizeof(struct poll_ctl) * mchanges); - if (ps->changes == NULL) { - goto fail; - } - - ps->events = nxt_malloc(sizeof(struct pollfd) * mevents); - if (ps->events == NULL) { - goto fail; - } - - ps->pollset = pollset_create(-1); - if (ps->pollset == -1) { - nxt_main_log_emerg("pollset_create() failed %E", nxt_errno); - goto fail; - } - - nxt_main_log_debug("pollset_create(): %d", ps->pollset); - - return event_set; - -fail: - - nxt_pollset_free(event_set); - - return NULL; -} - - -static void -nxt_pollset_free(nxt_event_set_t *event_set) -{ - nxt_pollset_event_set_t *ps; - - ps = &event_set->pollset; - - nxt_main_log_debug("pollset %d free", ps->pollset); - - if (ps->pollset != -1) { - if (pollset_destroy(ps->pollset) != 0) { - nxt_main_log_emerg("pollset_destroy(%d) failed %E", - ps->pollset, nxt_errno); - } - } - - nxt_free(ps->events); - nxt_free(ps->changes); - nxt_free(ps->pollset_changes); - nxt_event_set_fd_hash_destroy(&ps->fd_hash); - nxt_free(ps); -} - - -static void -nxt_pollset_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_DEFAULT; - ev->write = NXT_EVENT_DEFAULT; - - nxt_pollset_change(event_set, ev, NXT_POLLSET_ADD, POLLIN | POLLOUT); -} - - -/* - * A closed descriptor must be deleted from a pollset, otherwise next - * pollset_poll() will return POLLNVAL on it. However, pollset_ctl() - * allows to delete the already closed file descriptor from the pollset - * using PS_DELETE, so the removal can be batched, pollset_ctl(2): - * - * After a file descriptor is added to a pollset, the file descriptor will - * not be removed until a pollset_ctl call with the cmd of PS_DELETE is - * executed. The file descriptor remains in the pollset even if the file - * descriptor is closed. A pollset_poll operation on a pollset containing - * a closed file descriptor returns a POLLNVAL event for that file - * descriptor. If the file descriptor is later allocated to a new object, - * the new object will be polled on future pollset_poll calls. - */ - -static void -nxt_pollset_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_pollset_change(event_set, ev, NXT_POLLSET_DELETE, 0); - } -} - - -static void -nxt_pollset_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - if (ev->read != NXT_EVENT_BLOCKED) { - - events = POLLIN; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_POLLSET_ADD; - - } else if (ev->write == NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_CHANGE; - - } else { - op = NXT_POLLSET_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_pollset_change(event_set, ev, op, events); - } - - ev->read = NXT_EVENT_DEFAULT; -} - - -static void -nxt_pollset_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - if (ev->write != NXT_EVENT_BLOCKED) { - - events = POLLOUT; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_POLLSET_ADD; - - } else if (ev->read == NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_CHANGE; - - } else { - op = NXT_POLLSET_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_pollset_change(event_set, ev, op, events); - } - - ev->write = NXT_EVENT_DEFAULT; -} - - -static void -nxt_pollset_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write <= NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_POLLSET_CHANGE; - events = POLLOUT; - } - - nxt_pollset_change(event_set, ev, op, events); -} - - -static void -nxt_pollset_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read <= NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_POLLSET_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_POLLSET_CHANGE; - events = POLLIN; - } - - nxt_pollset_change(event_set, ev, op, events); -} - - -static void -nxt_pollset_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_pollset_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_pollset_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_pollset_enable_read(event_set, ev); - - ev->read = NXT_EVENT_ONESHOT; -} - - -static void -nxt_pollset_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_pollset_enable_write(event_set, ev); - - ev->write = NXT_EVENT_ONESHOT; -} - - -/* - * PS_ADD adds only a new file descriptor to a pollset. - * PS_DELETE removes a file descriptor from a pollset. - * - * PS_MOD can add a new file descriptor or modify events for a file - * descriptor which is already in a pollset. However, modified events - * are always ORed, so to delete an event for a file descriptor, - * the file descriptor must be removed using PS_DELETE and then - * added again without the event. - */ - -static void -nxt_pollset_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t op, nxt_uint_t events) -{ - nxt_pollset_change_t *ch; - nxt_pollset_event_set_t *ps; - - ps = &event_set->pollset; - - nxt_log_debug(ev->log, "pollset %d change fd:%d op:%ui ev:%04Xi", - ps->pollset, ev->fd, op, events); - - if (ps->nchanges >= ps->mchanges) { - (void) nxt_pollset_commit_changes(nxt_thread(), ps); - } - - ch = &ps->pollset_changes[ps->nchanges++]; - ch->op = op; - ch->cmd = (op == NXT_POLLSET_DELETE) ? PS_DELETE : PS_MOD; - ch->fd = ev->fd; - ch->events = events; - ch->event = ev; -} - - -static nxt_int_t -nxt_pollset_commit_changes(nxt_thread_t *thr, nxt_pollset_event_set_t *ps) -{ - size_t n; - nxt_int_t ret, retval; - struct poll_ctl *ctl; - nxt_pollset_change_t *ch, *end; - - nxt_log_debug(thr->log, "pollset %d changes:%ui", - ps->pollset, ps->nchanges); - - retval = NXT_OK; - n = 0; - ch = ps->pollset_changes; - end = ch + ps->nchanges; - - do { - nxt_log_debug(thr->log, "pollset fd:%d op:%d ev:%04Xd", - ch->fd, ch->op, ch->events); - - if (ch->op == NXT_POLLSET_CHANGE) { - ctl = &ps->changes[n++]; - ctl->cmd = PS_DELETE; - ctl->events = 0; - ctl->fd = ch->fd; - } - - ctl = &ps->changes[n++]; - ctl->cmd = ch->cmd; - ctl->events = ch->events; - ctl->fd = ch->fd; - - ch++; - - } while (ch < end); - - ch = ps->pollset_changes; - end = ch + ps->nchanges; - - ret = nxt_pollset_write(thr, ps->pollset, ps->changes, n); - - if (nxt_slow_path(ret != NXT_OK)) { - do { - nxt_pollset_change_error(thr, ps, ch->event); - ch++; - } while (ch < end); - - ps->nchanges = 0; - - return NXT_ERROR; - } - - do { - if (ch->op == NXT_POLLSET_ADD) { - ret = nxt_event_set_fd_hash_add(&ps->fd_hash, ch->fd, ch->event); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_pollset_change_error(thr, ps, ch->event); - retval = NXT_ERROR; - } - - } else if (ch->op == NXT_POLLSET_DELETE) { - nxt_event_set_fd_hash_delete(&ps->fd_hash, ch->fd, 0); - } - - /* Nothing to do for NXT_POLLSET_UPDATE and NXT_POLLSET_CHANGE. */ - - ch++; - - } while (ch < end); - - ps->nchanges = 0; - - return retval; -} - - -static void -nxt_pollset_change_error(nxt_thread_t *thr, nxt_pollset_event_set_t *ps, - nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - ev->error_handler, ev, ev->data, ev->log); - - nxt_event_set_fd_hash_delete(&ps->fd_hash, ev->fd, 1); - - nxt_pollset_remove(thr, ps, ev->fd); -} - - -static void -nxt_pollset_remove(nxt_thread_t *thr, nxt_pollset_event_set_t *ps, nxt_fd_t fd) -{ - int n; - struct pollfd pfd; - struct poll_ctl ctl; - - pfd.fd = fd; - pfd.events = 0; - pfd.revents = 0; - - n = pollset_query(ps->pollset, &pfd); - - nxt_thread_log_debug("pollset_query(%d, %d): %d", ps->pollset, fd, n); - - if (n == 0) { - /* The file descriptor is not in the pollset. */ - return; - } - - if (n == -1) { - nxt_thread_log_alert("pollset_query(%d, %d) failed %E", - ps->pollset, fd, nxt_errno); - /* Fall through. */ - } - - /* n == 1: The file descriptor is in the pollset. */ - - nxt_thread_log_debug("pollset %d remove fd:%d", ps->pollset, fd); - - ctl.cmd = PS_DELETE; - ctl.events = 0; - ctl.fd = fd; - - nxt_pollset_write(thr, ps->pollset, &ctl, 1); -} - - -static nxt_int_t -nxt_pollset_write(nxt_thread_t *thr, int pollset, struct poll_ctl *ctl, int n) -{ - nxt_thread_log_debug("pollset_ctl(%d) changes:%d", pollset, n); - - nxt_set_errno(0); - - n = pollset_ctl(pollset, ctl, n); - - if (nxt_fast_path(n == 0)) { - return NXT_OK; - } - - nxt_log_alert(thr->log, "pollset_ctl(%d) failed: %d %E", - pollset, n, nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_pollset_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout) -{ - int nevents; - nxt_fd_t fd; - nxt_int_t i; - nxt_err_t err; - nxt_uint_t events, level; - struct pollfd *pfd; - nxt_event_fd_t *ev; - nxt_pollset_event_set_t *ps; - - ps = &event_set->pollset; - - if (ps->nchanges != 0) { - if (nxt_pollset_commit_changes(thr, ps) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - nxt_log_debug(thr->log, "pollset_poll(%d) timeout:%M", - ps->pollset, timeout); - - nevents = pollset_poll(ps->pollset, ps->events, ps->mevents, timeout); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(thr); - - nxt_log_debug(thr->log, "pollset_poll(%d): %d", ps->pollset, nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log_error(level, thr->log, "pollset_poll(%d) failed %E", - ps->pollset, err); - return; - } - - for (i = 0; i < nevents; i++) { - - pfd = &ps->events[i]; - fd = pfd->fd; - events = pfd->revents; - - ev = nxt_event_set_fd_hash_get(&ps->fd_hash, fd); - - if (nxt_slow_path(ev == NULL)) { - nxt_log_alert(thr->log, "pollset_poll(%d) returned invalid " - "fd:%d ev:%04Xd rev:%04uXi", - ps->pollset, fd, pfd->events, events); - - nxt_pollset_remove(thr, ps, fd); - continue; - } - - nxt_log_debug(ev->log, "pollset: fd:%d ev:%04uXi", fd, events); - - if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { - nxt_log_alert(ev->log, - "pollset_poll(%d) error fd:%d ev:%04Xd rev:%04uXi", - ps->pollset, fd, pfd->events, events); - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - ev->error_handler, ev, ev->data, ev->log); - continue; - } - - if (events & POLLIN) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - - if (ev->read == NXT_EVENT_ONESHOT) { - nxt_pollset_disable_read(event_set, ev); - } - - nxt_thread_work_queue_add(thr, ev->read_work_queue, - ev->read_handler, - ev, ev->data, ev->log); - } - } - - if (events & POLLOUT) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - - if (ev->write == NXT_EVENT_ONESHOT) { - nxt_pollset_disable_write(event_set, ev); - } - - nxt_thread_work_queue_add(thr, ev->write_work_queue, - ev->write_handler, - ev, ev->data, ev->log); - } - } - } -} diff --git a/src/nxt_pollset_engine.c b/src/nxt_pollset_engine.c new file mode 100644 index 00000000..571ad794 --- /dev/null +++ b/src/nxt_pollset_engine.c @@ -0,0 +1,647 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* + * pollset has been introduced in AIX 5L 5.3. + * + * pollset_create() returns a pollset_t descriptor which is not + * a file descriptor, so it cannot be added to another pollset. + * The first pollset_create() call returns 0. + */ + + +#define NXT_POLLSET_ADD 0 +#define NXT_POLLSET_UPDATE 1 +#define NXT_POLLSET_CHANGE 2 +#define NXT_POLLSET_DELETE 3 + + +static nxt_int_t nxt_pollset_create(nxt_event_engine_t *engine, + nxt_uint_t mchanges, nxt_uint_t mevents); +static void nxt_pollset_free(nxt_event_engine_t *engine); +static void nxt_pollset_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_pollset_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static nxt_bool_t nxt_pollset_close(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_enable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_enable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_disable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_disable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_block_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_block_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_oneshot_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_oneshot_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, + nxt_uint_t op, nxt_uint_t events); +static nxt_int_t nxt_pollset_commit_changes(nxt_event_engine_t *engine); +static void nxt_pollset_change_error(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_pollset_remove(nxt_event_engine_t *engine, nxt_fd_t fd); +static nxt_int_t nxt_pollset_write(nxt_event_engine_t *engine, + struct poll_ctl *ctl, int n); +static void nxt_pollset_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); + + +const nxt_event_interface_t nxt_pollset_engine = { + "pollset", + nxt_pollset_create, + nxt_pollset_free, + nxt_pollset_enable, + nxt_pollset_disable, + nxt_pollset_disable, + nxt_pollset_close, + nxt_pollset_enable_read, + nxt_pollset_enable_write, + nxt_pollset_disable_read, + nxt_pollset_disable_write, + nxt_pollset_block_read, + nxt_pollset_block_write, + nxt_pollset_oneshot_read, + nxt_pollset_oneshot_write, + nxt_pollset_enable_read, + NULL, + NULL, + NULL, + NULL, + nxt_pollset_poll, + + &nxt_unix_event_conn_io, + + NXT_NO_FILE_EVENTS, + NXT_NO_SIGNAL_EVENTS, +}; + + +static nxt_int_t +nxt_pollset_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, + nxt_uint_t mevents) +{ + void *changes; + + engine->u.pollset.ps = -1; + engine->u.pollset.mchanges = mchanges; + engine->u.pollset.mevents = mevents; + + changes = nxt_malloc(sizeof(nxt_pollset_change_t) * mchanges); + if (changes == NULL) { + goto fail; + } + + engine->u.pollset.changes = changes; + + /* + * NXT_POLLSET_CHANGE requires two struct poll_ctl's + * for PS_DELETE and subsequent PS_ADD. + */ + changes = nxt_malloc(2 * sizeof(struct poll_ctl) * mchanges); + if (changes == NULL) { + goto fail; + } + + engine->u.pollset.write_changes = changes; + + engine->u.pollset.events = nxt_malloc(sizeof(struct pollfd) * mevents); + if (engine->u.pollset.events == NULL) { + goto fail; + } + + engine->u.pollset.ps = pollset_create(-1); + + if (engine->u.pollset.ps == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, "pollset_create() failed %E", + nxt_errno); + goto fail; + } + + nxt_debug(&engine->task, "pollset_create(): %d", engine->u.pollset.ps); + + return NXT_OK; + +fail: + + nxt_pollset_free(engine); + + return NXT_ERROR; +} + + +static void +nxt_pollset_free(nxt_event_engine_t *engine) +{ + pollset_t ps; + + ps = engine->u.pollset.ps; + + nxt_debug(&engine->task, "pollset %d free", ps); + + if (ps != -1 && pollset_destroy(ps) != 0) { + nxt_log(&engine->task, NXT_LOG_CRIT, "pollset_destroy(%d) failed %E", + ps, nxt_errno); + } + + nxt_free(engine->u.pollset.events); + nxt_free(engine->u.pollset.write_changes); + nxt_free(engine->u.pollset.changes); + nxt_fd_event_hash_destroy(&engine->u.pollset.fd_hash); + + nxt_memzero(&engine->u.pollset, sizeof(nxt_pollset_engine_t)); +} + + +static void +nxt_pollset_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_ACTIVE; + ev->write = NXT_EVENT_ACTIVE; + + nxt_pollset_change(engine, ev, NXT_POLLSET_ADD, POLLIN | POLLOUT); +} + + +static void +nxt_pollset_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { + + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + nxt_pollset_change(engine, ev, NXT_POLLSET_DELETE, 0); + } +} + + +/* + * A closed descriptor must be deleted from a pollset, otherwise next + * pollset_poll() will return POLLNVAL on it. However, pollset_ctl() + * allows to delete the already closed file descriptor from the pollset + * using PS_DELETE, so the removal can be batched, pollset_ctl(2): + * + * After a file descriptor is added to a pollset, the file descriptor will + * not be removed until a pollset_ctl call with the cmd of PS_DELETE is + * executed. The file descriptor remains in the pollset even if the file + * descriptor is closed. A pollset_poll operation on a pollset containing + * a closed file descriptor returns a POLLNVAL event for that file + * descriptor. If the file descriptor is later allocated to a new object, + * the new object will be polled on future pollset_poll calls. + */ + +static nxt_bool_t +nxt_pollset_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_pollset_disable(engine, ev); + + return ev->changing; +} + + +static void +nxt_pollset_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + if (ev->read != NXT_EVENT_BLOCKED) { + + events = POLLIN; + + if (ev->write == NXT_EVENT_INACTIVE) { + op = NXT_POLLSET_ADD; + + } else if (ev->write == NXT_EVENT_BLOCKED) { + ev->write = NXT_EVENT_INACTIVE; + op = NXT_POLLSET_CHANGE; + + } else { + op = NXT_POLLSET_UPDATE; + events = POLLIN | POLLOUT; + } + + nxt_pollset_change(engine, ev, op, events); + } + + ev->read = NXT_EVENT_ACTIVE; +} + + +static void +nxt_pollset_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + if (ev->write != NXT_EVENT_BLOCKED) { + + events = POLLOUT; + + if (ev->read == NXT_EVENT_INACTIVE) { + op = NXT_POLLSET_ADD; + + } else if (ev->read == NXT_EVENT_BLOCKED) { + ev->read = NXT_EVENT_INACTIVE; + op = NXT_POLLSET_CHANGE; + + } else { + op = NXT_POLLSET_UPDATE; + events = POLLIN | POLLOUT; + } + + nxt_pollset_change(engine, ev, op, events); + } + + ev->write = NXT_EVENT_ACTIVE; +} + + +static void +nxt_pollset_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->read = NXT_EVENT_INACTIVE; + + if (ev->write <= NXT_EVENT_BLOCKED) { + ev->write = NXT_EVENT_INACTIVE; + op = NXT_POLLSET_DELETE; + events = POLLREMOVE; + + } else { + op = NXT_POLLSET_CHANGE; + events = POLLOUT; + } + + nxt_pollset_change(engine, ev, op, events); +} + + +static void +nxt_pollset_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_uint_t op, events; + + ev->write = NXT_EVENT_INACTIVE; + + if (ev->read <= NXT_EVENT_BLOCKED) { + ev->read = NXT_EVENT_INACTIVE; + op = NXT_POLLSET_DELETE; + events = POLLREMOVE; + + } else { + op = NXT_POLLSET_CHANGE; + events = POLLIN; + } + + nxt_pollset_change(engine, ev, op, events); +} + + +static void +nxt_pollset_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE) { + ev->read = NXT_EVENT_BLOCKED; + } +} + + +static void +nxt_pollset_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->write != NXT_EVENT_INACTIVE) { + ev->write = NXT_EVENT_BLOCKED; + } +} + + +static void +nxt_pollset_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_pollset_enable_read(engine, ev); + + ev->read = NXT_EVENT_ONESHOT; +} + + +static void +nxt_pollset_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_pollset_enable_write(engine, ev); + + ev->write = NXT_EVENT_ONESHOT; +} + + +/* + * PS_ADD adds only a new file descriptor to a pollset. + * PS_DELETE removes a file descriptor from a pollset. + * + * PS_MOD can add a new file descriptor or modify events for a file + * descriptor which is already in a pollset. However, modified events + * are always ORed, so to delete an event for a file descriptor, + * the file descriptor must be removed using PS_DELETE and then + * added again without the event. + */ + +static void +nxt_pollset_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, + nxt_uint_t op, nxt_uint_t events) +{ + nxt_pollset_change_t *change; + + nxt_debug(ev->task, "pollset %d change fd:%d op:%ui ev:%04Xi", + engine->u.pollset.ps, ev->fd, op, events); + + if (engine->u.pollset.nchanges >= engine->u.pollset.mchanges) { + (void) nxt_pollset_commit_changes(engine); + } + + ev->changing = 1; + + change = &engine->u.pollset.changes[engine->u.pollset.nchanges++]; + change->op = op; + change->cmd = (op == NXT_POLLSET_DELETE) ? PS_DELETE : PS_MOD; + change->events = events; + change->event = ev; +} + + +static nxt_int_t +nxt_pollset_commit_changes(nxt_event_engine_t *engine) +{ + size_t n; + nxt_int_t ret, retval; + nxt_fd_event_t *ev; + struct poll_ctl *ctl, *write_changes; + nxt_pollset_change_t *change, *end; + + nxt_debug(&engine->task, "pollset %d changes:%ui", + engine->u.pollset.ps, engine->u.pollset.nchanges); + + retval = NXT_OK; + n = 0; + write_changes = engine->u.pollset.write_changes; + change = engine->u.pollset.changes; + end = change + engine->u.pollset.nchanges; + + do { + ev = change->event; + ev->changing = 0; + + nxt_debug(&engine->task, "pollset fd:%d op:%d ev:%04Xd", + ev->fd, change->op, change->events); + + if (change->op == NXT_POLLSET_CHANGE) { + ctl = &write_changes[n++]; + ctl->cmd = PS_DELETE; + ctl->events = 0; + ctl->fd = ev->fd; + } + + ctl = &write_changes[n++]; + ctl->cmd = change->cmd; + ctl->events = change->events; + ctl->fd = ev->fd; + + change++; + + } while (change < end); + + change = engine->u.pollset.changes; + end = change + engine->u.pollset.nchanges; + + ret = nxt_pollset_write(engine, write_changes, n); + + if (nxt_slow_path(ret != NXT_OK)) { + + do { + nxt_pollset_change_error(engine, change->event); + change++; + } while (change < end); + + engine->u.pollset.nchanges = 0; + + return NXT_ERROR; + } + + do { + ev = change->event; + + if (change->op == NXT_POLLSET_ADD) { + ret = nxt_fd_event_hash_add(&engine->u.pollset.fd_hash, ev->fd, ev); + + if (nxt_slow_path(ret != NXT_OK)) { + nxt_pollset_change_error(engine, ev); + retval = NXT_ERROR; + } + + } else if (change->op == NXT_POLLSET_DELETE) { + nxt_fd_event_hash_delete(&engine->task, &engine->u.pollset.fd_hash, + ev->fd, 0); + } + + /* Nothing to do for NXT_POLLSET_UPDATE and NXT_POLLSET_CHANGE. */ + + change++; + + } while (change < end); + + engine->u.pollset.nchanges = 0; + + return retval; +} + + +static void +nxt_pollset_change_error(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, + ev->task, ev, ev->data); + + nxt_fd_event_hash_delete(&engine->task, &engine->u.pollset.fd_hash, + ev->fd, 1); + + nxt_pollset_remove(engine, ev->fd); +} + + +static void +nxt_pollset_remove(nxt_event_engine_t *engine, nxt_fd_t fd) +{ + int n; + struct pollfd pfd; + struct poll_ctl ctl; + + pfd.fd = fd; + pfd.events = 0; + pfd.revents = 0; + + n = pollset_query(engine->u.pollset.ps, &pfd); + + nxt_debug(&engine->task, "pollset_query(%d, %d): %d", + engine->u.pollset.ps, fd, n); + + if (n == 0) { + /* The file descriptor is not in the pollset. */ + return; + } + + if (n == -1) { + nxt_log(&engine->task, NXT_LOG_CRIT, "pollset_query(%d, %d) failed %E", + engine->u.pollset.ps, fd, nxt_errno); + /* Fall through. */ + } + + /* n == 1: The file descriptor is in the pollset. */ + + nxt_debug(&engine->task, "pollset %d remove fd:%d", + engine->u.pollset.ps, fd); + + ctl.cmd = PS_DELETE; + ctl.events = 0; + ctl.fd = fd; + + nxt_pollset_write(engine, &ctl, 1); +} + + +static nxt_int_t +nxt_pollset_write(nxt_event_engine_t *engine, struct poll_ctl *ctl, int n) +{ + pollset_t ps; + + ps = engine->u.pollset.ps; + + nxt_debug(&engine->task, "pollset_ctl(%d) changes:%d", ps, n); + + nxt_set_errno(0); + + n = pollset_ctl(ps, ctl, n); + + if (nxt_fast_path(n == 0)) { + return NXT_OK; + } + + nxt_log(&engine->task, NXT_LOG_CRIT, "pollset_ctl(%d) failed: %d %E", + ps, n, nxt_errno); + + return NXT_ERROR; +} + + +static void +nxt_pollset_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) +{ + int nevents; + nxt_fd_t fd; + nxt_int_t i; + nxt_err_t err; + nxt_uint_t events, level; + struct pollfd *pfd; + nxt_fd_event_t *ev; + + if (engine->u.pollset.nchanges != 0) { + if (nxt_pollset_commit_changes(engine) != NXT_OK) { + /* Error handlers have been enqueued on failure. */ + timeout = 0; + } + } + + nxt_debug(&engine->task, "pollset_poll(%d) timeout:%M", + engine->u.pollset.ps, timeout); + + nevents = pollset_poll(engine->u.pollset.ps, engine->u.pollset.events, + engine->u.pollset.mevents, timeout); + + err = (nevents == -1) ? nxt_errno : 0; + + nxt_thread_time_update(engine->task.thread); + + nxt_debug(&engine->task, "pollset_poll(%d): %d", + engine->u.pollset.ps, nevents); + + if (nevents == -1) { + level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT; + + nxt_log(&engine->task, level, "pollset_poll(%d) failed %E", + engine->u.pollset.ps, err); + + return; + } + + for (i = 0; i < nevents; i++) { + + pfd = &engine->u.pollset.events[i]; + fd = pfd->fd; + events = pfd->revents; + + ev = nxt_fd_event_hash_get(&engine->task, &engine->u.pollset.fd_hash, + fd); + + if (nxt_slow_path(ev == NULL)) { + nxt_log(&engine->task, NXT_LOG_CRIT, + "pollset_poll(%d) returned invalid " + "fd:%d ev:%04Xd rev:%04uXi", + engine->u.pollset.ps, fd, pfd->events, events); + + nxt_pollset_remove(engine, fd); + continue; + } + + nxt_debug(ev->task, "pollset: fd:%d ev:%04uXi", fd, events); + + if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { + nxt_log(ev->task, NXT_LOG_CRIT, + "pollset_poll(%d) error fd:%d ev:%04Xd rev:%04uXi", + engine->u.pollset.ps, fd, pfd->events, events); + + nxt_work_queue_add(&engine->fast_work_queue, ev->error_handler, + ev->task, ev, ev->data); + continue; + } + + if (events & POLLIN) { + ev->read_ready = 1; + + if (ev->read != NXT_EVENT_BLOCKED) { + nxt_work_queue_add(ev->read_work_queue, ev->read_handler, + ev->task, ev, ev->data); + } + + if (ev->read == NXT_EVENT_BLOCKED + || ev->read == NXT_EVENT_ONESHOT) + { + nxt_pollset_disable_read(engine, ev); + } + } + + if (events & POLLOUT) { + ev->write_ready = 1; + + if (ev->write != NXT_EVENT_BLOCKED) { + nxt_work_queue_add(ev->write_work_queue, ev->write_handler, + ev->task, ev, ev->data); + } + + if (ev->write == NXT_EVENT_BLOCKED + || ev->write == NXT_EVENT_ONESHOT) + { + nxt_pollset_disable_write(engine, ev); + } + } + } +} diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index 4dc72d64..5b0c2d43 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -219,7 +219,7 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data) link = nxt_queue_first(&port->messages); if (link == nxt_queue_tail(&port->messages)) { - nxt_event_fd_block_write(task->thread->engine, &port->socket); + nxt_fd_event_block_write(task->thread->engine, &port->socket); return; } @@ -282,8 +282,8 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data) } while (port->socket.write_ready); - if (nxt_event_fd_is_disabled(port->socket.write)) { - nxt_event_fd_enable_write(task->thread->engine, &port->socket); + if (nxt_fd_event_is_disabled(port->socket.write)) { + nxt_fd_event_enable_write(task->thread->engine, &port->socket); } return; @@ -311,7 +311,7 @@ nxt_port_read_enable(nxt_task_t *task, nxt_port_t *port) port->socket.read_handler = nxt_port_read_handler; port->socket.error_handler = nxt_port_error_handler; - nxt_event_fd_enable_read(task->thread->engine, &port->socket); + nxt_fd_event_enable_read(task->thread->engine, &port->socket); } @@ -371,7 +371,7 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data) if (n == NXT_AGAIN) { nxt_port_buf_free(port, b); - nxt_event_fd_enable_read(task->thread->engine, &port->socket); + nxt_fd_event_enable_read(task->thread->engine, &port->socket); return; } diff --git a/src/nxt_port_socket.h b/src/nxt_port_socket.h index b72efeba..e3202a28 100644 --- a/src/nxt_port_socket.h +++ b/src/nxt_port_socket.h @@ -31,7 +31,7 @@ typedef void (*nxt_port_handler_t)(nxt_task_t *task, nxt_port_recv_msg_t *msg); typedef struct { /* Must be the first field. */ - nxt_event_fd_t socket; + nxt_fd_event_t socket; nxt_task_t task; diff --git a/src/nxt_select.c b/src/nxt_select.c deleted file mode 100644 index 8ee5808e..00000000 --- a/src/nxt_select.c +++ /dev/null @@ -1,390 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -static nxt_event_set_t *nxt_select_create(nxt_event_signals_t *signals, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_select_free(nxt_event_set_t *event_set); -static void nxt_select_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_select_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_select_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_error_handler(nxt_task_t *task, void *obj, void *data); -static void nxt_select_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_block_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_select_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout); - - -const nxt_event_set_ops_t nxt_select_event_set = { - "select", - nxt_select_create, - nxt_select_free, - nxt_select_enable, - nxt_select_disable, - nxt_select_disable, - nxt_select_disable, - nxt_select_enable_read, - nxt_select_enable_write, - nxt_select_disable_read, - nxt_select_disable_write, - nxt_select_block_read, - nxt_select_block_write, - nxt_select_oneshot_read, - nxt_select_oneshot_write, - nxt_select_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_select_poll, - - &nxt_unix_event_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_event_set_t * -nxt_select_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - nxt_event_set_t *event_set; - nxt_select_event_set_t *ss; - - event_set = nxt_zalloc(sizeof(nxt_select_event_set_t)); - if (event_set == NULL) { - return NULL; - } - - ss = &event_set->select; - - ss->nfds = -1; - ss->update_nfds = 0; - - ss->events = nxt_zalloc(FD_SETSIZE * sizeof(nxt_event_fd_t *)); - if (ss->events != NULL) { - return event_set; - } - - nxt_select_free(event_set); - - return NULL; -} - - -static void -nxt_select_free(nxt_event_set_t *event_set) -{ - nxt_select_event_set_t *ss; - - nxt_main_log_debug("select free"); - - ss = &event_set->select; - - nxt_free(ss->events); - nxt_free(ss); -} - - -static void -nxt_select_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_select_enable_read(event_set, ev); - nxt_select_enable_write(event_set, ev); -} - - -static void -nxt_select_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - nxt_select_disable_read(event_set, ev); - } - - if (ev->write != NXT_EVENT_INACTIVE) { - nxt_select_disable_write(event_set, ev); - } -} - - -static void -nxt_select_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_fd_t fd; - nxt_thread_t *thr; - nxt_select_event_set_t *ss; - - fd = ev->fd; - - nxt_log_debug(ev->log, "select enable read: fd:%d", fd); - - ss = &event_set->select; - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - thr = nxt_thread(); - nxt_work_queue_add(&thr->engine->fast_work_queue, - nxt_select_error_handler, ev->task, ev, ev->data); - return; - } - - ev->read = NXT_EVENT_DEFAULT; - - FD_SET(fd, &ss->main_read_fd_set); - ss->events[fd] = ev; - - if (ss->nfds < fd) { - ss->nfds = fd; - ss->update_nfds = 0; - } -} - - -static void -nxt_select_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_fd_t fd; - nxt_thread_t *thr; - nxt_select_event_set_t *ss; - - fd = ev->fd; - - nxt_log_debug(ev->log, "select enable write: fd:%d", fd); - - ss = &event_set->select; - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - thr = nxt_thread(); - nxt_work_queue_add(&thr->engine->fast_work_queue, - nxt_select_error_handler, ev->task, ev, ev->data); - return; - } - - ev->write = NXT_EVENT_DEFAULT; - - FD_SET(fd, &ss->main_write_fd_set); - ss->events[fd] = ev; - - if (ss->nfds < fd) { - ss->nfds = fd; - ss->update_nfds = 0; - } -} - - -static void -nxt_select_error_handler(nxt_task_t *task, void *obj, void *data) -{ - nxt_event_fd_t *ev; - - ev = obj; - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - ev->error_handler(task, ev, data); -} - - -static void -nxt_select_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_fd_t fd; - nxt_select_event_set_t *ss; - - fd = ev->fd; - - nxt_log_debug(ev->log, "select disable read: fd:%d", fd); - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - return; - } - - ss = &event_set->select; - FD_CLR(fd, &ss->main_read_fd_set); - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write == NXT_EVENT_INACTIVE) { - ss->events[fd] = NULL; - ss->update_nfds = 1; - } -} - - -static void -nxt_select_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_fd_t fd; - nxt_select_event_set_t *ss; - - fd = ev->fd; - - nxt_log_debug(ev->log, "select disable write: fd:%d", fd); - - if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { - return; - } - - ss = &event_set->select; - FD_CLR(fd, &ss->main_write_fd_set); - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read == NXT_EVENT_INACTIVE) { - ss->events[fd] = NULL; - ss->update_nfds = 1; - } -} - - -static void -nxt_select_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - nxt_select_disable_read(event_set, ev); - } -} - - -static void -nxt_select_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - nxt_select_disable_write(event_set, ev); - } -} - - -static void -nxt_select_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_select_enable_read(event_set, ev); - - ev->read = NXT_EVENT_ONESHOT; -} - - -static void -nxt_select_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_select_enable_write(event_set, ev); - - ev->write = NXT_EVENT_ONESHOT; -} - - -static void -nxt_select_poll(nxt_task_t *task, nxt_event_set_t *event_set, - nxt_msec_t timeout) -{ - int nevents, nfds, found; - nxt_err_t err; - nxt_int_t i; - nxt_uint_t fd, level; - nxt_event_fd_t *ev; - struct timeval tv, *tp; - nxt_select_event_set_t *ss; - - if (timeout == NXT_INFINITE_MSEC) { - tp = NULL; - - } else { - tv.tv_sec = (long) (timeout / 1000); - tv.tv_usec = (long) ((timeout % 1000) * 1000); - tp = &tv; - } - - ss = &event_set->select; - - if (ss->update_nfds) { - for (i = ss->nfds; i >= 0; i--) { - if (ss->events[i] != NULL) { - ss->nfds = i; - ss->update_nfds = 0; - break; - } - } - } - - ss->work_read_fd_set = ss->main_read_fd_set; - ss->work_write_fd_set = ss->main_write_fd_set; - - nfds = ss->nfds + 1; - - nxt_debug(task, "select() nfds:%d timeout:%M", nfds, timeout); - - nevents = select(nfds, &ss->work_read_fd_set, &ss->work_write_fd_set, - NULL, tp); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(task->thread); - - nxt_debug(task, "select(): %d", nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log(task, level, "select() failed %E", err); - return; - } - - for (fd = 0; fd < (nxt_uint_t) nfds && nevents != 0; fd++) { - - found = 0; - - if (FD_ISSET(fd, &ss->work_read_fd_set)) { - ev = ss->events[fd]; - - nxt_debug(ev->task, "select() fd:%ui read rd:%d wr:%d", - fd, ev->read, ev->write); - - ev->read_ready = 1; - - if (ev->read == NXT_EVENT_ONESHOT) { - nxt_select_disable_read(event_set, ev); - } - - nxt_work_queue_add(ev->read_work_queue, ev->read_handler, - ev->task, ev, ev->data); - found = 1; - } - - if (FD_ISSET(fd, &ss->work_write_fd_set)) { - ev = ss->events[fd]; - - nxt_log_debug(ev->log, "select() fd:%ui write rd:%d wr:%d", - fd, ev->read, ev->write); - - ev->write_ready = 1; - - if (ev->write == NXT_EVENT_ONESHOT) { - nxt_select_disable_write(event_set, ev); - } - - nxt_work_queue_add(ev->write_work_queue, ev->write_handler, - ev->task, ev, ev->data); - found = 1; - } - - nevents -= found; - } -} diff --git a/src/nxt_select_engine.c b/src/nxt_select_engine.c new file mode 100644 index 00000000..8a6f0710 --- /dev/null +++ b/src/nxt_select_engine.c @@ -0,0 +1,370 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +static nxt_int_t nxt_select_create(nxt_event_engine_t *engine, + nxt_uint_t mchanges, nxt_uint_t mevents); +static void nxt_select_free(nxt_event_engine_t *engine); +static void nxt_select_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static void nxt_select_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); +static nxt_bool_t nxt_select_close(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_enable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_enable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_error_handler(nxt_task_t *task, void *obj, void *data); +static void nxt_select_disable_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_disable_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_block_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_block_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_oneshot_read(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_oneshot_write(nxt_event_engine_t *engine, + nxt_fd_event_t *ev); +static void nxt_select_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); + + +const nxt_event_interface_t nxt_select_engine = { + "select", + nxt_select_create, + nxt_select_free, + nxt_select_enable, + nxt_select_disable, + nxt_select_disable, + nxt_select_close, + nxt_select_enable_read, + nxt_select_enable_write, + nxt_select_disable_read, + nxt_select_disable_write, + nxt_select_block_read, + nxt_select_block_write, + nxt_select_oneshot_read, + nxt_select_oneshot_write, + nxt_select_enable_read, + NULL, + NULL, + NULL, + NULL, + nxt_select_poll, + + &nxt_unix_event_conn_io, + + NXT_NO_FILE_EVENTS, + NXT_NO_SIGNAL_EVENTS, +}; + + +static nxt_int_t +nxt_select_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, + nxt_uint_t mevents) +{ + engine->u.select.nfds = -1; + engine->u.select.update_nfds = 0; + + engine->u.select.events = nxt_zalloc(FD_SETSIZE * sizeof(nxt_fd_event_t *)); + + if (engine->u.select.events != NULL) { + return NXT_OK; + } + + nxt_select_free(engine); + + return NXT_ERROR; +} + + +static void +nxt_select_free(nxt_event_engine_t *engine) +{ + nxt_debug(&engine->task, "select free"); + + nxt_free(engine->u.select.events); + + nxt_memzero(&engine->u.select, sizeof(nxt_select_engine_t)); +} + + +static void +nxt_select_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_select_enable_read(engine, ev); + nxt_select_enable_write(engine, ev); +} + + +static void +nxt_select_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE) { + nxt_select_disable_read(engine, ev); + } + + if (ev->write != NXT_EVENT_INACTIVE) { + nxt_select_disable_write(engine, ev); + } +} + + +static nxt_bool_t +nxt_select_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_select_disable(engine, ev); + + return 0; +} + + +static void +nxt_select_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_fd_t fd; + + fd = ev->fd; + + nxt_debug(ev->task, "select enable read: fd:%d", fd); + + if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { + nxt_work_queue_add(&engine->fast_work_queue, nxt_select_error_handler, + ev->task, ev, ev->data); + return; + } + + ev->read = NXT_EVENT_ACTIVE; + + FD_SET(fd, &engine->u.select.main_read_fd_set); + engine->u.select.events[fd] = ev; + + if (engine->u.select.nfds < fd) { + engine->u.select.nfds = fd; + engine->u.select.update_nfds = 0; + } +} + + +static void +nxt_select_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_fd_t fd; + + fd = ev->fd; + + nxt_debug(ev->task, "select enable write: fd:%d", fd); + + if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { + nxt_work_queue_add(&engine->fast_work_queue, nxt_select_error_handler, + ev->task, ev, ev->data); + return; + } + + ev->write = NXT_EVENT_ACTIVE; + + FD_SET(fd, &engine->u.select.main_write_fd_set); + engine->u.select.events[fd] = ev; + + if (engine->u.select.nfds < fd) { + engine->u.select.nfds = fd; + engine->u.select.update_nfds = 0; + } +} + + +static void +nxt_select_error_handler(nxt_task_t *task, void *obj, void *data) +{ + nxt_fd_event_t *ev; + + ev = obj; + + ev->read = NXT_EVENT_INACTIVE; + ev->write = NXT_EVENT_INACTIVE; + + ev->error_handler(task, ev, data); +} + + +static void +nxt_select_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_fd_t fd; + + fd = ev->fd; + + nxt_debug(ev->task, "select disable read: fd:%d", fd); + + if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { + return; + } + + FD_CLR(fd, &engine->u.select.main_read_fd_set); + + ev->read = NXT_EVENT_INACTIVE; + + if (ev->write == NXT_EVENT_INACTIVE) { + engine->u.select.events[fd] = NULL; + engine->u.select.update_nfds = 1; + } +} + + +static void +nxt_select_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_fd_t fd; + + fd = ev->fd; + + nxt_debug(ev->task, "select disable write: fd:%d", fd); + + if (fd < 0 || fd >= (nxt_fd_t) FD_SETSIZE) { + return; + } + + FD_CLR(fd, &engine->u.select.main_write_fd_set); + + ev->write = NXT_EVENT_INACTIVE; + + if (ev->read == NXT_EVENT_INACTIVE) { + engine->u.select.events[fd] = NULL; + engine->u.select.update_nfds = 1; + } +} + + +static void +nxt_select_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->read != NXT_EVENT_INACTIVE) { + nxt_select_disable_read(engine, ev); + } +} + + +static void +nxt_select_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + if (ev->write != NXT_EVENT_INACTIVE) { + nxt_select_disable_write(engine, ev); + } +} + + +static void +nxt_select_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_select_enable_read(engine, ev); + + ev->read = NXT_EVENT_ONESHOT; +} + + +static void +nxt_select_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) +{ + nxt_select_enable_write(engine, ev); + + ev->write = NXT_EVENT_ONESHOT; +} + + +static void +nxt_select_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) +{ + int nevents, nfds, found; + nxt_err_t err; + nxt_int_t i; + nxt_uint_t fd, level; + nxt_fd_event_t *ev; + struct timeval tv, *tp; + + if (timeout == NXT_INFINITE_MSEC) { + tp = NULL; + + } else { + tv.tv_sec = (long) (timeout / 1000); + tv.tv_usec = (long) ((timeout % 1000) * 1000); + tp = &tv; + } + + if (engine->u.select.update_nfds) { + for (i = engine->u.select.nfds; i >= 0; i--) { + if (engine->u.select.events[i] != NULL) { + engine->u.select.nfds = i; + engine->u.select.update_nfds = 0; + break; + } + } + } + + engine->u.select.work_read_fd_set = engine->u.select.main_read_fd_set; + engine->u.select.work_write_fd_set = engine->u.select.main_write_fd_set; + + nfds = engine->u.select.nfds + 1; + + nxt_debug(&engine->task, "select() nfds:%d timeout:%M", nfds, timeout); + + nevents = select(nfds, &engine->u.select.work_read_fd_set, + &engine->u.select.work_write_fd_set, NULL, tp); + + err = (nevents == -1) ? nxt_errno : 0; + + nxt_thread_time_update(engine->task.thread); + + nxt_debug(&engine->task, "select(): %d", nevents); + + if (nevents == -1) { + level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; + nxt_log(&engine->task, level, "select() failed %E", err); + return; + } + + for (fd = 0; fd < (nxt_uint_t) nfds && nevents != 0; fd++) { + + found = 0; + + if (FD_ISSET(fd, &engine->u.select.work_read_fd_set)) { + ev = engine->u.select.events[fd]; + + nxt_debug(ev->task, "select() fd:%ui read rd:%d wr:%d", + fd, ev->read, ev->write); + + ev->read_ready = 1; + + if (ev->read == NXT_EVENT_ONESHOT) { + nxt_select_disable_read(engine, ev); + } + + nxt_work_queue_add(ev->read_work_queue, ev->read_handler, + ev->task, ev, ev->data); + found = 1; + } + + if (FD_ISSET(fd, &engine->u.select.work_write_fd_set)) { + ev = engine->u.select.events[fd]; + + nxt_debug(ev->task, "select() fd:%ui write rd:%d wr:%d", + fd, ev->read, ev->write); + + ev->write_ready = 1; + + if (ev->write == NXT_EVENT_ONESHOT) { + nxt_select_disable_write(engine, ev); + } + + nxt_work_queue_add(ev->write_work_queue, ev->write_handler, + ev->task, ev, ev->data); + found = 1; + } + + nevents -= found; + } +} diff --git a/src/nxt_service.c b/src/nxt_service.c index a911f53e..43aecfdd 100644 --- a/src/nxt_service.c +++ b/src/nxt_service.c @@ -10,34 +10,34 @@ static const nxt_service_t nxt_services[] = { #if (NXT_HAVE_KQUEUE) - { "engine", "kqueue", &nxt_kqueue_event_set }, + { "engine", "kqueue", &nxt_kqueue_engine }, #endif #if (NXT_HAVE_EPOLL_EDGE) - { "engine", "epoll", &nxt_epoll_edge_event_set }, - { "engine", "epoll_edge", &nxt_epoll_edge_event_set }, - { "engine", "epoll_level", &nxt_epoll_level_event_set }, + { "engine", "epoll", &nxt_epoll_edge_engine }, + { "engine", "epoll_edge", &nxt_epoll_edge_engine }, + { "engine", "epoll_level", &nxt_epoll_level_engine }, #elif (NXT_HAVE_EPOLL) - { "engine", "epoll", &nxt_epoll_level_event_set }, - { "engine", "epoll_level", &nxt_epoll_level_event_set }, + { "engine", "epoll", &nxt_epoll_level_engine }, + { "engine", "epoll_level", &nxt_epoll_level_engine }, #endif #if (NXT_HAVE_EVENTPORT) - { "engine", "eventport", &nxt_eventport_event_set }, + { "engine", "eventport", &nxt_eventport_engine }, #endif #if (NXT_HAVE_DEVPOLL) - { "engine", "devpoll", &nxt_devpoll_event_set }, - { "engine", "/dev/poll", &nxt_devpoll_event_set }, + { "engine", "devpoll", &nxt_devpoll_engine }, + { "engine", "/dev/poll", &nxt_devpoll_engine }, #endif #if (NXT_HAVE_POLLSET) - { "engine", "pollset", &nxt_pollset_event_set }, + { "engine", "pollset", &nxt_pollset_engine }, #endif - { "engine", "poll", &nxt_poll_event_set }, - { "engine", "select", &nxt_select_event_set }, + { "engine", "poll", &nxt_poll_engine }, + { "engine", "select", &nxt_select_engine }, #if (NXT_HAVE_OPENSSL) { "SSL/TLS", "OpenSSL", &nxt_openssl_lib }, diff --git a/src/nxt_signal.c b/src/nxt_signal.c index e267e3eb..492904d1 100644 --- a/src/nxt_signal.c +++ b/src/nxt_signal.c @@ -26,7 +26,7 @@ static nxt_int_t nxt_signal_action(int signo, void (*handler)(int)); nxt_event_signals_t * -nxt_event_engine_signals(const nxt_event_sig_t *sigev) +nxt_event_engine_signals(const nxt_sig_event_t *sigev) { nxt_event_signals_t *signals; @@ -115,7 +115,7 @@ nxt_int_t nxt_signal_thread_start(nxt_event_engine_t *engine) { nxt_thread_link_t *link; - const nxt_event_sig_t *sigev; + const nxt_sig_event_t *sigev; if (engine->signals->process == nxt_pid) { return NXT_OK; @@ -202,7 +202,7 @@ nxt_signal_thread_stop(nxt_event_engine_t *engine) nxt_int_t nxt_signal_handlers_start(nxt_event_engine_t *engine) { - const nxt_event_sig_t *sigev; + const nxt_sig_event_t *sigev; for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { if (nxt_signal_action(sigev->signo, nxt_signal_handler) != NXT_OK) { diff --git a/src/nxt_signal.h b/src/nxt_signal.h index 4141f39f..48d5c922 100644 --- a/src/nxt_signal.h +++ b/src/nxt_signal.h @@ -4,17 +4,15 @@ * Copyright (C) NGINX, Inc. */ -#ifndef _NXT_UNIX_SIGNAL_H_INCLUDED_ -#define _NXT_UNIX_SIGNAL_H_INCLUDED_ +#ifndef _NXT_SIGNAL_H_INCLUDED_ +#define _NXT_SIGNAL_H_INCLUDED_ -typedef struct nxt_event_sig_s nxt_event_sig_t; - -struct nxt_event_sig_s { +typedef struct { int signo; nxt_work_handler_t handler; const char *name; -}; +} nxt_sig_event_t; #define nxt_event_signal(sig, handler) \ { sig, handler, #sig } @@ -27,7 +25,7 @@ typedef struct { /* Used by epoll and eventport. */ nxt_work_handler_t handler; - const nxt_event_sig_t *sigev; + const nxt_sig_event_t *sigev; sigset_t sigmask; #if (NXT_THREADS) @@ -38,7 +36,7 @@ typedef struct { } nxt_event_signals_t; -nxt_event_signals_t *nxt_event_engine_signals(const nxt_event_sig_t *sigev); +nxt_event_signals_t *nxt_event_engine_signals(const nxt_sig_event_t *sigev); #if (NXT_THREADS) @@ -71,4 +69,4 @@ NXT_EXPORT void nxt_signal_handlers_stop(nxt_event_engine_t *engine); #endif -#endif /* _NXT_UNIX_SIGNAL_H_INCLUDED_ */ +#endif /* _NXT_SIGNAL_H_INCLUDED_ */ diff --git a/src/nxt_socket.h b/src/nxt_socket.h index 8912fb23..5ebe5c95 100644 --- a/src/nxt_socket.h +++ b/src/nxt_socket.h @@ -114,9 +114,9 @@ nxt_uint_t nxt_socket_error_level(nxt_err_t err, NXT_EXPORT nxt_int_t nxt_socketpair_create(nxt_socket_t *pair); NXT_EXPORT void nxt_socketpair_close(nxt_socket_t *pair); -NXT_EXPORT ssize_t nxt_socketpair_send(nxt_event_fd_t *ev, nxt_fd_t fd, +NXT_EXPORT ssize_t nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob, nxt_uint_t niob); -NXT_EXPORT ssize_t nxt_socketpair_recv(nxt_event_fd_t *ev, nxt_fd_t *fd, +NXT_EXPORT ssize_t nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob); diff --git a/src/nxt_socketpair.c b/src/nxt_socketpair.c index 4a7cbbaa..d0449020 100644 --- a/src/nxt_socketpair.c +++ b/src/nxt_socketpair.c @@ -71,7 +71,7 @@ nxt_socketpair_close(nxt_socket_t *pair) ssize_t -nxt_socketpair_send(nxt_event_fd_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob, +nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob, nxt_uint_t niob) { ssize_t n; @@ -113,7 +113,7 @@ nxt_socketpair_send(nxt_event_fd_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob, ssize_t -nxt_socketpair_recv(nxt_event_fd_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, +nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) { ssize_t n; diff --git a/src/nxt_worker_process.c b/src/nxt_worker_process.c index a30ac9e6..0f5f6eb6 100644 --- a/src/nxt_worker_process.c +++ b/src/nxt_worker_process.c @@ -29,7 +29,7 @@ static nxt_process_port_handler_t nxt_worker_process_port_handlers[] = { }; -static const nxt_event_sig_t nxt_worker_process_signals[] = { +static const nxt_sig_event_t nxt_worker_process_signals[] = { nxt_event_signal(SIGHUP, nxt_worker_process_signal_handler), nxt_event_signal(SIGINT, nxt_worker_process_sigterm_handler), nxt_event_signal(SIGQUIT, nxt_worker_process_sigterm_handler), @@ -44,11 +44,11 @@ static const nxt_event_sig_t nxt_worker_process_signals[] = { void nxt_worker_process_start(void *data) { - nxt_int_t n; - nxt_cycle_t *cycle; - nxt_thread_t *thr; - nxt_process_port_t *proc; - const nxt_event_set_ops_t *event_set; + nxt_int_t n; + nxt_cycle_t *cycle; + nxt_thread_t *thr; + nxt_process_port_t *proc; + const nxt_event_interface_t *interface; cycle = data; @@ -77,12 +77,12 @@ nxt_worker_process_start(void *data) /* Update inherited master process event engine and signals processing. */ thr->engine->signals->sigev = nxt_worker_process_signals; - event_set = nxt_service_get(cycle->services, "engine", cycle->engine); - if (event_set == NULL) { + interface = nxt_service_get(cycle->services, "engine", cycle->engine); + if (interface == NULL) { goto fail; } - if (nxt_event_engine_change(thr, &nxt_main_task, event_set, cycle->batch) != NXT_OK) { + if (nxt_event_engine_change(thr, &nxt_main_task, interface, cycle->batch) != NXT_OK) { goto fail; } @@ -150,7 +150,7 @@ nxt_worker_process_quit(nxt_task_t *task) cls = nxt_queue_link_data(link, nxt_event_conn_listen_t, link); nxt_queue_remove(link); - nxt_event_fd_close(task->thread->engine, &cls->socket); + nxt_fd_event_close(task->thread->engine, &cls->socket); } if (cycle->listen_sockets != NULL) { |