39#if _POSIX_C_SOURCE >= 200112L
40#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
49#ifndef LELY_NO_THREADS
55#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
59#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
81#define io_poll_lock(poll)
82#define io_poll_unlock(poll)
85static void io_poll_unlock(
io_poll_t *poll);
88static struct io_watch *io_poll_insert(
92#if _POSIX_C_SOURCE >= 200112L \
93 && !(defined(__linux__) && defined(HAVE_SYS_EPOLL_H))
94static int _poll(
struct pollfd *fds, nfds_t nfds,
int timeout);
100 void *ptr = malloc(
sizeof(
struct __io_poll));
107__io_poll_free(
void *ptr)
119#ifndef LELY_NO_THREADS
123#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
135#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
140 poll->
pipe) == -1)) {
146 goto error_open_pipe;
152 goto error_set_flags;
156 goto error_set_flags;
160#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
161 poll->
epfd = epoll_create1(EPOLL_CLOEXEC);
164 goto error_epoll_create1;
168 struct epoll_event ev = { .events = EPOLLIN,
169 .data.ptr = poll->
pipe[0] };
175 goto error_epoll_ctl;
181#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
186#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
204#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
208#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
213#ifndef LELY_NO_THREADS
226 goto error_alloc_poll;
231 goto error_init_poll;
237 __io_poll_free(poll);
247 __io_poll_fini(poll);
248 __io_poll_free(poll);
263 assert(handle->
vtab);
265#if defined(__linux__) && defined(HAVE_LINUX_CAN_H)
268#if _POSIX_C_SOURCE >= 200112L
273#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
285#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
296 watch = io_poll_insert(poll,
handle);
307#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
310 int op =
node ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
312 struct epoll_event ev = { 0, { NULL } };
314 ev.events |= EPOLLIN | EPOLLRDHUP | EPOLLPRI;
316 ev.events |= EPOLLOUT;
317 ev.data.ptr = watch->
handle;
324 goto error_epoll_ctl;
333#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
335 epoll_ctl(poll->
epfd, EPOLL_CTL_DEL, watch->
handle->
fd, NULL);
337 io_poll_remove(poll, watch);
340 io_poll_unlock(poll);
344#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
346 epoll_ctl(poll->
epfd, EPOLL_CTL_DEL, watch->
handle->
fd, NULL);
348 io_poll_remove(poll, watch);
350 io_poll_unlock(poll);
370#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
371 unsigned char sig = 0;
385 FD_SET((SOCKET)poll->
pipe[0]->
fd, &readfds);
394 io_poll_remove(poll, watch);
398 SOCKET fd = (SOCKET)watch->
handle->
fd;
400 FD_SET(fd, &readfds);
403 FD_SET(fd, &writefds);
405 FD_SET(fd, &errorfds);
407 io_poll_unlock(poll);
409 struct timeval tv = { .tv_sec = timeout / 1000,
410 .tv_usec = (timeout % 1000) * 1000 };
411 int result = select(0, &readfds, nwritefds ? &writefds : NULL,
412 &errorfds, timeout >= 0 ? &tv : NULL);
417 if (FD_ISSET((SOCKET)poll->
pipe[0]->
fd, &readfds))
422 while (node && nevents < maxevents) {
427 io_poll_remove(poll, watch);
431 events[nevents].
events = 0;
432 if (FD_ISSET((SOCKET)watch->
handle->
fd, &readfds)
435 if (FD_ISSET((SOCKET)watch->
handle->
fd, &writefds)
438 if (FD_ISSET((SOCKET)watch->
handle->
fd, &errorfds))
441 if (!events[nevents].events)
444 events[nevents].u = watch->
event.
u;
448 io_poll_remove(poll, watch);
450 io_poll_unlock(poll);
451#elif _POSIX_C_SOURCE >= 200112L
452#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
453 struct epoll_event ev[maxevents];
458 nfds = epoll_wait(poll->
epfd, ev, maxevents,
459 timeout >= 0 ? timeout : -1);
460 }
while (
__unlikely(nfds == -1 && errno == EINTR));
465 for (
int i = 0; i < nfds; i++) {
467 if (ev[i].data.ptr == poll->
pipe[0]) {
478 events[nevents].
events = 0;
482 if (ev[i].events & (EPOLLRDHUP | EPOLLPRI | EPOLLERR
486 if (ev[i].events & EPOLLIN)
488 if (ev[i].events & EPOLLOUT)
490 events[nevents].
u = watch->
event.
u;
497 io_poll_remove(poll, watch);
500 io_poll_unlock(poll);
506 fds[nfds].fd = poll->
pipe[0]->
fd;
507 fds[nfds].events = POLLIN;
515 io_poll_remove(poll, watch);
520 fds[nfds].events = 0;
522 fds[nfds].events |= POLLIN | POLLPRI;
524 fds[nfds].events |= POLLOUT;
527 io_poll_unlock(poll);
533 n = _poll(fds, nfds, timeout >= 0 ? timeout : -1);
534 }
while (
__unlikely(n == -1 && errno == EINTR));
537 maxevents =
MIN(n, maxevents);
540 for (nfds_t nfd = 0; nfd < nfds && nevents < maxevents; nfd++) {
542 if (fds[nfd].fd == poll->
pipe[0]->
fd) {
547 events[nevents].
events = 0;
549 if (fds[nfd].revents & (POLLPRI | POLLERR | POLLHUP | POLLNVAL))
552 if (fds[nfd].revents & POLLIN)
554 if (fds[nfd].revents & POLLOUT)
557 if (!events[nevents].events)
566 events[nevents].u = watch->
event.
u;
571 io_poll_remove(poll, watch);
573 io_poll_unlock(poll);
579#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
583 while (nevents < maxevents
586 events[nevents].
u.
sig = sig;
595#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
605#ifndef LELY_NO_THREADS
631 struct io_watch *watch = malloc(
sizeof(*watch));
636#if defined(__linux__) && defined(HAVE_SYS_EPOLL_H)
658#if _POSIX_C_SOURCE >= 200112L \
659 && !(defined(__linux__) && defined(HAVE_SYS_EPOLL_H))
661_poll(
struct pollfd *fds, nfds_t nfds,
int timeout)
663 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.
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
This is the internal header file of the I/O handle declarations.
@ 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.
int io_close(io_handle_t handle)
Closes an I/O device.
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.
ssize_t io_write(io_handle_t handle, const void *buf, size_t nbytes)
Performs a write operation.
@ IO_FLAG_NONBLOCK
Perform I/O operations in non-blocking mode.
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 pipe declarations.
int io_open_pipe(io_handle_t handle_vector[2])
Opens a pipe.
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.
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 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.
@ IO_SOCK_STREAM
A stream-oriented connection-mode socket type.
int io_open_socketpair(int domain, int type, io_handle_t handle_vector[2])
Opens a pair of connected sockets.
@ IO_SOCK_IPV4
An IPv4 socket.
This is the internal header file of the I/O library.
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::@10 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.
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.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
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.