Event engines refactoring.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
665
src/nxt_devpoll_engine.c
Normal file
665
src/nxt_devpoll_engine.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
nxt_debug(&engine->task, "signalfd(): %d", fd);
|
||||
|
||||
thr = nxt_thread();
|
||||
|
||||
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;
|
||||
|
||||
if (epoll_ctl(es->epoll, EPOLL_CTL_ADD, es->eventfd.fd, &ee) == 0) {
|
||||
ret = epoll_ctl(engine->u.epoll.fd, EPOLL_CTL_ADD,
|
||||
engine->u.epoll.eventfd.fd, &ee);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
es = &event_set->epoll;
|
||||
|
||||
if (es->nchanges != 0) {
|
||||
if (nxt_epoll_commit_changes(task, es) != NXT_OK) {
|
||||
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;
|
||||
@@ -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;
|
||||
|
||||
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);
|
||||
|
||||
ret = setsockopt(c->socket.fd, SOL_SOCKET, SO_LINGER, &linger, len);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (c->socket.error == 0 && !c->socket.closed && !c->socket.shutdown) {
|
||||
wq = &engine->shutdown_work_queue;
|
||||
handler = nxt_conn_shutdown_handler;
|
||||
|
||||
} else{
|
||||
wq = &engine->close_work_queue;
|
||||
handler = nxt_conn_close_handler;
|
||||
}
|
||||
|
||||
nxt_work_queue_add(wq, handler, c->socket.task, c, engine);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_conn_shutdown_handler(nxt_task_t *task, void *obj, void *data)
|
||||
{
|
||||
nxt_event_conn_t *c;
|
||||
nxt_event_engine_t *engine;
|
||||
|
||||
c = obj;
|
||||
engine = data;
|
||||
|
||||
nxt_debug(task, "event conn shutdown fd:%d", c->socket.fd);
|
||||
|
||||
c->socket.shutdown = 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_conn_close_handler(nxt_task_t *task, void *obj, void *data)
|
||||
{
|
||||
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);
|
||||
|
||||
thr = task->thread;
|
||||
timers_pending = nxt_timer_delete(engine, &c->read_timer);
|
||||
timers_pending += nxt_timer_delete(engine, &c->write_timer);
|
||||
|
||||
engine = thr->engine;
|
||||
events_pending = nxt_fd_event_close(engine, &c->socket);
|
||||
|
||||
nxt_timer_delete(engine, &c->read_timer);
|
||||
nxt_timer_delete(engine, &c->write_timer);
|
||||
|
||||
nxt_event_fd_close(engine, &c->socket);
|
||||
engine->connections--;
|
||||
|
||||
nxt_debug(task, "event connections: %uD", engine->connections);
|
||||
|
||||
if (engine->batch != 0) {
|
||||
|
||||
if (c->socket.closed || c->socket.error != 0) {
|
||||
wq = &engine->close_work_queue;
|
||||
handler = nxt_event_conn_close_socket;
|
||||
|
||||
} else {
|
||||
wq = &engine->shutdown_work_queue;
|
||||
handler = nxt_event_conn_shutdown_socket;
|
||||
}
|
||||
|
||||
nxt_work_queue_add(wq, handler, task,
|
||||
(void *) (uintptr_t) c->socket.fd, NULL);
|
||||
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
c->socket.fd = -1;
|
||||
c->write_timer.handler = nxt_conn_close_timer_handler;
|
||||
c->write_timer.work_queue = &engine->fast_work_queue;
|
||||
|
||||
nxt_timer_add(engine, &c->write_timer, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_event_conn_shutdown_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;
|
||||
|
||||
s = (nxt_socket_t) (uintptr_t) obj;
|
||||
ev = obj;
|
||||
|
||||
nxt_socket_shutdown(s, SHUT_RDWR);
|
||||
c = nxt_event_write_timer_conn(ev);
|
||||
|
||||
nxt_work_queue_add(&task->thread->engine->close_work_queue,
|
||||
nxt_event_conn_close_socket, task,
|
||||
(void *) (uintptr_t) s, NULL);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
nxt_event_conn_close_socket(nxt_task_t *task, void *obj, void *data)
|
||||
{
|
||||
nxt_socket_t s;
|
||||
engine = task->thread->engine;
|
||||
|
||||
s = (nxt_socket_t) (uintptr_t) obj;
|
||||
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -7,32 +7,446 @@
|
||||
#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;
|
||||
|
||||
union {
|
||||
nxt_poll_engine_t poll;
|
||||
nxt_select_engine_t select;
|
||||
|
||||
#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;
|
||||
|
||||
nxt_timers_t timers;
|
||||
|
||||
nxt_task_t task;
|
||||
/* The engine ID, the main engine has ID 0. */
|
||||
uint32_t id;
|
||||
|
||||
/*
|
||||
* 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_work_queue_cache_t work_queue_cache;
|
||||
nxt_work_queue_t *current_work_queue;
|
||||
nxt_work_queue_t fast_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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
618
src/nxt_eventport_engine.c
Normal file
618
src/nxt_eventport_engine.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
131
src/nxt_fd_event.c
Normal file
131
src/nxt_fd_event.c
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
const nxt_sig_event_t *sigev;
|
||||
|
||||
event_set = nxt_zalloc(sizeof(nxt_kqueue_event_set_t));
|
||||
if (event_set == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
engine->u.kqueue.fd = -1;
|
||||
engine->u.kqueue.mchanges = mchanges;
|
||||
engine->u.kqueue.mevents = mevents;
|
||||
engine->u.kqueue.pid = nxt_pid;
|
||||
|
||||
ks = &event_set->kqueue;
|
||||
|
||||
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;
|
||||
|
||||
ks = &event_set->kqueue;
|
||||
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;
|
||||
|
||||
kev = nxt_kqueue_get_kevent(ks);
|
||||
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(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;
|
||||
struct kevent *kev;
|
||||
|
||||
ks = &event_set->kqueue;
|
||||
nxt_debug(ev->task, "kevent(%d) set event: id:%d ft:%i fl:%04Xui",
|
||||
engine->u.kqueue.fd, ev->fd, filter, flags);
|
||||
|
||||
nxt_log_debug(ev->log, "kevent(%d) set event: id:%d ft:%i fl:%04Xui",
|
||||
ks->kqueue, 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;
|
||||
|
||||
nchanges = engine->u.kqueue.nchanges;
|
||||
|
||||
if (nxt_slow_path(nchanges >= engine->u.kqueue.mchanges)) {
|
||||
|
||||
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);
|
||||
|
||||
nxt_kqueue_error(engine);
|
||||
}
|
||||
|
||||
engine->u.kqueue.nchanges = 0;
|
||||
}
|
||||
|
||||
return &ks->changes[ks->nchanges++];
|
||||
return &engine->u.kqueue.changes[engine->u.kqueue.nchanges++];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_kqueue_commit_changes(nxt_kqueue_event_set_t *ks)
|
||||
{
|
||||
nxt_thread_log_debug("kevent(%d) changes:%d", ks->kqueue, ks->nchanges);
|
||||
|
||||
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(ks);
|
||||
}
|
||||
|
||||
ks->nchanges = 0;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
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 *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;
|
||||
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_kqueue_error(ks);
|
||||
nxt_log(&engine->task, level, "kevent(%d) failed %E",
|
||||
engine->u.kqueue.fd, err);
|
||||
|
||||
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);
|
||||
@@ -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>
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
|
||||
752
src/nxt_poll.c
752
src/nxt_poll.c
@@ -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);
|
||||
}
|
||||
}
|
||||
710
src/nxt_poll_engine.c
Normal file
710
src/nxt_poll_engine.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
647
src/nxt_pollset_engine.c
Normal file
647
src/nxt_pollset_engine.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
390
src/nxt_select.c
390
src/nxt_select.c
@@ -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;
|
||||
}
|
||||
}
|
||||
370
src/nxt_select_engine.c
Normal file
370
src/nxt_select_engine.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 },
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user