10e552da7Schristos /* Copyright libuv project contributors. All rights reserved.
20e552da7Schristos *
30e552da7Schristos * Permission is hereby granted, free of charge, to any person obtaining a copy
40e552da7Schristos * of this software and associated documentation files (the "Software"), to
50e552da7Schristos * deal in the Software without restriction, including without limitation the
60e552da7Schristos * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
70e552da7Schristos * sell copies of the Software, and to permit persons to whom the Software is
80e552da7Schristos * furnished to do so, subject to the following conditions:
90e552da7Schristos *
100e552da7Schristos * The above copyright notice and this permission notice shall be included in
110e552da7Schristos * all copies or substantial portions of the Software.
120e552da7Schristos *
130e552da7Schristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
140e552da7Schristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
150e552da7Schristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
160e552da7Schristos * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
170e552da7Schristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
180e552da7Schristos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
190e552da7Schristos * IN THE SOFTWARE.
200e552da7Schristos */
210e552da7Schristos
220e552da7Schristos #include "uv.h"
230e552da7Schristos #include "internal.h"
240e552da7Schristos
250e552da7Schristos /* POSIX defines poll() as a portable way to wait on file descriptors.
260e552da7Schristos * Here we maintain a dynamically sized array of file descriptors and
270e552da7Schristos * events to pass as the first argument to poll().
280e552da7Schristos */
290e552da7Schristos
300e552da7Schristos #include <assert.h>
310e552da7Schristos #include <stddef.h>
320e552da7Schristos #include <stdint.h>
330e552da7Schristos #include <errno.h>
340e552da7Schristos #include <unistd.h>
350e552da7Schristos
uv__platform_loop_init(uv_loop_t * loop)360e552da7Schristos int uv__platform_loop_init(uv_loop_t* loop) {
370e552da7Schristos loop->poll_fds = NULL;
380e552da7Schristos loop->poll_fds_used = 0;
390e552da7Schristos loop->poll_fds_size = 0;
400e552da7Schristos loop->poll_fds_iterating = 0;
410e552da7Schristos return 0;
420e552da7Schristos }
430e552da7Schristos
uv__platform_loop_delete(uv_loop_t * loop)440e552da7Schristos void uv__platform_loop_delete(uv_loop_t* loop) {
450e552da7Schristos uv__free(loop->poll_fds);
460e552da7Schristos loop->poll_fds = NULL;
470e552da7Schristos }
480e552da7Schristos
uv__io_fork(uv_loop_t * loop)490e552da7Schristos int uv__io_fork(uv_loop_t* loop) {
500e552da7Schristos uv__platform_loop_delete(loop);
510e552da7Schristos return uv__platform_loop_init(loop);
520e552da7Schristos }
530e552da7Schristos
540e552da7Schristos /* Allocate or dynamically resize our poll fds array. */
uv__pollfds_maybe_resize(uv_loop_t * loop)550e552da7Schristos static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
560e552da7Schristos size_t i;
570e552da7Schristos size_t n;
580e552da7Schristos struct pollfd* p;
590e552da7Schristos
600e552da7Schristos if (loop->poll_fds_used < loop->poll_fds_size)
610e552da7Schristos return;
620e552da7Schristos
630e552da7Schristos n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
640e552da7Schristos p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));
650e552da7Schristos if (p == NULL)
660e552da7Schristos abort();
670e552da7Schristos
680e552da7Schristos loop->poll_fds = p;
690e552da7Schristos for (i = loop->poll_fds_size; i < n; i++) {
700e552da7Schristos loop->poll_fds[i].fd = -1;
710e552da7Schristos loop->poll_fds[i].events = 0;
720e552da7Schristos loop->poll_fds[i].revents = 0;
730e552da7Schristos }
740e552da7Schristos loop->poll_fds_size = n;
750e552da7Schristos }
760e552da7Schristos
770e552da7Schristos /* Primitive swap operation on poll fds array elements. */
uv__pollfds_swap(uv_loop_t * loop,size_t l,size_t r)780e552da7Schristos static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) {
790e552da7Schristos struct pollfd pfd;
800e552da7Schristos pfd = loop->poll_fds[l];
810e552da7Schristos loop->poll_fds[l] = loop->poll_fds[r];
820e552da7Schristos loop->poll_fds[r] = pfd;
830e552da7Schristos }
840e552da7Schristos
850e552da7Schristos /* Add a watcher's fd to our poll fds array with its pending events. */
uv__pollfds_add(uv_loop_t * loop,uv__io_t * w)860e552da7Schristos static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) {
870e552da7Schristos size_t i;
880e552da7Schristos struct pollfd* pe;
890e552da7Schristos
900e552da7Schristos /* If the fd is already in the set just update its events. */
910e552da7Schristos assert(!loop->poll_fds_iterating);
920e552da7Schristos for (i = 0; i < loop->poll_fds_used; ++i) {
930e552da7Schristos if (loop->poll_fds[i].fd == w->fd) {
940e552da7Schristos loop->poll_fds[i].events = w->pevents;
950e552da7Schristos return;
960e552da7Schristos }
970e552da7Schristos }
980e552da7Schristos
990e552da7Schristos /* Otherwise, allocate a new slot in the set for the fd. */
1000e552da7Schristos uv__pollfds_maybe_resize(loop);
1010e552da7Schristos pe = &loop->poll_fds[loop->poll_fds_used++];
1020e552da7Schristos pe->fd = w->fd;
1030e552da7Schristos pe->events = w->pevents;
1040e552da7Schristos }
1050e552da7Schristos
1060e552da7Schristos /* Remove a watcher's fd from our poll fds array. */
uv__pollfds_del(uv_loop_t * loop,int fd)1070e552da7Schristos static void uv__pollfds_del(uv_loop_t* loop, int fd) {
1080e552da7Schristos size_t i;
1090e552da7Schristos assert(!loop->poll_fds_iterating);
1100e552da7Schristos for (i = 0; i < loop->poll_fds_used;) {
1110e552da7Schristos if (loop->poll_fds[i].fd == fd) {
1120e552da7Schristos /* swap to last position and remove */
1130e552da7Schristos --loop->poll_fds_used;
1140e552da7Schristos uv__pollfds_swap(loop, i, loop->poll_fds_used);
1150e552da7Schristos loop->poll_fds[loop->poll_fds_used].fd = -1;
1160e552da7Schristos loop->poll_fds[loop->poll_fds_used].events = 0;
1170e552da7Schristos loop->poll_fds[loop->poll_fds_used].revents = 0;
1180e552da7Schristos /* This method is called with an fd of -1 to purge the invalidated fds,
1190e552da7Schristos * so we may possibly have multiples to remove.
1200e552da7Schristos */
1210e552da7Schristos if (-1 != fd)
1220e552da7Schristos return;
1230e552da7Schristos } else {
1240e552da7Schristos /* We must only increment the loop counter when the fds do not match.
1250e552da7Schristos * Otherwise, when we are purging an invalidated fd, the value just
1260e552da7Schristos * swapped here from the previous end of the array will be skipped.
1270e552da7Schristos */
1280e552da7Schristos ++i;
1290e552da7Schristos }
1300e552da7Schristos }
1310e552da7Schristos }
1320e552da7Schristos
1330e552da7Schristos
uv__io_poll(uv_loop_t * loop,int timeout)1340e552da7Schristos void uv__io_poll(uv_loop_t* loop, int timeout) {
1350e552da7Schristos sigset_t* pset;
1360e552da7Schristos sigset_t set;
1370e552da7Schristos uint64_t time_base;
1380e552da7Schristos uint64_t time_diff;
1390e552da7Schristos QUEUE* q;
1400e552da7Schristos uv__io_t* w;
1410e552da7Schristos size_t i;
1420e552da7Schristos unsigned int nevents;
1430e552da7Schristos int nfds;
1440e552da7Schristos int have_signals;
1450e552da7Schristos struct pollfd* pe;
1460e552da7Schristos int fd;
147*5f2f4271Schristos int user_timeout;
148*5f2f4271Schristos int reset_timeout;
1490e552da7Schristos
1500e552da7Schristos if (loop->nfds == 0) {
1510e552da7Schristos assert(QUEUE_EMPTY(&loop->watcher_queue));
1520e552da7Schristos return;
1530e552da7Schristos }
1540e552da7Schristos
1550e552da7Schristos /* Take queued watchers and add their fds to our poll fds array. */
1560e552da7Schristos while (!QUEUE_EMPTY(&loop->watcher_queue)) {
1570e552da7Schristos q = QUEUE_HEAD(&loop->watcher_queue);
1580e552da7Schristos QUEUE_REMOVE(q);
1590e552da7Schristos QUEUE_INIT(q);
1600e552da7Schristos
1610e552da7Schristos w = QUEUE_DATA(q, uv__io_t, watcher_queue);
1620e552da7Schristos assert(w->pevents != 0);
1630e552da7Schristos assert(w->fd >= 0);
1640e552da7Schristos assert(w->fd < (int) loop->nwatchers);
1650e552da7Schristos
1660e552da7Schristos uv__pollfds_add(loop, w);
1670e552da7Schristos
1680e552da7Schristos w->events = w->pevents;
1690e552da7Schristos }
1700e552da7Schristos
1710e552da7Schristos /* Prepare a set of signals to block around poll(), if any. */
1720e552da7Schristos pset = NULL;
1730e552da7Schristos if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
1740e552da7Schristos pset = &set;
1750e552da7Schristos sigemptyset(pset);
1760e552da7Schristos sigaddset(pset, SIGPROF);
1770e552da7Schristos }
1780e552da7Schristos
1790e552da7Schristos assert(timeout >= -1);
1800e552da7Schristos time_base = loop->time;
1810e552da7Schristos
182*5f2f4271Schristos if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
183*5f2f4271Schristos reset_timeout = 1;
184*5f2f4271Schristos user_timeout = timeout;
185*5f2f4271Schristos timeout = 0;
186*5f2f4271Schristos } else {
187*5f2f4271Schristos reset_timeout = 0;
188*5f2f4271Schristos }
189*5f2f4271Schristos
1900e552da7Schristos /* Loop calls to poll() and processing of results. If we get some
1910e552da7Schristos * results from poll() but they turn out not to be interesting to
1920e552da7Schristos * our caller then we need to loop around and poll() again.
1930e552da7Schristos */
1940e552da7Schristos for (;;) {
195*5f2f4271Schristos /* Only need to set the provider_entry_time if timeout != 0. The function
196*5f2f4271Schristos * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
197*5f2f4271Schristos */
198*5f2f4271Schristos if (timeout != 0)
199*5f2f4271Schristos uv__metrics_set_provider_entry_time(loop);
200*5f2f4271Schristos
2010e552da7Schristos if (pset != NULL)
2020e552da7Schristos if (pthread_sigmask(SIG_BLOCK, pset, NULL))
2030e552da7Schristos abort();
2040e552da7Schristos nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout);
2050e552da7Schristos if (pset != NULL)
2060e552da7Schristos if (pthread_sigmask(SIG_UNBLOCK, pset, NULL))
2070e552da7Schristos abort();
2080e552da7Schristos
2090e552da7Schristos /* Update loop->time unconditionally. It's tempting to skip the update when
2100e552da7Schristos * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
2110e552da7Schristos * operating system didn't reschedule our process while in the syscall.
2120e552da7Schristos */
2130e552da7Schristos SAVE_ERRNO(uv__update_time(loop));
2140e552da7Schristos
2150e552da7Schristos if (nfds == 0) {
216*5f2f4271Schristos if (reset_timeout != 0) {
217*5f2f4271Schristos timeout = user_timeout;
218*5f2f4271Schristos reset_timeout = 0;
219*5f2f4271Schristos if (timeout == -1)
220*5f2f4271Schristos continue;
221*5f2f4271Schristos if (timeout > 0)
222*5f2f4271Schristos goto update_timeout;
223*5f2f4271Schristos }
224*5f2f4271Schristos
2250e552da7Schristos assert(timeout != -1);
2260e552da7Schristos return;
2270e552da7Schristos }
2280e552da7Schristos
2290e552da7Schristos if (nfds == -1) {
2300e552da7Schristos if (errno != EINTR)
2310e552da7Schristos abort();
2320e552da7Schristos
233*5f2f4271Schristos if (reset_timeout != 0) {
234*5f2f4271Schristos timeout = user_timeout;
235*5f2f4271Schristos reset_timeout = 0;
236*5f2f4271Schristos }
237*5f2f4271Schristos
2380e552da7Schristos if (timeout == -1)
2390e552da7Schristos continue;
2400e552da7Schristos
2410e552da7Schristos if (timeout == 0)
2420e552da7Schristos return;
2430e552da7Schristos
2440e552da7Schristos /* Interrupted by a signal. Update timeout and poll again. */
2450e552da7Schristos goto update_timeout;
2460e552da7Schristos }
2470e552da7Schristos
2480e552da7Schristos /* Tell uv__platform_invalidate_fd not to manipulate our array
2490e552da7Schristos * while we are iterating over it.
2500e552da7Schristos */
2510e552da7Schristos loop->poll_fds_iterating = 1;
2520e552da7Schristos
2530e552da7Schristos /* Initialize a count of events that we care about. */
2540e552da7Schristos nevents = 0;
2550e552da7Schristos have_signals = 0;
2560e552da7Schristos
2570e552da7Schristos /* Loop over the entire poll fds array looking for returned events. */
2580e552da7Schristos for (i = 0; i < loop->poll_fds_used; i++) {
2590e552da7Schristos pe = loop->poll_fds + i;
2600e552da7Schristos fd = pe->fd;
2610e552da7Schristos
2620e552da7Schristos /* Skip invalidated events, see uv__platform_invalidate_fd. */
2630e552da7Schristos if (fd == -1)
2640e552da7Schristos continue;
2650e552da7Schristos
2660e552da7Schristos assert(fd >= 0);
2670e552da7Schristos assert((unsigned) fd < loop->nwatchers);
2680e552da7Schristos
2690e552da7Schristos w = loop->watchers[fd];
2700e552da7Schristos
2710e552da7Schristos if (w == NULL) {
2720e552da7Schristos /* File descriptor that we've stopped watching, ignore. */
2730e552da7Schristos uv__platform_invalidate_fd(loop, fd);
2740e552da7Schristos continue;
2750e552da7Schristos }
2760e552da7Schristos
2770e552da7Schristos /* Filter out events that user has not requested us to watch
2780e552da7Schristos * (e.g. POLLNVAL).
2790e552da7Schristos */
2800e552da7Schristos pe->revents &= w->pevents | POLLERR | POLLHUP;
2810e552da7Schristos
2820e552da7Schristos if (pe->revents != 0) {
2830e552da7Schristos /* Run signal watchers last. */
2840e552da7Schristos if (w == &loop->signal_io_watcher) {
2850e552da7Schristos have_signals = 1;
2860e552da7Schristos } else {
287*5f2f4271Schristos uv__metrics_update_idle_time(loop);
2880e552da7Schristos w->cb(loop, w, pe->revents);
2890e552da7Schristos }
2900e552da7Schristos
2910e552da7Schristos nevents++;
2920e552da7Schristos }
2930e552da7Schristos }
2940e552da7Schristos
295*5f2f4271Schristos if (reset_timeout != 0) {
296*5f2f4271Schristos timeout = user_timeout;
297*5f2f4271Schristos reset_timeout = 0;
298*5f2f4271Schristos }
299*5f2f4271Schristos
300*5f2f4271Schristos if (have_signals != 0) {
301*5f2f4271Schristos uv__metrics_update_idle_time(loop);
3020e552da7Schristos loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
303*5f2f4271Schristos }
3040e552da7Schristos
3050e552da7Schristos loop->poll_fds_iterating = 0;
3060e552da7Schristos
3070e552da7Schristos /* Purge invalidated fds from our poll fds array. */
3080e552da7Schristos uv__pollfds_del(loop, -1);
3090e552da7Schristos
3100e552da7Schristos if (have_signals != 0)
3110e552da7Schristos return; /* Event loop should cycle now so don't poll again. */
3120e552da7Schristos
3130e552da7Schristos if (nevents != 0)
3140e552da7Schristos return;
3150e552da7Schristos
3160e552da7Schristos if (timeout == 0)
3170e552da7Schristos return;
3180e552da7Schristos
3190e552da7Schristos if (timeout == -1)
3200e552da7Schristos continue;
3210e552da7Schristos
3220e552da7Schristos update_timeout:
3230e552da7Schristos assert(timeout > 0);
3240e552da7Schristos
3250e552da7Schristos time_diff = loop->time - time_base;
3260e552da7Schristos if (time_diff >= (uint64_t) timeout)
3270e552da7Schristos return;
3280e552da7Schristos
3290e552da7Schristos timeout -= time_diff;
3300e552da7Schristos }
3310e552da7Schristos }
3320e552da7Schristos
3330e552da7Schristos /* Remove the given fd from our poll fds array because no one
3340e552da7Schristos * is interested in its events anymore.
3350e552da7Schristos */
uv__platform_invalidate_fd(uv_loop_t * loop,int fd)3360e552da7Schristos void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
3370e552da7Schristos size_t i;
3380e552da7Schristos
3390e552da7Schristos assert(fd >= 0);
3400e552da7Schristos
3410e552da7Schristos if (loop->poll_fds_iterating) {
3420e552da7Schristos /* uv__io_poll is currently iterating. Just invalidate fd. */
3430e552da7Schristos for (i = 0; i < loop->poll_fds_used; i++)
3440e552da7Schristos if (loop->poll_fds[i].fd == fd) {
3450e552da7Schristos loop->poll_fds[i].fd = -1;
3460e552da7Schristos loop->poll_fds[i].events = 0;
3470e552da7Schristos loop->poll_fds[i].revents = 0;
3480e552da7Schristos }
3490e552da7Schristos } else {
3500e552da7Schristos /* uv__io_poll is not iterating. Delete fd from the set. */
3510e552da7Schristos uv__pollfds_del(loop, fd);
3520e552da7Schristos }
3530e552da7Schristos }
3540e552da7Schristos
3550e552da7Schristos /* Check whether the given fd is supported by poll(). */
uv__io_check_fd(uv_loop_t * loop,int fd)3560e552da7Schristos int uv__io_check_fd(uv_loop_t* loop, int fd) {
3570e552da7Schristos struct pollfd p[1];
3580e552da7Schristos int rv;
3590e552da7Schristos
3600e552da7Schristos p[0].fd = fd;
3610e552da7Schristos p[0].events = POLLIN;
3620e552da7Schristos
3630e552da7Schristos do
3640e552da7Schristos rv = poll(p, 1, 0);
3650e552da7Schristos while (rv == -1 && (errno == EINTR || errno == EAGAIN));
3660e552da7Schristos
3670e552da7Schristos if (rv == -1)
3680e552da7Schristos return UV__ERR(errno);
3690e552da7Schristos
3700e552da7Schristos if (p[0].revents & POLLNVAL)
3710e552da7Schristos return UV_EINVAL;
3720e552da7Schristos
3730e552da7Schristos return 0;
3740e552da7Schristos }
375