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 144 goto error_open_pipe;
150 goto error_set_flags;
154 goto error_set_flags;
158 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 159 poll->
epfd = epoll_create1(EPOLL_CLOEXEC);
160 if (poll->
epfd == -1) {
162 goto error_epoll_create1;
166 struct epoll_event ev = { .events = EPOLLIN,
167 .data.ptr = poll->
pipe[0] };
168 if (epoll_ctl(poll->
epfd, EPOLL_CTL_ADD, poll->
pipe[0]->
fd, &ev)
171 goto error_epoll_ctl;
177 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 182 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L 200 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 204 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L 209 #ifndef LELY_NO_THREADS 222 goto error_alloc_poll;
225 if (!__io_poll_init(poll)) {
227 goto error_init_poll;
233 __io_poll_free(poll);
243 __io_poll_fini(poll);
244 __io_poll_free(poll);
259 assert(handle->
vtab);
261 #if defined(__linux__) && defined(HAVE_LINUX_CAN_H) 264 #if _POSIX_C_SOURCE >= 200112L 269 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L 281 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 292 watch = io_poll_insert(poll, handle);
303 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 306 int op = node ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
308 struct epoll_event ev = { 0, { NULL } };
310 ev.events |= EPOLLIN | EPOLLRDHUP | EPOLLPRI;
312 ev.events |= EPOLLOUT;
313 ev.data.ptr = watch->
handle;
315 if (epoll_ctl(poll->
epfd, op, watch->
handle->
fd, &ev) == -1) {
317 goto error_epoll_ctl;
326 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 328 epoll_ctl(poll->
epfd, EPOLL_CTL_DEL, watch->
handle->
fd, NULL);
330 io_poll_remove(poll, watch);
333 io_poll_unlock(poll);
337 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 339 epoll_ctl(poll->
epfd, EPOLL_CTL_DEL, watch->
handle->
fd, NULL);
341 io_poll_remove(poll, watch);
343 io_poll_unlock(poll);
359 if (!maxevents || !events)
363 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L 364 unsigned char sig = 0;
378 FD_SET((SOCKET)poll->
pipe[0]->
fd, &readfds);
387 io_poll_remove(poll, watch);
391 SOCKET fd = (SOCKET)watch->
handle->
fd;
393 FD_SET(fd, &readfds);
396 FD_SET(fd, &writefds);
398 FD_SET(fd, &errorfds);
400 io_poll_unlock(poll);
402 struct timeval tv = { .tv_sec = timeout / 1000,
403 .tv_usec = (timeout % 1000) * 1000 };
404 int result = select(0, &readfds, nwritefds ? &writefds : NULL,
405 &errorfds, timeout >= 0 ? &tv : NULL);
410 if (FD_ISSET((SOCKET)poll->
pipe[0]->
fd, &readfds))
415 while (node && nevents < maxevents) {
420 io_poll_remove(poll, watch);
424 events[nevents].
events = 0;
425 if (FD_ISSET((SOCKET)watch->
handle->
fd, &readfds)
428 if (FD_ISSET((SOCKET)watch->
handle->
fd, &writefds)
431 if (FD_ISSET((SOCKET)watch->
handle->
fd, &errorfds))
434 if (!events[nevents].events)
437 events[nevents].u = watch->
event.
u;
441 io_poll_remove(poll, watch);
443 io_poll_unlock(poll);
444 #elif _POSIX_C_SOURCE >= 200112L 445 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 446 struct epoll_event ev[maxevents];
451 nfds = epoll_wait(poll->
epfd, ev, maxevents,
452 timeout >= 0 ? timeout : -1);
453 }
while (nfds == -1 && errno == EINTR);
458 for (
int i = 0; i < nfds; i++) {
460 if (ev[i].data.ptr == poll->
pipe[0]) {
471 events[nevents].
events = 0;
475 if (ev[i].events & (EPOLLRDHUP | EPOLLPRI | EPOLLERR
479 if (ev[i].events & EPOLLIN)
481 if (ev[i].events & EPOLLOUT)
483 events[nevents].
u = watch->
event.
u;
490 io_poll_remove(poll, watch);
493 io_poll_unlock(poll);
496 struct pollfd fds[rbtree_size(&poll->
tree) + 1];
499 fds[nfds].fd = poll->
pipe[0]->
fd;
500 fds[nfds].events = POLLIN;
508 io_poll_remove(poll, watch);
513 fds[nfds].events = 0;
515 fds[nfds].events |= POLLIN | POLLPRI;
517 fds[nfds].events |= POLLOUT;
520 io_poll_unlock(poll);
526 n = _poll(fds, nfds, timeout >= 0 ? timeout : -1);
527 }
while (n == -1 && errno == EINTR);
530 maxevents =
MIN(n, maxevents);
533 for (nfds_t nfd = 0; nfd < nfds && nevents < maxevents; nfd++) {
535 if (fds[nfd].fd == poll->
pipe[0]->
fd) {
540 events[nevents].
events = 0;
542 if (fds[nfd].revents & (POLLPRI | POLLERR | POLLHUP | POLLNVAL))
545 if (fds[nfd].revents & POLLIN)
547 if (fds[nfd].revents & POLLOUT)
550 if (!events[nevents].events)
559 events[nevents].u = watch->
event.
u;
564 io_poll_remove(poll, watch);
566 io_poll_unlock(poll);
567 #endif // __linux__ && HAVE_SYS_EPOLL_H 572 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L 576 while (nevents < maxevents
579 events[nevents].
u.
sig = sig;
588 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L 598 #ifndef LELY_NO_THREADS 616 #endif // !LELY_NO_THREADS 624 struct io_watch *watch = malloc(
sizeof(*watch));
629 #if defined(__linux__) && defined(HAVE_SYS_EPOLL_H) 651 #if _POSIX_C_SOURCE >= 200112L \ 652 && !(defined(__linux__) && defined(HAVE_SYS_EPOLL_H)) 654 _poll(
struct pollfd *fds, nfds_t nfds,
int timeout)
656 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.
This header file is part of the I/O library; it contains I/O polling interface declarations.
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...
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.
A stream-oriented connection-mode socket type.
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.
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...
An event signaling that a file descriptor is ready for reading normal-priority (non-OOB) data...
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.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
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.
void io_poll_destroy(io_poll_t *poll)
Destroys an I/O polling interface.
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
Perform I/O operations in non-blocking mode.
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.
An event representing the occurrence of a signal.
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.
An event signaling that a file descriptor is ready for writing normal-priority (non-OOB) data...
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.
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 ...
union io_event::@13 u
Signal attributes depending on the value of events.
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...
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
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.
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...
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...
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.
An event signaling that an error has occurred for a file descriptor.
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: ...
int io_poll_signal(io_poll_t *poll, unsigned char sig)
Generates a signal event.