42#if _POSIX_C_SOURCE >= 200112L
43#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
58#if _WIN32 || _POSIX_C_SOURCE >= 200112L
62#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
84#define io_poll_lock(poll)
85#define io_poll_unlock(poll)
88static void io_poll_unlock(
io_poll_t *poll);
91static struct io_watch *io_poll_insert(
95#if _POSIX_C_SOURCE >= 200112L \
96 && !(defined(__linux__) && defined(HAVE_SYS_EPOLL_H))
97static int _poll(
struct pollfd *fds, nfds_t nfds,
int timeout);
103 void *ptr = malloc(
sizeof(
struct __io_poll));
110__io_poll_free(
void *ptr)
126#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
138#if _WIN32 || _POSIX_C_SOURCE >= 200112L
147 goto error_open_pipe;
153 goto error_set_flags;
157 goto error_set_flags;
161#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
162 poll->
epfd = epoll_create1(EPOLL_CLOEXEC);
163 if (poll->
epfd == -1) {
165 goto error_epoll_create1;
169 struct epoll_event ev = { .events = EPOLLIN,
170 .data.ptr = poll->
pipe[0] };
171 if (epoll_ctl(poll->
epfd, EPOLL_CTL_ADD, poll->
pipe[0]->
fd, &ev)
174 goto error_epoll_ctl;
180#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
185#if _WIN32 || _POSIX_C_SOURCE >= 200112L
203#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
207#if _WIN32 || _POSIX_C_SOURCE >= 200112L
225 goto error_alloc_poll;
228 if (!__io_poll_init(poll)) {
230 goto error_init_poll;
236 __io_poll_free(poll);
246 __io_poll_fini(poll);
247 __io_poll_free(poll);
262 assert(handle->
vtab);
264#if defined(__linux__) && defined(HAVE_LINUX_CAN_H)
267#if _POSIX_C_SOURCE >= 200112L
272#if _WIN32 || _POSIX_C_SOURCE >= 200112L
284#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
295 watch = io_poll_insert(poll,
handle);
306#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
309 int op =
node ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
311 struct epoll_event ev = { 0, { NULL } };
313 ev.events |= EPOLLIN | EPOLLRDHUP | EPOLLPRI;
315 ev.events |= EPOLLOUT;
316 ev.data.ptr = watch->
handle;
318 if (epoll_ctl(poll->
epfd, op, watch->
handle->
fd, &ev) == -1) {
320 goto error_epoll_ctl;
329#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
331 epoll_ctl(poll->
epfd, EPOLL_CTL_DEL, watch->
handle->
fd, NULL);
333 io_poll_remove(poll, watch);
336 io_poll_unlock(poll);
340#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
342 epoll_ctl(poll->
epfd, EPOLL_CTL_DEL, watch->
handle->
fd, NULL);
344 io_poll_remove(poll, watch);
346 io_poll_unlock(poll);
362 if (!maxevents || !events)
366#if _WIN32 || _POSIX_C_SOURCE >= 200112L
367 unsigned char sig = 0;
381 FD_SET((SOCKET)poll->
pipe[0]->
fd, &readfds);
390 io_poll_remove(poll, watch);
394 SOCKET fd = (SOCKET)watch->
handle->
fd;
396 FD_SET(fd, &readfds);
399 FD_SET(fd, &writefds);
401 FD_SET(fd, &errorfds);
403 io_poll_unlock(poll);
405 struct timeval tv = { .tv_sec = timeout / 1000,
406 .tv_usec = (timeout % 1000) * 1000 };
407 int result = select(0, &readfds, nwritefds ? &writefds : NULL,
408 &errorfds, timeout >= 0 ? &tv : NULL);
413 if (FD_ISSET((SOCKET)poll->
pipe[0]->
fd, &readfds))
418 while (node && nevents < maxevents) {
423 io_poll_remove(poll, watch);
427 events[nevents].
events = 0;
428 if (FD_ISSET((SOCKET)watch->
handle->
fd, &readfds)
431 if (FD_ISSET((SOCKET)watch->
handle->
fd, &writefds)
434 if (FD_ISSET((SOCKET)watch->
handle->
fd, &errorfds))
437 if (!events[nevents].events)
440 events[nevents].u = watch->
event.
u;
444 io_poll_remove(poll, watch);
446 io_poll_unlock(poll);
447#elif _POSIX_C_SOURCE >= 200112L
448#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
449 struct epoll_event ev[maxevents];
454 nfds = epoll_wait(poll->
epfd, ev, maxevents,
455 timeout >= 0 ? timeout : -1);
456 }
while (nfds == -1 && errno == EINTR);
461 for (
int i = 0; i < nfds; i++) {
463 if (ev[i].data.ptr == poll->
pipe[0]) {
474 events[nevents].
events = 0;
478 if (ev[i].events & (EPOLLRDHUP | EPOLLPRI | EPOLLERR
482 if (ev[i].events & EPOLLIN)
484 if (ev[i].events & EPOLLOUT)
486 events[nevents].
u = watch->
event.
u;
493 io_poll_remove(poll, watch);
496 io_poll_unlock(poll);
502 fds[nfds].fd = poll->
pipe[0]->
fd;
503 fds[nfds].events = POLLIN;
511 io_poll_remove(poll, watch);
516 fds[nfds].events = 0;
518 fds[nfds].events |= POLLIN | POLLPRI;
520 fds[nfds].events |= POLLOUT;
523 io_poll_unlock(poll);
529 n = _poll(fds, nfds, timeout >= 0 ? timeout : -1);
530 }
while (n == -1 && errno == EINTR);
533 maxevents =
MIN(n, maxevents);
536 for (nfds_t nfd = 0; nfd < nfds && nevents < maxevents; nfd++) {
538 if (fds[nfd].fd == poll->
pipe[0]->
fd) {
543 events[nevents].
events = 0;
545 if (fds[nfd].revents & (POLLPRI | POLLERR | POLLHUP | POLLNVAL))
548 if (fds[nfd].revents & POLLIN)
550 if (fds[nfd].revents & POLLOUT)
553 if (!events[nevents].events)
562 events[nevents].u = watch->
event.
u;
567 io_poll_remove(poll, watch);
569 io_poll_unlock(poll);
575#if _WIN32 || _POSIX_C_SOURCE >= 200112L
579 while (nevents < maxevents
582 events[nevents].
u.
sig = sig;
591#if _WIN32 || _POSIX_C_SOURCE >= 200112L
627 struct io_watch *watch = malloc(
sizeof(*watch));
632#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
654#if _POSIX_C_SOURCE >= 200112L \
655 && !(defined(__linux__) && defined(HAVE_SYS_EPOLL_H))
657_poll(
struct pollfd *fds, nfds_t nfds,
int timeout)
659 return poll(fds, nfds, timeout);
This header file is part of the utilities library; it contains the comparison function definitions.
This header file is part of the utilities library; it contains the native and platform-independent er...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
@ ERRNUM_BADF
Bad file descriptor.
@ ERRNUM_INVAL
Invalid argument.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
This is the internal header file of the I/O handle declarations.
int io_close(io_handle_t handle)
Closes an I/O device.
@ IO_TYPE_FILE
A regular file.
@ IO_TYPE_SERIAL
A serial I/O device.
@ IO_TYPE_CAN
A CAN device.
@ IO_TYPE_SOCK
A network socket.
ssize_t io_read(io_handle_t handle, void *buf, size_t nbytes)
Performs a read operation.
io_handle_t io_handle_acquire(io_handle_t handle)
Increments the reference count of an I/O device handle.
int io_handle_unique(io_handle_t handle)
Returns 1 if there is only a single reference to the specified I/O device handle, and 0 otherwise.
int io_set_flags(io_handle_t handle, int flags)
Sets the flags of an I/O device.
@ IO_FLAG_NONBLOCK
Perform I/O operations in non-blocking mode.
ssize_t io_write(io_handle_t handle, const void *buf, size_t nbytes)
Performs a write operation.
void io_handle_release(io_handle_t handle)
Decrements the reference count of an I/O device handle.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
#define MIN(a, b)
Returns the minimum of a and b.
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.
int io_poll_signal(io_poll_t *poll, unsigned char sig)
Generates a signal event.
int io_poll_wait(io_poll_t *poll, int maxevents, struct io_event *events, int timeout)
Waits at most timeout milliseconds for at most maxevents I/O events to occur for any of the I/O devic...
This header file is part of the I/O library; it contains I/O polling interface declarations.
@ IO_EVENT_READ
An event signaling that a file descriptor is ready for reading normal-priority (non-OOB) data.
@ IO_EVENT_WRITE
An event signaling that a file descriptor is ready for writing normal-priority (non-OOB) data.
@ IO_EVENT_SIGNAL
An event representing the occurrence of a signal.
@ IO_EVENT_ERROR
An event signaling that an error has occurred for a file descriptor.
This header file is part of the I/O library; it contains the pipe declarations.
int io_open_pipe(io_handle_t handle_vector[2])
Opens a pipe.
This header file is part of the utilities library; it contains the red-black tree declarations.
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.
struct rbnode * rbtree_first(const struct rbtree *tree)
Returns a pointer to the first (leftmost) node in a red-black tree.
struct rbnode * rbnode_next(const struct rbnode *node)
Returns a pointer to the next (in-order) node in a red-black tree with respect to node.
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.
#define rbtree_foreach(tree, node)
Iterates over each node in a red-black tree in ascending order.
This header file is part of the I/O library; it contains the network socket declarations.
int io_open_socketpair(int domain, int type, io_handle_t handle_vector[2])
Opens a pair of connected sockets.
@ IO_SOCK_STREAM
A stream-oriented connection-mode socket type.
@ IO_SOCK_IPV4
An IPv4 socket.
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.
io_handle_t pipe[2]
A self-pipe used to generate signal events.
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.
unsigned char sig
The signal number (if events == IO_EVENT_SIGNAL).
int events
The events that should be watched or have been triggered (either IO_EVENT_SIGNAL, or any combination ...
union io_event::@13 u
Signal attributes depending on the value of events.
int type
The type of the device (one of IO_TYPE_CAN, IO_TYPE_FILE, IO_TYPE_PIPE, IO_TYPE_SERIAL or IO_TYPE_SOC...
int fd
The native file descriptor.
const struct io_handle_vtab * vtab
A pointer to the virtual table.
An object representing a file descriptor being monitored for I/O events.
The attributes of an I/O device handle being watched.
struct rbnode node
The node in the tree of file descriptors.
struct io_handle * handle
A pointer to the I/O device handle.
struct io_event event
The events being watched.
int keep
A flag indicating whether to keep watching the file descriptor after an event occurs.
A node in a red-black tree.
const void * key
A pointer to the key for this node.
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values:
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.