diff options
Diffstat (limited to 'src/nxt_devpoll.c')
-rw-r--r-- | src/nxt_devpoll.c | 699 |
1 files changed, 0 insertions, 699 deletions
diff --git a/src/nxt_devpoll.c b/src/nxt_devpoll.c deleted file mode 100644 index 8fbe8184..00000000 --- a/src/nxt_devpoll.c +++ /dev/null @@ -1,699 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -/* - * "/dev/poll" has been introduced in Solaris 7 (11/99), HP-UX 11.22 (named - * "eventport pseudo driver" internally, not to be confused with Solaris 10 - * event ports), IRIX 6.5.15, and Tru64 UNIX 5.1A. - * - * Although "/dev/poll" descriptor is a file descriptor, nevertheless - * it cannot be added to another poll set, Solaris poll(7d): - * - * The /dev/poll driver does not yet support polling. Polling on a - * /dev/poll file descriptor will result in POLLERR being returned - * in the revents field of pollfd structure. - */ - - -#define NXT_DEVPOLL_ADD 0 -#define NXT_DEVPOLL_UPDATE 1 -#define NXT_DEVPOLL_CHANGE 2 -#define NXT_DEVPOLL_DELETE 3 - - -static nxt_event_set_t *nxt_devpoll_create(nxt_event_signals_t *signals, - nxt_uint_t mchanges, nxt_uint_t mevents); -static void nxt_devpoll_free(nxt_event_set_t *event_set); -static void nxt_devpoll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_devpoll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -#if (NXT_HPUX) -static void nxt_devpoll_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev); -static void nxt_devpoll_drop_changes(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -#endif -static void nxt_devpoll_enable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_enable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_disable_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_disable_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_block_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_block_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_oneshot_read(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_oneshot_write(nxt_event_set_t *event_set, - nxt_event_fd_t *ev); -static void nxt_devpoll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t op, nxt_uint_t events); -static nxt_int_t nxt_devpoll_commit_changes(nxt_thread_t *thr, - nxt_devpoll_event_set_t *ds); -static void nxt_devpoll_change_error(nxt_thread_t *thr, - nxt_devpoll_event_set_t *ds, nxt_event_fd_t *ev); -static void nxt_devpoll_remove(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds, - nxt_fd_t fd); -static nxt_int_t nxt_devpoll_write(nxt_thread_t *thr, int devpoll, - struct pollfd *pfd, size_t n); -static void nxt_devpoll_set_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout); - - -const nxt_event_set_ops_t nxt_devpoll_event_set = { - "devpoll", - nxt_devpoll_create, - nxt_devpoll_free, - nxt_devpoll_enable, - nxt_devpoll_disable, - nxt_devpoll_disable, -#if (NXT_HPUX) - nxt_devpoll_close, -#else - nxt_devpoll_disable, -#endif - nxt_devpoll_enable_read, - nxt_devpoll_enable_write, - nxt_devpoll_disable_read, - nxt_devpoll_disable_write, - nxt_devpoll_block_read, - nxt_devpoll_block_write, - nxt_devpoll_oneshot_read, - nxt_devpoll_oneshot_write, - nxt_devpoll_enable_read, - NULL, - NULL, - NULL, - NULL, - nxt_devpoll_set_poll, - - &nxt_unix_event_conn_io, - - NXT_NO_FILE_EVENTS, - NXT_NO_SIGNAL_EVENTS, -}; - - -static nxt_event_set_t * -nxt_devpoll_create(nxt_event_signals_t *signals, nxt_uint_t mchanges, - nxt_uint_t mevents) -{ - nxt_event_set_t *event_set; - nxt_devpoll_event_set_t *ds; - - event_set = nxt_zalloc(sizeof(nxt_devpoll_event_set_t)); - if (event_set == NULL) { - return NULL; - } - - ds = &event_set->devpoll; - - ds->devpoll = -1; - ds->mchanges = mchanges; - ds->mevents = mevents; - - ds->devpoll_changes = nxt_malloc(sizeof(nxt_devpoll_change_t) * mchanges); - if (ds->devpoll_changes == NULL) { - goto fail; - } - - /* - * NXT_DEVPOLL_CHANGE requires two struct pollfd's: - * for POLLREMOVE and subsequent POLLIN or POLLOUT. - */ - ds->changes = nxt_malloc(2 * sizeof(struct pollfd) * mchanges); - if (ds->changes == NULL) { - goto fail; - } - - ds->events = nxt_malloc(sizeof(struct pollfd) * mevents); - if (ds->events == NULL) { - goto fail; - } - - ds->devpoll = open("/dev/poll", O_RDWR); - if (ds->devpoll == -1) { - nxt_main_log_emerg("open(/dev/poll) failed %E", nxt_errno); - goto fail; - } - - nxt_main_log_debug("open(/dev/poll): %d", ds->devpoll); - - return event_set; - -fail: - - nxt_devpoll_free(event_set); - - return NULL; -} - - -static void -nxt_devpoll_free(nxt_event_set_t *event_set) -{ - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - nxt_main_log_debug("devpoll %d free", ds->devpoll); - - if (ds->devpoll != -1) { - if (close(ds->devpoll) != 0) { - nxt_main_log_emerg("devpoll close(%d) failed %E", - ds->devpoll, nxt_errno); - } - } - - nxt_free(ds->events); - nxt_free(ds->changes); - nxt_free(ds->devpoll_changes); - nxt_event_set_fd_hash_destroy(&ds->fd_hash); - nxt_free(ds); -} - - -static void -nxt_devpoll_enable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_DEFAULT; - ev->write = NXT_EVENT_DEFAULT; - - nxt_devpoll_change(event_set, ev, NXT_DEVPOLL_ADD, POLLIN | POLLOUT); -} - - -/* - * Solaris does not automatically remove a closed file descriptor from - * a "/dev/poll" set: ioctl(DP_ISPOLLED) for the descriptor returns 1, - * significative of active descriptor. POLLREMOVE can remove already - * closed file descriptor, so the removal can be batched, Solaris poll(7d): - * - * When using the "/dev/poll" driver, you should remove a closed file - * descriptor from a monitored poll set. Failure to do so may result - * in a POLLNVAL revents being returned for the closed file descriptor. - * When a file descriptor is closed but not removed from the monitored - * set, and is reused in subsequent open of a different device, you - * will be polling the device associated with the reused file descriptor. - * In a multithreaded application, careful coordination among threads - * doing close and DP_POLL ioctl is recommended for consistent results. - * - * Besides Solaris and HP-UX allow to add invalid descriptors to an - * "/dev/poll" set, although the descriptors are not marked as polled, - * that is, ioctl(DP_ISPOLLED) returns 0. - */ - -static void -nxt_devpoll_disable(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) { - - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_devpoll_change(event_set, ev, NXT_DEVPOLL_DELETE, POLLREMOVE); - } -} - - -#if (NXT_HPUX) - -/* - * HP-UX poll(7): - * - * When a polled file descriptor is closed, it is automatically - * deregistered. - */ - -static void -nxt_devpoll_close(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_devpoll_drop_changes(event_set, ev); -} - - -static void -nxt_devpoll_drop_changes(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_devpoll_change_t *dst, *src, *end; - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - dst = ds->devpoll_changes; - end = dst + ds->nchanges; - - for (src = dst; src < end; src++) { - - if (src->event == ev) { - continue; - } - - if (dst != src) { - *dst = *src; - } - - dst++; - } - - ds->nchanges -= end - dst; -} - -#endif - - -/* - * Solaris poll(7d): - * - * The fd field specifies the file descriptor being polled. The events - * field indicates the interested poll events on the file descriptor. - * If a pollfd array contains multiple pollfd entries with the same fd field, - * the "events" field in each pollfd entry is OR'ed. A special POLLREMOVE - * event in the events field of the pollfd structure removes the fd from - * the monitored set. The revents field is not used. - */ - -static void -nxt_devpoll_enable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - if (ev->read != NXT_EVENT_BLOCKED) { - - events = POLLIN; - - if (ev->write == NXT_EVENT_INACTIVE) { - op = NXT_DEVPOLL_ADD; - - } else if (ev->write == NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_CHANGE; - - } else { - op = NXT_DEVPOLL_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_devpoll_change(event_set, ev, op, events); - } - - ev->read = NXT_EVENT_DEFAULT; -} - - -static void -nxt_devpoll_enable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - if (ev->write != NXT_EVENT_BLOCKED) { - - events = POLLOUT; - - if (ev->read == NXT_EVENT_INACTIVE) { - op = NXT_DEVPOLL_ADD; - - } else if (ev->read == NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_CHANGE; - - } else { - op = NXT_DEVPOLL_UPDATE; - events = POLLIN | POLLOUT; - } - - nxt_devpoll_change(event_set, ev, op, events); - } - - ev->write = NXT_EVENT_DEFAULT; -} - - -static void -nxt_devpoll_disable_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->read = NXT_EVENT_INACTIVE; - - if (ev->write <= NXT_EVENT_BLOCKED) { - ev->write = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_DEVPOLL_CHANGE; - events = POLLOUT; - } - - nxt_devpoll_change(event_set, ev, op, events); -} - - -static void -nxt_devpoll_disable_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_uint_t op, events; - - ev->write = NXT_EVENT_INACTIVE; - - if (ev->read <= NXT_EVENT_BLOCKED) { - ev->read = NXT_EVENT_INACTIVE; - op = NXT_DEVPOLL_DELETE; - events = POLLREMOVE; - - } else { - op = NXT_DEVPOLL_CHANGE; - events = POLLIN; - } - - nxt_devpoll_change(event_set, ev, op, events); -} - - -static void -nxt_devpoll_block_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->read != NXT_EVENT_INACTIVE) { - ev->read = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_devpoll_block_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - if (ev->write != NXT_EVENT_INACTIVE) { - ev->write = NXT_EVENT_BLOCKED; - } -} - - -static void -nxt_devpoll_oneshot_read(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_devpoll_enable_read(event_set, ev); - - ev->read = NXT_EVENT_ONESHOT; -} - - -static void -nxt_devpoll_oneshot_write(nxt_event_set_t *event_set, nxt_event_fd_t *ev) -{ - nxt_devpoll_enable_write(event_set, ev); - - ev->write = NXT_EVENT_ONESHOT; -} - - -static void -nxt_devpoll_change(nxt_event_set_t *event_set, nxt_event_fd_t *ev, - nxt_uint_t op, nxt_uint_t events) -{ - nxt_devpoll_change_t *ch; - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - nxt_log_debug(ev->log, "devpoll %d change fd:%d op:%ui ev:%04Xi", - ds->devpoll, ev->fd, op, events); - - if (ds->nchanges >= ds->mchanges) { - (void) nxt_devpoll_commit_changes(nxt_thread(), ds); - } - - ch = &ds->devpoll_changes[ds->nchanges++]; - ch->op = op; - ch->fd = ev->fd; - ch->events = events; - ch->event = ev; -} - - -static nxt_int_t -nxt_devpoll_commit_changes(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds) -{ - size_t n; - nxt_int_t ret, retval; - struct pollfd *pfd; - nxt_devpoll_change_t *ch, *end; - - nxt_log_debug(thr->log, "devpoll %d changes:%ui", - ds->devpoll, ds->nchanges); - - retval = NXT_OK; - n = 0; - ch = ds->devpoll_changes; - end = ch + ds->nchanges; - - do { - nxt_log_debug(thr->log, "devpoll fd:%d op:%d ev:%04Xd", - ch->fd, ch->op, ch->events); - - if (ch->op == NXT_DEVPOLL_CHANGE) { - pfd = &ds->changes[n++]; - pfd->fd = ch->fd; - pfd->events = POLLREMOVE; - pfd->revents = 0; - } - - pfd = &ds->changes[n++]; - pfd->fd = ch->fd; - pfd->events = ch->events; - pfd->revents = 0; - - ch++; - - } while (ch < end); - - ch = ds->devpoll_changes; - end = ch + ds->nchanges; - - ret = nxt_devpoll_write(thr, ds->devpoll, ds->changes, n); - - if (nxt_slow_path(ret != NXT_OK)) { - do { - nxt_devpoll_change_error(thr, ds, ch->event); - ch++; - } while (ch < end); - - ds->nchanges = 0; - - return NXT_ERROR; - } - - do { - if (ch->op == NXT_DEVPOLL_ADD) { - ret = nxt_event_set_fd_hash_add(&ds->fd_hash, ch->fd, ch->event); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_devpoll_change_error(thr, ds, ch->event); - retval = NXT_ERROR; - } - - } else if (ch->op == NXT_DEVPOLL_DELETE) { - nxt_event_set_fd_hash_delete(&ds->fd_hash, ch->fd, 0); - } - - /* Nothing tp do for NXT_DEVPOLL_UPDATE and NXT_DEVPOLL_CHANGE. */ - - ch++; - - } while (ch < end); - - ds->nchanges = 0; - - return retval; -} - - -static void -nxt_devpoll_change_error(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds, - nxt_event_fd_t *ev) -{ - ev->read = NXT_EVENT_INACTIVE; - ev->write = NXT_EVENT_INACTIVE; - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - ev->error_handler, ev, ev->data, ev->log); - - nxt_event_set_fd_hash_delete(&ds->fd_hash, ev->fd, 1); - - nxt_devpoll_remove(thr, ds, ev->fd); -} - - -static void -nxt_devpoll_remove(nxt_thread_t *thr, nxt_devpoll_event_set_t *ds, nxt_fd_t fd) -{ - int n; - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = 0; - pfd.revents = 0; - - n = ioctl(ds->devpoll, DP_ISPOLLED, &pfd); - - nxt_log_debug(thr->log, "ioctl(%d, DP_ISPOLLED, %d): %d", - ds->devpoll, fd, n); - - if (n == 0) { - /* The file descriptor is not in the set. */ - return; - } - - if (n == -1) { - nxt_log_alert(thr->log, "ioctl(%d, DP_ISPOLLED, %d) failed %E", - ds->devpoll, fd, nxt_errno); - /* Fall through. */ - } - - /* n == 1: the file descriptor is in the set. */ - - nxt_log_debug(thr->log, "devpoll %d remove fd:%d", ds->devpoll, fd); - - pfd.fd = fd; - pfd.events = POLLREMOVE; - pfd.revents = 0; - - nxt_devpoll_write(thr, ds->devpoll, &pfd, 1); -} - - -static nxt_int_t -nxt_devpoll_write(nxt_thread_t *thr, int devpoll, struct pollfd *pfd, - size_t n) -{ - nxt_log_debug(thr->log, "devpoll write(%d) changes:%uz", devpoll, n); - - n *= sizeof(struct pollfd); - - if (nxt_slow_path(write(devpoll, pfd, n) == (ssize_t) n)) { - return NXT_OK; - } - - nxt_log_alert(thr->log, "devpoll write(%d) failed %E", - devpoll, nxt_errno); - - return NXT_ERROR; -} - - -static void -nxt_devpoll_set_poll(nxt_thread_t *thr, nxt_event_set_t *event_set, - nxt_msec_t timeout) -{ - int nevents; - nxt_fd_t fd; - nxt_int_t i; - nxt_err_t err; - nxt_uint_t events, level; - struct dvpoll dvp; - struct pollfd *pfd; - nxt_event_fd_t *ev; - nxt_devpoll_event_set_t *ds; - - ds = &event_set->devpoll; - - if (ds->nchanges != 0) { - if (nxt_devpoll_commit_changes(thr, ds) != NXT_OK) { - /* Error handlers have been enqueued on failure. */ - timeout = 0; - } - } - - nxt_log_debug(thr->log, "ioctl(%d, DP_POLL) timeout:%M", - ds->devpoll, timeout); - - dvp.dp_fds = ds->events; - dvp.dp_nfds = ds->mevents; - dvp.dp_timeout = timeout; - - nevents = ioctl(ds->devpoll, DP_POLL, &dvp); - - err = (nevents == -1) ? nxt_errno : 0; - - nxt_thread_time_update(thr); - - nxt_log_debug(thr->log, "ioctl(%d, DP_POLL): %d", ds->devpoll, nevents); - - if (nevents == -1) { - level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; - nxt_log_error(level, thr->log, "ioctl(%d, DP_POLL) failed %E", - ds->devpoll, err); - return; - } - - for (i = 0; i < nevents; i++) { - - pfd = &ds->events[i]; - fd = pfd->fd; - events = pfd->revents; - - ev = nxt_event_set_fd_hash_get(&ds->fd_hash, fd); - - if (nxt_slow_path(ev == NULL)) { - nxt_log_alert(thr->log, "ioctl(%d, DP_POLL) returned invalid " - "fd:%d ev:%04Xd rev:%04uXi", - ds->devpoll, fd, pfd->events, events); - - nxt_devpoll_remove(thr, ds, fd); - continue; - } - - nxt_log_debug(ev->log, "devpoll: fd:%d ev:%04uXi rd:%d wr:%d", - fd, events, ev->read, ev->write); - - if (nxt_slow_path(events & (POLLERR | POLLHUP | POLLNVAL)) != 0) { - nxt_log_alert(ev->log, - "ioctl(%d, DP_POLL) error fd:%d ev:%04Xd rev:%04uXi", - ds->devpoll, fd, pfd->events, events); - - nxt_thread_work_queue_add(thr, &thr->work_queue.main, - ev->error_handler, ev, ev->data, ev->log); - continue; - } - - if (events & POLLIN) { - ev->read_ready = 1; - - if (ev->read != NXT_EVENT_BLOCKED) { - - if (ev->read == NXT_EVENT_ONESHOT) { - nxt_devpoll_disable_read(event_set, ev); - } - - nxt_thread_work_queue_add(thr, ev->read_work_queue, - ev->read_handler, - ev, ev->data, ev->log); - } - } - - if (events & POLLOUT) { - ev->write_ready = 1; - - if (ev->write != NXT_EVENT_BLOCKED) { - - if (ev->write == NXT_EVENT_ONESHOT) { - nxt_devpoll_disable_write(event_set, ev); - } - - nxt_thread_work_queue_add(thr, ev->write_work_queue, - ev->write_handler, - ev, ev->data, ev->log); - } - } - } -} |