26 #if !LELY_NO_STDIO && defined(__linux__)
42 #include <sys/epoll.h>
45 #define EPOLL_EVENT_INIT(events, fd) \
47 (((events) & IO_EVENT_IN) ? (EPOLLIN | EPOLLRDHUP) : 0) \
48 | (((events) & IO_EVENT_PRI) ? EPOLLPRI : 0) \
49 | (((events) & IO_EVENT_OUT) ? EPOLLOUT : 0) \
55 #ifndef LELY_IO_EPOLL_MAXEVENTS
56 #define LELY_IO_EPOLL_MAXEVENTS \
57 MAX((LELY_VLA_SIZE_MAX / sizeof(struct epoll_event)), 1)
70 static const struct io_svc_vtbl io_poll_svc_vtbl = {
71 &io_poll_svc_notify_fork,
76 static void *io_poll_poll_self(
const ev_poll_t *poll);
77 static int io_poll_poll_wait(
ev_poll_t *poll,
int timeout);
78 static int io_poll_poll_kill(
ev_poll_t *poll,
void *thr);
93 struct sigaction oact;
106 static int io_poll_open(
io_poll_t *poll);
107 static int io_poll_close(
io_poll_t *poll);
109 static void io_poll_process(
112 static int io_fd_cmp(
const void *p1,
const void *p2);
117 static void sig_ign(
int signo);
126 io_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))) {
173 if ((errsv = pthread_mutex_init(&poll->
mtx, NULL)))
180 if (io_poll_open(poll) == -1) {
192 pthread_mutex_destroy(&poll->
mtx);
196 sigprocmask(SIG_SETMASK, &poll->oset, NULL);
198 pthread_sigmask(SIG_SETMASK, &poll->oset, NULL);
201 sigaction(poll->signo, &poll->oact, NULL);
217 pthread_mutex_destroy(&poll->
mtx);
223 sigaddset(&set, poll->signo);
225 while (sigtimedwait(&set, &(siginfo_t){ 0 }, &(
struct timespec){ 0, 0 })
231 sigprocmask(SIG_SETMASK, &poll->oset, NULL);
233 pthread_sigmask(SIG_SETMASK, &poll->oset, NULL);
235 sigaction(poll->signo, &poll->oact, NULL);
249 io_poll_t *tmp = io_poll_init(poll, ctx, signo);
283 return &poll->poll_vptr;
291 int epfd = poll->
epfd;
293 if (fd == -1 || fd == epfd) {
302 events &= IO_EVENT_MASK;
307 pthread_mutex_lock(&poll->
mtx);
311 if (node && node != &watch->_node) {
317 struct epoll_event event = EPOLL_EVENT_INIT(events, fd);
318 if (node && events != watch->_events) {
319 if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event) == -1) {
321 epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
329 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) == -1) {
340 watch->_events = events;
342 epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
353 pthread_mutex_unlock(&poll->
mtx);
370 if (io_poll_close(poll) == -1) {
375 if (io_poll_open(poll) == -1 && !result) {
380 int epfd = poll->
epfd;
384 int events = watch->_events;
386 struct epoll_event event = EPOLL_EVENT_INIT(events, fd);
388 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) == -1) {
415 thread = pthread_self();
416 thr.thread = &thread;
423 io_poll_poll_wait(
ev_poll_t *poll_,
int timeout)
425 io_poll_t *poll = io_poll_from_poll(poll_);
426 void *thr_ = io_poll_poll_self(poll_);
435 struct epoll_event events[LELY_IO_EPOLL_MAXEVENTS];
438 pthread_mutex_lock(&poll->
mtx);
452 pthread_mutex_unlock(&poll->
mtx);
455 int nevents = epoll_pwait(poll->
epfd, events,
456 LELY_IO_EPOLL_MAXEVENTS, timeout, &set);
457 if (nevents == -1 && errno == EINTR) {
464 sigaddset(&set, poll->signo);
466 pthread_mutex_lock(&poll->
mtx);
477 pthread_mutex_lock(&poll->
mtx);
482 for (
int i = 0; i < nevents; i++) {
484 if (events[i].events & (EPOLLIN | EPOLLRDHUP))
486 if (events[i].events & EPOLLPRI)
488 if (events[i].events & EPOLLOUT)
490 if (events[i].events & EPOLLERR)
492 if (events[i].events & EPOLLHUP)
494 int fd = events[i].data.fd;
496 pthread_mutex_lock(&poll->
mtx);
501 io_poll_watch_from_node(node);
502 io_poll_process(poll, revents, watch);
506 pthread_mutex_unlock(&poll->
mtx);
511 pthread_mutex_lock(&poll->
mtx);
514 stopped = nevents != LELY_IO_EPOLL_MAXEVENTS;
518 pthread_mutex_unlock(&poll->
mtx);
526 io_poll_poll_kill(
ev_poll_t *poll_,
void *thr_)
529 io_poll_t *poll = io_poll_from_poll(poll_);
534 if (thr_ == io_poll_poll_self(poll_))
538 pthread_mutex_lock(&poll->
mtx);
540 int stopped = thr->stopped;
544 pthread_mutex_unlock(&poll->
mtx);
546 int errsv = pthread_kill(*thr->thread, poll->signo);
557 io_poll_from_svc(
const struct io_svc *svc)
575 if (io_poll_close(poll) == -1)
578 return (poll->
epfd = epoll_create1(EPOLL_CLOEXEC)) == -1 ? -1 : 0;
586 int epfd = poll->
epfd;
598 assert(poll->nwatch);
600 assert(watch->_events);
607 pthread_mutex_unlock(&poll->
mtx);
609 watch->
func(watch, revents);
611 pthread_mutex_lock(&poll->
mtx);
617 io_fd_cmp(
const void *p1,
const void *p2)
620 int fd1 = *(
const int *)p1;
622 int fd2 = *(
const int *)p2;
624 return (fd2 < fd1) - (fd1 < fd2);
628 io_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.
io_fork_event
The type of event generated by an I/O context before and after a process fork.
@ IO_FORK_CHILD
The event generated after the fork in the child process.
#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.
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.
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.
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.
This header file is part of the I/O library; it contains the I/O polling declarations for POSIX platf...
int io_poll_watch(io_poll_t *poll, io_handle_t handle, struct io_event *event, int keep)
Registers an I/O device with an I/O polling interface and instructs it to watch for certain events.
io_poll_t * io_poll_create(void)
Creates a new I/O polling interface.
void io_poll_destroy(io_poll_t *poll)
Destroys an 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.
void rbtree_init(struct rbtree *tree, rbtree_cmp_t *cmp)
Initializes a red-black tree.
void rbtree_remove(struct rbtree *tree, struct rbnode *node)
Removes a node from a red-black tree.
#define rbtree_foreach(tree, node)
Iterates over each node in a red-black tree in ascending order.
struct rbnode * rbtree_find(const struct rbtree *tree, const void *key)
Finds a node in a red-black tree.
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.
int epfd
The epoll file descriptor.
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.
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....