26#if !LELY_NO_STDIO && _POSIX_C_SOURCE >= 200112L
43#ifndef LELY_HAVE_PPOLL
46#if defined(__linux__) || (__FreeBSD__ >= 11)
47#define LELY_HAVE_PPOLL 1
54#include <sys/select.h>
58#ifndef LELY_IO_PPOLL_NFDS
59#define LELY_IO_PPOLL_NFDS MAX((LELY_VLA_SIZE_MAX / sizeof(struct pollfd)), 1)
78static void *io_poll_poll_self(
const ev_poll_t *poll);
79static int io_poll_poll_wait(
ev_poll_t *poll,
int timeout);
80static int io_poll_poll_kill(
ev_poll_t *poll,
void *thr);
95 struct sigaction oact;
109static void io_poll_process(
112static int io_fd_cmp(
const void *p1,
const void *p2);
117static void sig_ign(
int signo);
126io_poll_free(
void *ptr)
145 poll->poll_vptr = &io_poll_poll_vtbl;
149 struct sigaction act;
150 act.sa_handler = &sig_ign;
151 sigemptyset(&act.sa_mask);
153 if (sigaction(poll->signo, &act, &poll->oact) == -1) {
155 goto error_sigaction;
161 sigaddset(&set, poll->signo);
163 if (sigprocmask(SIG_BLOCK, &set, &poll->oset) == -1) {
166 if ((errsv = pthread_sigmask(SIG_BLOCK, &set, &poll->oset))) {
172 if ((errsv = pthread_mutex_init(&poll->
mtx, NULL)))
191 sigprocmask(SIG_SETMASK, &poll->oset, NULL);
193 pthread_sigmask(SIG_SETMASK, &poll->oset, NULL);
196 sigaction(poll->signo, &poll->oact, NULL);
214 pthread_mutex_destroy(&poll->
mtx);
220 sigaddset(&set, poll->signo);
222 while (sigtimedwait(&set, &(siginfo_t){ 0 }, &(
struct timespec){ 0, 0 })
228 sigprocmask(SIG_SETMASK, &poll->oset, NULL);
230 pthread_sigmask(SIG_SETMASK, &poll->oset, NULL);
232 sigaction(poll->signo, &poll->oact, NULL);
246 io_poll_t *tmp = io_poll_init(poll, ctx, signo);
280 return &poll->poll_vptr;
298 events &= IO_EVENT_MASK;
303 pthread_mutex_lock(&poll->
mtx);
308 if (node != &watch->_node) {
328 if (events != watch->_events) {
329 watch->_events = events;
337 pthread_kill(*thr->thread, poll->signo);
347 pthread_mutex_unlock(&poll->
mtx);
364 thread = pthread_self();
365 thr.thread = &thread;
372io_poll_poll_wait(
ev_poll_t *poll_,
int timeout_)
374 io_poll_t *poll = io_poll_from_poll(poll_);
375 void *thr_ = io_poll_poll_self(poll_);
380 tv.
tv_sec = timeout_ / 1000;
381 tv.
tv_nsec = (timeout_ % 1000) * 1000000l;
383 struct timespec *timeout = timeout_ >= 0 ? &tv : NULL;
392 struct pollfd fds_[LELY_IO_PPOLL_NFDS];
393 struct pollfd *fds = fds_;
395 fd_set rfds, wfds, efds;
399 pthread_mutex_lock(&poll->
mtx);
420 if (nfds > LELY_IO_PPOLL_NFDS) {
421 fds = malloc(nfds *
sizeof(*fds));
432 io_poll_watch_from_node(node);
437 events |= POLLRDBAND | POLLPRI;
440 fds[i++] = (
struct pollfd){ .fd = watch->_fd,
455 io_poll_watch_from_node(node);
457 FD_SET(watch->_fd, &rfds);
458 nrfds =
MAX(nrfds, watch->_fd + 1);
461 FD_SET(watch->_fd, &wfds);
462 nwfds =
MAX(nwfds, watch->_fd + 1);
464 FD_SET(watch->_fd, &efds);
465 nefds =
MAX(nefds, watch->_fd + 1);
470 pthread_mutex_unlock(&poll->
mtx);
474 int result = ppoll(fds, nfds, timeout, &set);
476 int result = pselect(nefds, nrfds ? &rfds : NULL,
477 nwfds ? &wfds : NULL, nefds ? &efds : NULL,
481 pthread_mutex_lock(&poll->
mtx);
484 if (errno == EINTR) {
492 sigaddset(&set, poll->signo);
503 for (i = 0; i < nfds; i++) {
504 if (!fds[i].revents || (fds[i].revents & POLLNVAL))
511 io_poll_watch_from_node(node);
513 if (fds[i].revents & POLLIN)
515 if (fds[i].revents & (POLLRDBAND | POLLPRI))
517 if (fds[i].revents & POLLOUT)
519 if (fds[i].revents & POLLERR)
521 if (fds[i].revents & POLLHUP)
523 io_poll_process(poll, revents, watch);
529 io_poll_watch_from_node(node);
533 if (FD_ISSET(watch->_fd, &rfds))
535 if (FD_ISSET(watch->_fd, &wfds))
537 if (FD_ISSET(watch->_fd, &efds)) {
544 io_poll_process(poll, revents, watch);
550 stopped = thr->stopped = 1;
557 pthread_mutex_unlock(&poll->
mtx);
570io_poll_poll_kill(
ev_poll_t *poll_,
void *thr_)
573 io_poll_t *poll = io_poll_from_poll(poll_);
578 if (thr_ == io_poll_poll_self(poll_))
582 pthread_mutex_lock(&poll->
mtx);
584 int stopped = thr->stopped;
588 pthread_mutex_unlock(&poll->
mtx);
590 int errsv = pthread_kill(*thr->thread, poll->signo);
601io_poll_from_svc(
const struct io_svc *svc)
626 pthread_mutex_unlock(&poll->
mtx);
628 watch->
func(watch, revents);
630 pthread_mutex_lock(&poll->
mtx);
636io_fd_cmp(
const void *p1,
const void *p2)
639 int fd1 = *(
const int *)p1;
641 int fd2 = *(
const int *)p2;
643 return (fd2 < fd1) - (fd1 < fd2);
647io_poll_watch_from_node(
struct rbnode *node)
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
This header file is part of the utilities library; it contains the doubly-linked list declarations.
void dllist_push_back(struct dllist *list, struct dlnode *node)
Pushes a node to the back of a doubly-linked list.
void dllist_init(struct dllist *list)
Initializes a doubly-linked list.
int dllist_empty(const struct dllist *list)
Returns 1 if the doubly-linked list is empty, and 0 if not.
#define dllist_foreach(list, node)
Iterates in order over each node in a doubly-linked list.
#define DLNODE_INIT
The static initializer for dlnode.
void dllist_remove(struct dllist *list, struct dlnode *node)
Removes a node from a doubly-linked list.
const struct ev_poll_vtbl *const ev_poll_t
The abstract polling interface.
@ IO_EVENT_HUP
The device has been disconnected.
@ IO_EVENT_IN
Data (other than priority data) MAY be read without blocking.
@ IO_EVENT_OUT
Data (bot normal and priority data) MAY be written without blocking.
@ IO_EVENT_ERR
An error has occurred. This event is always reported.
@ IO_EVENT_PRI
Priority data MAY be read without blocking.
#define _Thread_local
An object whose identifier is declared with the storage-class specifier _Thread_local has thread stor...
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
#define MAX(a, b)
Returns the maximum of a and b.
ev_poll_t * io_poll_get_poll(const io_poll_t *poll)
Returns a pointer to the ev_poll_t instance corresponding to the I/O polling instance.
io_ctx_t * io_poll_get_ctx(const io_poll_t *poll)
Returns a pointer to the I/O context with which the I/O polling instance is registered.
This header file is part of the I/O library; it contains the I/O polling declarations for POSIX platf...
This header file is part of the I/O library; it contains the I/O polling declarations for Windows.
void io_poll_destroy(io_poll_t *poll)
Destroys an I/O polling interface.
io_poll_t * io_poll_create(void)
Creates a new I/O polling interface.
void rbnode_init(struct rbnode *node, const void *key)
Initializes a node in a red-black tree.
void rbtree_insert(struct rbtree *tree, struct rbnode *node)
Inserts a node into a red-black tree.
struct rbnode * rbtree_find(const struct rbtree *tree, const void *key)
Finds a node in a red-black tree.
void rbtree_init(struct rbtree *tree, rbtree_cmp_t *cmp)
Initializes a red-black tree.
size_t rbtree_size(const struct rbtree *tree)
Returns the size (in number of nodes) of a red-black tree.
void rbtree_remove(struct rbtree *tree, struct rbnode *node)
Removes a node from a red-black tree.
int rbtree_empty(const struct rbtree *tree)
Returns 1 if the red-black tree is empty, and 0 if not.
#define rbtree_foreach(tree, node)
Iterates over each node in a red-black tree in ascending order.
This is the internal header file of the Windows-specific I/O declarations.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
An I/O polling interface.
struct rbtree tree
The tree containing the I/O device handles being watched.
mtx_t mtx
The mutex protecting tree.
A node in a doubly-linked list.
An object representing a file descriptor being monitored for I/O events.
io_poll_watch_func_t * func
A pointer to the function to be invoked when an I/O event occurs.
The virtual table of an I/O service.
A node in a red-black tree.
A time type with nanosecond resolution.
long tv_nsec
Nanoseconds [0, 999999999].
time_t tv_sec
Whole seconds (>= 0).
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....