39 #if _POSIX_C_SOURCE >= 200112L 40 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 41 #include <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) 80 #ifdef LELY_NO_THREADS 81 #define io_poll_lock(poll) 82 #define io_poll_unlock(poll) 84 static void io_poll_lock(
io_poll_t *poll);
85 static void io_poll_unlock(
io_poll_t *poll);
88 static struct io_watch *io_poll_insert(
92 #if _POSIX_C_SOURCE >= 200112L \ 93 && !(defined(__linux__) && defined(HAVE_SYS_EPOLL_H)) 94 static 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);
574 #endif // __linux__ && HAVE_SYS_EPOLL_H 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 623 #endif // !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);
unsigned char sig
The signal number (if events == IO_EVENT_SIGNAL).
const void * key
A pointer to the key for this node.
This header file is part of the I/O library; it contains the pipe declarations.
An event representing the occurrence of a signal.
An I/O polling interface.
mtx_t mtx
The mutex protecting tree.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
int io_open_socketpair(int domain, int type, io_handle_t handle_vector[2])
Opens a pair of connected sockets.
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
This header file is part of the utilities library; it contains the comparison function definitions...
io_poll_t * io_poll_create(void)
Creates a new I/O polling interface.
size_t rbtree_size(const struct rbtree *tree)
Returns the size (in number of nodes) of a red-black tree.
The attributes of an I/O device handle being watched.
int keep
A flag indicating whether to keep watching the file descriptor after an event occurs.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
struct rbnode node
The node in the tree of file descriptors.
An event signaling that a file descriptor is ready for reading normal-priority (non-OOB) data...
This header file is part of the utilities library; it contains the red-black tree declarations...
struct rbtree tree
The tree containing the I/O device handles being watched.
ssize_t io_write(io_handle_t handle, const void *buf, size_t nbytes)
Performs a write operation.
#define MIN(a, b)
Returns the minimum of a and b.
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...
void io_poll_destroy(io_poll_t *poll)
Destroys an I/O polling interface.
A mutex type that supports neither timeout nor test and return.
int io_open_pipe(io_handle_t handle_vector[2])
Opens a pipe.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
union io_event::@10 u
Signal attributes depending on the value of events.
An event signaling that an error has occurred for a file descriptor.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
This header file is part of the I/O library; it contains I/O polling interface declarations.
This is the internal header file of the I/O handle declarations.
io_handle_t io_handle_acquire(io_handle_t handle)
Increments the reference count of an I/O device handle.
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...
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
This header file is part of the utilities library; it contains the native and platform-independent er...
io_handle_t pipe[2]
A self-pipe used to generate signal events.
#define rbtree_foreach(tree, node)
Iterates over each node in a red-black tree in ascending order.
int io_poll_signal(io_poll_t *poll, unsigned char sig)
Generates a signal event.
const struct io_handle_vtab * vtab
A pointer to the virtual table.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
int io_set_flags(io_handle_t handle, int flags)
Sets the flags of an I/O device.
struct rbnode * rbtree_find(const struct rbtree *tree, const void *key)
Finds a node in a red-black tree.
This header file is part of the I/O library; it contains the network socket declarations.
void io_handle_release(io_handle_t handle)
Decrements the reference count of an I/O device handle.
int epfd
The epoll file descriptor.
void rbtree_remove(struct rbtree *tree, struct rbnode *node)
Removes a node from a red-black tree.
struct io_handle * handle
A pointer to the I/O device handle.
ssize_t io_read(io_handle_t handle, void *buf, size_t nbytes)
Performs a read operation.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
This is the internal header file of the I/O library.
int io_close(io_handle_t handle)
Closes an I/O device.
int events
The events that should be watched or have been triggered (either IO_EVENT_SIGNAL, or any combination ...
An event signaling that a file descriptor is ready for writing normal-priority (non-OOB) data...
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...
Perform I/O operations in non-blocking mode.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
void rbtree_init(struct rbtree *tree, rbtree_cmp_t *cmp)
Initializes 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...
A stream-oriented connection-mode socket type.
void rbtree_insert(struct rbtree *tree, struct rbnode *node)
Inserts a node into a red-black tree.
int fd
The native file descriptor.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
struct io_event event
The events being watched.
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...
struct rbnode * rbtree_first(const struct rbtree *tree)
Returns a pointer to the first (leftmost) node in a red-black tree.
A node in a red-black tree.
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: ...