summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2017-02-07 20:04:56 +0300
committerIgor Sysoev <igor@sysoev.ru>2017-02-07 20:04:56 +0300
commit059a8642898a6bd4b47d13a1c1d599cd44af7e1c (patch)
treee3c8c530a04f1ae44777d5ea4fd6901dc55a8ebf
parente57b95a92333fa7ff558737b0ba2b76894cc0412 (diff)
downloadunit-059a8642898a6bd4b47d13a1c1d599cd44af7e1c.tar.gz
unit-059a8642898a6bd4b47d13a1c1d599cd44af7e1c.tar.bz2
Event engines refactoring.
Diffstat (limited to '')
-rw-r--r--auto/sources19
-rw-r--r--src/nxt_application.c30
-rw-r--r--src/nxt_cycle.c52
-rw-r--r--src/nxt_devpoll.c699
-rw-r--r--src/nxt_devpoll_engine.c665
-rw-r--r--src/nxt_epoll_engine.c (renamed from src/nxt_epoll.c)541
-rw-r--r--src/nxt_event_conn.c144
-rw-r--r--src/nxt_event_conn.h12
-rw-r--r--src/nxt_event_conn_accept.c25
-rw-r--r--src/nxt_event_conn_connect.c4
-rw-r--r--src/nxt_event_conn_job_sendfile.c4
-rw-r--r--src/nxt_event_conn_proxy.c20
-rw-r--r--src/nxt_event_conn_read.c10
-rw-r--r--src/nxt_event_conn_write.c10
-rw-r--r--src/nxt_event_engine.c71
-rw-r--r--src/nxt_event_engine.h455
-rw-r--r--src/nxt_event_set.c107
-rw-r--r--src/nxt_event_set.h473
-rw-r--r--src/nxt_eventport.c646
-rw-r--r--src/nxt_eventport_engine.c618
-rw-r--r--src/nxt_fd_event.c131
-rw-r--r--src/nxt_fd_event.h (renamed from src/nxt_event_fd.h)50
-rw-r--r--src/nxt_kqueue_engine.c (renamed from src/nxt_kqueue.c)481
-rw-r--r--src/nxt_main.h7
-rw-r--r--src/nxt_master_process.c2
-rw-r--r--src/nxt_master_process.h2
-rw-r--r--src/nxt_openssl.c12
-rw-r--r--src/nxt_poll.c752
-rw-r--r--src/nxt_poll_engine.c710
-rw-r--r--src/nxt_pollset.c627
-rw-r--r--src/nxt_pollset_engine.c647
-rw-r--r--src/nxt_port_socket.c10
-rw-r--r--src/nxt_port_socket.h2
-rw-r--r--src/nxt_select.c390
-rw-r--r--src/nxt_select_engine.c370
-rw-r--r--src/nxt_service.c24
-rw-r--r--src/nxt_signal.c6
-rw-r--r--src/nxt_signal.h16
-rw-r--r--src/nxt_socket.h4
-rw-r--r--src/nxt_socketpair.c4
-rw-r--r--src/nxt_worker_process.c20
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) {