sd-future: add fiber-aware non-blocking I/O wrappers
Add a family of sd_fiber_*() I/O wrappers that, when called from a
fiber, behave like blocking I/O from the caller's perspective but
yield to the event loop instead of blocking the thread:
sd_fiber_read / sd_fiber_write
sd_fiber_readv / sd_fiber_writev
sd_fiber_recv / sd_fiber_send
sd_fiber_connect
sd_fiber_recvmsg / sd_fiber_sendmsg
sd_fiber_recvfrom / sd_fiber_sendto
sd_fiber_accept
sd_fiber_ppoll
Most of them share a single helper, fiber_io_operation(), which when
invoked outside a fiber falls through to the underlying syscall
directly, preserving the regular blocking behaviour. Inside a fiber
the helper flips the fd to non-blocking (restoring its original mode
on return), tries the syscall once on the fast path, and on EAGAIN/
EWOULDBLOCK creates an sd-event-backed IO future via future_new_io(),
suspends the fiber, and retries the syscall once the event source
fires.
future_new_io() itself is added to sd-event/event-future.{c,h} as a
new IoFuture kind. It wraps sd_event_add_io() into an sd_future:
oneshot enable, EPOLLERR translated via SO_ERROR (suppressed for
non-sockets), and the fd duplicated with F_DUPFD_CLOEXEC to avoid
EEXIST when multiple sources watch the same descriptor.
Together these let fiber-using code write straight-line socket and
pipe I/O without bundling state into callbacks.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h> /* IWYU pragma: keep */
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -10,6 +11,14 @@
|
||||
#include "io-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
/* EPOLL_POLL_COMMON_MASK in io-util.h treats POLL* and EPOLL* as interchangeable; verify it. */
|
||||
assert_cc((uint32_t) POLLIN == EPOLLIN);
|
||||
assert_cc((uint32_t) POLLOUT == EPOLLOUT);
|
||||
assert_cc((uint32_t) POLLERR == EPOLLERR);
|
||||
assert_cc((uint32_t) POLLHUP == EPOLLHUP);
|
||||
assert_cc((uint32_t) POLLPRI == EPOLLPRI);
|
||||
assert_cc((uint32_t) POLLRDHUP == EPOLLRDHUP);
|
||||
|
||||
int flush_fd(int fd) {
|
||||
int count = 0;
|
||||
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
#include "basic-forward.h"
|
||||
|
||||
/* The intersection of poll() and epoll_wait() event masks. Linux defines POLL* and EPOLL* with the
|
||||
* same numeric values for these — see the assert_cc()s in io-util.c — so this mask can be used
|
||||
* interchangeably as a `revents` (poll) or `events` (epoll) bitset. */
|
||||
#define EPOLL_POLL_COMMON_MASK \
|
||||
(EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLRDHUP)
|
||||
|
||||
int flush_fd(int fd);
|
||||
|
||||
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
|
||||
|
||||
Reference in New Issue
Block a user