Path: blob/master/Utilities/cmlibuv/src/unix/posix-poll.c
3156 views
/* Copyright libuv project contributors. All rights reserved.1*2* Permission is hereby granted, free of charge, to any person obtaining a copy3* of this software and associated documentation files (the "Software"), to4* deal in the Software without restriction, including without limitation the5* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or6* sell copies of the Software, and to permit persons to whom the Software is7* furnished to do so, subject to the following conditions:8*9* The above copyright notice and this permission notice shall be included in10* all copies or substantial portions of the Software.11*12* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR13* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,14* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE15* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER16* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING17* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS18* IN THE SOFTWARE.19*/2021#include "uv.h"22#include "internal.h"2324/* POSIX defines poll() as a portable way to wait on file descriptors.25* Here we maintain a dynamically sized array of file descriptors and26* events to pass as the first argument to poll().27*/2829#include <assert.h>30#include <stddef.h>31#include <stdint.h>32#include <errno.h>33#include <unistd.h>3435int uv__platform_loop_init(uv_loop_t* loop) {36loop->poll_fds = NULL;37loop->poll_fds_used = 0;38loop->poll_fds_size = 0;39loop->poll_fds_iterating = 0;40return 0;41}4243void uv__platform_loop_delete(uv_loop_t* loop) {44uv__free(loop->poll_fds);45loop->poll_fds = NULL;46}4748int uv__io_fork(uv_loop_t* loop) {49uv__platform_loop_delete(loop);50return uv__platform_loop_init(loop);51}5253/* Allocate or dynamically resize our poll fds array. */54static void uv__pollfds_maybe_resize(uv_loop_t* loop) {55size_t i;56size_t n;57struct pollfd* p;5859if (loop->poll_fds_used < loop->poll_fds_size)60return;6162n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;63p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));64if (p == NULL)65abort();6667loop->poll_fds = p;68for (i = loop->poll_fds_size; i < n; i++) {69loop->poll_fds[i].fd = -1;70loop->poll_fds[i].events = 0;71loop->poll_fds[i].revents = 0;72}73loop->poll_fds_size = n;74}7576/* Primitive swap operation on poll fds array elements. */77static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) {78struct pollfd pfd;79pfd = loop->poll_fds[l];80loop->poll_fds[l] = loop->poll_fds[r];81loop->poll_fds[r] = pfd;82}8384/* Add a watcher's fd to our poll fds array with its pending events. */85static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) {86size_t i;87struct pollfd* pe;8889/* If the fd is already in the set just update its events. */90assert(!loop->poll_fds_iterating);91for (i = 0; i < loop->poll_fds_used; ++i) {92if (loop->poll_fds[i].fd == w->fd) {93loop->poll_fds[i].events = w->pevents;94return;95}96}9798/* Otherwise, allocate a new slot in the set for the fd. */99uv__pollfds_maybe_resize(loop);100pe = &loop->poll_fds[loop->poll_fds_used++];101pe->fd = w->fd;102pe->events = w->pevents;103}104105/* Remove a watcher's fd from our poll fds array. */106static void uv__pollfds_del(uv_loop_t* loop, int fd) {107size_t i;108assert(!loop->poll_fds_iterating);109for (i = 0; i < loop->poll_fds_used;) {110if (loop->poll_fds[i].fd == fd) {111/* swap to last position and remove */112--loop->poll_fds_used;113uv__pollfds_swap(loop, i, loop->poll_fds_used);114loop->poll_fds[loop->poll_fds_used].fd = -1;115loop->poll_fds[loop->poll_fds_used].events = 0;116loop->poll_fds[loop->poll_fds_used].revents = 0;117/* This method is called with an fd of -1 to purge the invalidated fds,118* so we may possibly have multiples to remove.119*/120if (-1 != fd)121return;122} else {123/* We must only increment the loop counter when the fds do not match.124* Otherwise, when we are purging an invalidated fd, the value just125* swapped here from the previous end of the array will be skipped.126*/127++i;128}129}130}131132133void uv__io_poll(uv_loop_t* loop, int timeout) {134sigset_t* pset;135sigset_t set;136uint64_t time_base;137uint64_t time_diff;138QUEUE* q;139uv__io_t* w;140size_t i;141unsigned int nevents;142int nfds;143int have_signals;144struct pollfd* pe;145int fd;146int user_timeout;147int reset_timeout;148149if (loop->nfds == 0) {150assert(QUEUE_EMPTY(&loop->watcher_queue));151return;152}153154/* Take queued watchers and add their fds to our poll fds array. */155while (!QUEUE_EMPTY(&loop->watcher_queue)) {156q = QUEUE_HEAD(&loop->watcher_queue);157QUEUE_REMOVE(q);158QUEUE_INIT(q);159160w = QUEUE_DATA(q, uv__io_t, watcher_queue);161assert(w->pevents != 0);162assert(w->fd >= 0);163assert(w->fd < (int) loop->nwatchers);164165uv__pollfds_add(loop, w);166167w->events = w->pevents;168}169170/* Prepare a set of signals to block around poll(), if any. */171pset = NULL;172if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {173pset = &set;174sigemptyset(pset);175sigaddset(pset, SIGPROF);176}177178assert(timeout >= -1);179time_base = loop->time;180181if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {182reset_timeout = 1;183user_timeout = timeout;184timeout = 0;185} else {186reset_timeout = 0;187}188189/* Loop calls to poll() and processing of results. If we get some190* results from poll() but they turn out not to be interesting to191* our caller then we need to loop around and poll() again.192*/193for (;;) {194/* Only need to set the provider_entry_time if timeout != 0. The function195* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.196*/197if (timeout != 0)198uv__metrics_set_provider_entry_time(loop);199200if (pset != NULL)201if (pthread_sigmask(SIG_BLOCK, pset, NULL))202abort();203nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout);204if (pset != NULL)205if (pthread_sigmask(SIG_UNBLOCK, pset, NULL))206abort();207208/* Update loop->time unconditionally. It's tempting to skip the update when209* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the210* operating system didn't reschedule our process while in the syscall.211*/212SAVE_ERRNO(uv__update_time(loop));213214if (nfds == 0) {215if (reset_timeout != 0) {216timeout = user_timeout;217reset_timeout = 0;218if (timeout == -1)219continue;220if (timeout > 0)221goto update_timeout;222}223224assert(timeout != -1);225return;226}227228if (nfds == -1) {229if (errno != EINTR)230abort();231232if (reset_timeout != 0) {233timeout = user_timeout;234reset_timeout = 0;235}236237if (timeout == -1)238continue;239240if (timeout == 0)241return;242243/* Interrupted by a signal. Update timeout and poll again. */244goto update_timeout;245}246247/* Tell uv__platform_invalidate_fd not to manipulate our array248* while we are iterating over it.249*/250loop->poll_fds_iterating = 1;251252/* Initialize a count of events that we care about. */253nevents = 0;254have_signals = 0;255256/* Loop over the entire poll fds array looking for returned events. */257for (i = 0; i < loop->poll_fds_used; i++) {258pe = loop->poll_fds + i;259fd = pe->fd;260261/* Skip invalidated events, see uv__platform_invalidate_fd. */262if (fd == -1)263continue;264265assert(fd >= 0);266assert((unsigned) fd < loop->nwatchers);267268w = loop->watchers[fd];269270if (w == NULL) {271/* File descriptor that we've stopped watching, ignore. */272uv__platform_invalidate_fd(loop, fd);273continue;274}275276/* Filter out events that user has not requested us to watch277* (e.g. POLLNVAL).278*/279pe->revents &= w->pevents | POLLERR | POLLHUP;280281if (pe->revents != 0) {282/* Run signal watchers last. */283if (w == &loop->signal_io_watcher) {284have_signals = 1;285} else {286uv__metrics_update_idle_time(loop);287w->cb(loop, w, pe->revents);288}289290nevents++;291}292}293294if (reset_timeout != 0) {295timeout = user_timeout;296reset_timeout = 0;297}298299if (have_signals != 0) {300uv__metrics_update_idle_time(loop);301loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);302}303304loop->poll_fds_iterating = 0;305306/* Purge invalidated fds from our poll fds array. */307uv__pollfds_del(loop, -1);308309if (have_signals != 0)310return; /* Event loop should cycle now so don't poll again. */311312if (nevents != 0)313return;314315if (timeout == 0)316return;317318if (timeout == -1)319continue;320321update_timeout:322assert(timeout > 0);323324time_diff = loop->time - time_base;325if (time_diff >= (uint64_t) timeout)326return;327328timeout -= time_diff;329}330}331332/* Remove the given fd from our poll fds array because no one333* is interested in its events anymore.334*/335void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {336size_t i;337338assert(fd >= 0);339340if (loop->poll_fds_iterating) {341/* uv__io_poll is currently iterating. Just invalidate fd. */342for (i = 0; i < loop->poll_fds_used; i++)343if (loop->poll_fds[i].fd == fd) {344loop->poll_fds[i].fd = -1;345loop->poll_fds[i].events = 0;346loop->poll_fds[i].revents = 0;347}348} else {349/* uv__io_poll is not iterating. Delete fd from the set. */350uv__pollfds_del(loop, fd);351}352}353354/* Check whether the given fd is supported by poll(). */355int uv__io_check_fd(uv_loop_t* loop, int fd) {356struct pollfd p[1];357int rv;358359p[0].fd = fd;360p[0].events = POLLIN;361362do363rv = poll(p, 1, 0);364while (rv == -1 && (errno == EINTR || errno == EAGAIN));365366if (rv == -1)367return UV__ERR(errno);368369if (p[0].revents & POLLNVAL)370return UV_EINVAL;371372return 0;373}374375376