[core] merge fdevent impls into fdevent_impl.c

master
Glenn Strauss 1 year ago
parent ec52917755
commit 7113dcb49b

@ -801,10 +801,6 @@ add_executable(lighttpd
ls-hpack/lshpack.c
algo_xxhash.c
fdevent_impl.c
fdevent_select.c fdevent_libev.c
fdevent_poll.c fdevent_linux_sysepoll.c
fdevent_solaris_devpoll.c fdevent_solaris_port.c
fdevent_freebsd_kqueue.c
http_range.c
network.c
network_write.c

@ -98,10 +98,6 @@ src = server.c response.c connections.c h2.c reqpool.c \
ls-hpack/lshpack.c \
algo_xxhash.c \
fdevent_impl.c \
fdevent_select.c fdevent_libev.c \
fdevent_poll.c fdevent_linux_sysepoll.c \
fdevent_solaris_devpoll.c fdevent_solaris_port.c \
fdevent_freebsd_kqueue.c \
http_range.c \
data_config.c \
vector.c \

@ -77,10 +77,6 @@ src = Split("server.c response.c connections.c h2.c reqpool.c \
ls-hpack/lshpack.c \
algo_xxhash.c \
fdevent_impl.c \
fdevent_select.c fdevent_libev.c \
fdevent_poll.c fdevent_linux_sysepoll.c \
fdevent_solaris_devpoll.c fdevent_solaris_port.c \
fdevent_freebsd_kqueue.c \
http_range.c \
network.c \
network_write.c \

@ -1,124 +0,0 @@
#include "first.h"
#include "fdevent_impl.h"
#include "fdevent.h"
#include "buffer.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#ifdef FDEVENT_USE_FREEBSD_KQUEUE
# include <sys/event.h>
# include <sys/time.h>
__attribute_cold__
static void fdevent_freebsd_kqueue_free(fdevents *ev) {
close(ev->kq_fd);
free(ev->kq_results);
}
static int fdevent_freebsd_kqueue_event_del(fdevents *ev, fdnode *fdn) {
struct kevent kev[2];
struct timespec ts = {0, 0};
int fd = fdn->fd;
int n = 0;
int oevents = fdn->events;
if (oevents & FDEVENT_IN) {
EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
n++;
}
if (oevents & FDEVENT_OUT) {
EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
n++;
}
return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
/*(kevent() changelist still processed on EINTR,
* but EINTR should not be received since 0 == nevents)*/
}
static int fdevent_freebsd_kqueue_event_set(fdevents *ev, fdnode *fdn, int events) {
struct kevent kev[2];
struct timespec ts = {0, 0};
int fd = fdn->fde_ndx = fdn->fd;
int n = 0;
int oevents = fdn->events;
int addevents = events & ~oevents;
int delevents = ~events & oevents;
if (addevents & FDEVENT_IN) {
EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD, 0, 0, fdn);
n++;
} else if (delevents & FDEVENT_IN) {
EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
n++;
}
if (addevents & FDEVENT_OUT) {
EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD, 0, 0, fdn);
n++;
} else if (delevents & FDEVENT_OUT) {
EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
n++;
}
return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
/*(kevent() changelist still processed on EINTR,
* but EINTR should not be received since 0 == nevents)*/
}
static int fdevent_freebsd_kqueue_poll(fdevents * const ev, int timeout_ms) {
struct timespec ts;
ts.tv_sec = timeout_ms / 1000;
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
struct kevent * const restrict kq_results = ev->kq_results;
const int n = kevent(ev->kq_fd, NULL, 0, kq_results, ev->maxfds, &ts);
for (int i = 0; i < n; ++i) {
fdnode * const fdn = (fdnode *)kq_results[i].udata;
int filt = kq_results[i].filter;
int e = kq_results[i].flags;
if ((fdevent_handler)NULL != fdn->handler) {
int revents = (filt == EVFILT_READ) ? FDEVENT_IN : FDEVENT_OUT;
if (e & EV_EOF)
revents |= (filt == EVFILT_READ ? FDEVENT_RDHUP : FDEVENT_HUP);
if (e & EV_ERROR)
revents |= FDEVENT_ERR;
(*fdn->handler)(fdn->ctx, revents);
}
}
return n;
}
__attribute_cold__
static int fdevent_freebsd_kqueue_reset(fdevents *ev) {
#ifdef __NetBSD__
ev->kq_fd = kqueue1(O_NONBLOCK|O_CLOEXEC|O_NOSIGPIPE);
return (-1 != ev->kq_fd) ? 0 : -1;
#else
ev->kq_fd = kqueue();
if (-1 == ev->kq_fd) return -1;
fdevent_setfd_cloexec(ev->kq_fd);
return 0;
#endif
}
__attribute_cold__
int fdevent_freebsd_kqueue_init(fdevents *ev) {
ev->type = FDEVENT_HANDLER_FREEBSD_KQUEUE;
ev->event_set = fdevent_freebsd_kqueue_event_set;
ev->event_del = fdevent_freebsd_kqueue_event_del;
ev->poll = fdevent_freebsd_kqueue_poll;
ev->reset = fdevent_freebsd_kqueue_reset;
ev->free = fdevent_freebsd_kqueue_free;
ev->kq_fd = -1;
ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results));
force_assert(NULL != ev->kq_results);
return 0;
}
#endif

@ -15,6 +15,36 @@
#include <winsock2.h> /* closesocket */
#endif
#ifdef FDEVENT_USE_LINUX_EPOLL
__attribute_cold__
static int fdevent_linux_sysepoll_init(struct fdevents *ev);
#endif
#ifdef FDEVENT_USE_FREEBSD_KQUEUE
__attribute_cold__
static int fdevent_freebsd_kqueue_init(struct fdevents *ev);
#endif
#ifdef FDEVENT_USE_SOLARIS_PORT
__attribute_cold__
static int fdevent_solaris_port_init(struct fdevents *ev);
#endif
#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
__attribute_cold__
static int fdevent_solaris_devpoll_init(struct fdevents *ev);
#endif
#ifdef FDEVENT_USE_LIBEV
__attribute_cold__
static int fdevent_libev_init(struct fdevents *ev);
#endif
#ifdef FDEVENT_USE_POLL
__attribute_cold__
static int fdevent_poll_init(struct fdevents *ev);
#endif
#ifdef FDEVENT_USE_SELECT
__attribute_cold__
static int fdevent_select_init(struct fdevents *ev);
#endif
int
fdevent_config (const char **event_handler_name, log_error_st *errh)
{
@ -316,3 +346,772 @@ fdevent_poll (fdevents * const ev, const int timeout_ms)
log_perror(ev->errh, __FILE__, __LINE__, "fdevent_poll failed");
return n;
}
#ifdef FDEVENT_USE_LINUX_EPOLL
#include <sys/epoll.h>
static int
fdevent_linux_sysepoll_event_del (fdevents *ev, fdnode *fdn)
{
return epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fdn->fd, NULL);
}
static int
fdevent_linux_sysepoll_event_set (fdevents *ev, fdnode *fdn, int events)
{
int op = (-1 == fdn->fde_ndx) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
int fd = fdn->fde_ndx = fdn->fd;
struct epoll_event ep;
#ifndef EPOLLRDHUP
events &= ~FDEVENT_RDHUP;
#endif
ep.events = events | EPOLLERR | EPOLLHUP;
ep.data.ptr = fdn;
return epoll_ctl(ev->epoll_fd, op, fd, &ep);
}
static int
fdevent_linux_sysepoll_poll (fdevents * const ev, int timeout_ms)
{
struct epoll_event * const restrict epoll_events = ev->epoll_events;
int n = epoll_wait(ev->epoll_fd, epoll_events, ev->maxfds, timeout_ms);
for (int i = 0; i < n; ++i) {
fdnode * const fdn = (fdnode *)epoll_events[i].data.ptr;
int revents = epoll_events[i].events;
if ((fdevent_handler)NULL != fdn->handler)
(*fdn->handler)(fdn->ctx, revents);
}
return n;
}
__attribute_cold__
static void
fdevent_linux_sysepoll_free (fdevents *ev)
{
close(ev->epoll_fd);
free(ev->epoll_events);
}
__attribute_cold__
static int
fdevent_linux_sysepoll_init (fdevents *ev)
{
force_assert(EPOLLIN == FDEVENT_IN);
force_assert(EPOLLPRI == FDEVENT_PRI);
force_assert(EPOLLOUT == FDEVENT_OUT);
force_assert(EPOLLERR == FDEVENT_ERR);
force_assert(EPOLLHUP == FDEVENT_HUP);
#ifdef EPOLLRDHUP
force_assert(EPOLLRDHUP == FDEVENT_RDHUP);
#endif
ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
ev->event_set = fdevent_linux_sysepoll_event_set;
ev->event_del = fdevent_linux_sysepoll_event_del;
ev->poll = fdevent_linux_sysepoll_poll;
ev->free = fdevent_linux_sysepoll_free;
#ifdef EPOLL_CLOEXEC
if (-1 == (ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC))) return -1;
#else
if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) return -1;
fdevent_setfd_cloexec(ev->epoll_fd);
#endif
ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));
force_assert(NULL != ev->epoll_events);
return 0;
}
#endif /* FDEVENT_USE_LINUX_EPOLL */
#ifdef FDEVENT_USE_FREEBSD_KQUEUE
#include <sys/event.h>
#include <sys/time.h>
#include <fcntl.h>
static int
fdevent_freebsd_kqueue_event_del (fdevents *ev, fdnode *fdn)
{
struct kevent kev[2];
struct timespec ts = {0, 0};
int fd = fdn->fd;
int n = 0;
int oevents = fdn->events;
if (oevents & FDEVENT_IN) {
EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
n++;
}
if (oevents & FDEVENT_OUT) {
EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
n++;
}
return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
/*(kevent() changelist still processed on EINTR,
* but EINTR should not be received since 0 == nevents)*/
}
static int
fdevent_freebsd_kqueue_event_set (fdevents *ev, fdnode *fdn, int events)
{
struct kevent kev[2];
struct timespec ts = {0, 0};
int fd = fdn->fde_ndx = fdn->fd;
int n = 0;
int oevents = fdn->events;
int addevents = events & ~oevents;
int delevents = ~events & oevents;
if (addevents & FDEVENT_IN) {
EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD, 0, 0, fdn);
n++;
}
else if (delevents & FDEVENT_IN) {
EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn);
n++;
}
if (addevents & FDEVENT_OUT) {
EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD, 0, 0, fdn);
n++;
}
else if (delevents & FDEVENT_OUT) {
EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn);
n++;
}
return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0;
/*(kevent() changelist still processed on EINTR,
* but EINTR should not be received since 0 == nevents)*/
}
static int
fdevent_freebsd_kqueue_poll (fdevents * const ev, int timeout_ms)
{
struct timespec ts;
ts.tv_sec = timeout_ms / 1000;
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
struct kevent * const restrict kq_results = ev->kq_results;
const int n = kevent(ev->kq_fd, NULL, 0, kq_results, ev->maxfds, &ts);
for (int i = 0; i < n; ++i) {
fdnode * const fdn = (fdnode *)kq_results[i].udata;
int filt = kq_results[i].filter;
int e = kq_results[i].flags;
if ((fdevent_handler)NULL != fdn->handler) {
int revents = (filt == EVFILT_READ) ? FDEVENT_IN : FDEVENT_OUT;
if (e & EV_EOF)
revents |= (filt == EVFILT_READ ? FDEVENT_RDHUP : FDEVENT_HUP);
if (e & EV_ERROR)
revents |= FDEVENT_ERR;
(*fdn->handler)(fdn->ctx, revents);
}
}
return n;
}
__attribute_cold__
static int
fdevent_freebsd_kqueue_reset (fdevents *ev)
{
#ifdef __NetBSD__
ev->kq_fd = kqueue1(O_NONBLOCK|O_CLOEXEC|O_NOSIGPIPE);
return (-1 != ev->kq_fd) ? 0 : -1;
#else
ev->kq_fd = kqueue();
if (-1 == ev->kq_fd) return -1;
fdevent_setfd_cloexec(ev->kq_fd);
return 0;
#endif
}
__attribute_cold__
static void
fdevent_freebsd_kqueue_free (fdevents *ev)
{
close(ev->kq_fd);
free(ev->kq_results);
}
__attribute_cold__
static int
fdevent_freebsd_kqueue_init (fdevents *ev)
{
ev->type = FDEVENT_HANDLER_FREEBSD_KQUEUE;
ev->event_set = fdevent_freebsd_kqueue_event_set;
ev->event_del = fdevent_freebsd_kqueue_event_del;
ev->poll = fdevent_freebsd_kqueue_poll;
ev->reset = fdevent_freebsd_kqueue_reset;
ev->free = fdevent_freebsd_kqueue_free;
ev->kq_fd = -1;
ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results));
force_assert(NULL != ev->kq_results);
return 0;
}
#endif /* FDEVENT_USE_FREEBSD_KQUEUE */
#ifdef FDEVENT_USE_SOLARIS_PORT
#include <sys/poll.h>
#include <fcntl.h>
static int
fdevent_solaris_port_event_del (fdevents *ev, fdnode *fdn)
{
return port_dissociate(ev->port_fd, PORT_SOURCE_FD, fdn->fd);
}
static int
fdevent_solaris_port_event_set (fdevents *ev, fdnode *fdn, int events)
{
int fd = fdn->fde_ndx = fdn->fd;
intptr_t ud = events & (POLLIN|POLLOUT);
return port_associate(ev->port_fd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud);
}
/* if there is any error it will return the return values of port_getn,
* otherwise it will return number of events */
static int
fdevent_solaris_port_poll (fdevents *ev, int timeout_ms)
{
const int pfd = ev->port_fd;
int ret;
unsigned int available_events, wait_for_events = 0;
struct timespec timeout;
timeout.tv_sec = timeout_ms/1000L;
timeout.tv_nsec = (timeout_ms % 1000L) * 1000000L;
/* get the number of file descriptors with events */
if ((ret = port_getn(pfd, ev->port_events, 0, &wait_for_events, &timeout)) < 0) return ret;
/* wait for at least one event */
if (0 == wait_for_events) wait_for_events = 1;
available_events = wait_for_events;
/* get the events of the file descriptors */
if ((ret = port_getn(pfd, ev->port_events, ev->maxfds, &available_events, &timeout)) < 0) {
/* if errno == ETIME and available_event == wait_for_events we didn't get any events */
/* for other errors we didn't get any events either */
if (!(errno == ETIME && wait_for_events != available_events)) return ret;
}
for (int i = 0; i < (int)available_events; ++i) {
int fd = (int)ev->port_events[i].portev_object;
fdnode * const fdn = ev->fdarray[fd];
const intptr_t ud = (intptr_t)ev->port_events[i].portev_user;
int revents = ev->port_events[i].portev_events;
if (0 == ((uintptr_t)fdn & 0x3)) {
if (port_associate(pfd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud) < 0)
log_error(ev->errh,__FILE__,__LINE__,"port_associate failed");
(*fdn->handler)(fdn->ctx, revents);
}
else {
fdn->fde_ndx = -1;
}
}
return available_events;
}
__attribute_cold__
static void
fdevent_solaris_port_free (fdevents *ev)
{
close(ev->port_fd);
free(ev->port_events);
}
__attribute_cold__
static int
fdevent_solaris_port_init (fdevents *ev)
{
force_assert(POLLIN == FDEVENT_IN);
force_assert(POLLPRI == FDEVENT_PRI);
force_assert(POLLOUT == FDEVENT_OUT);
force_assert(POLLERR == FDEVENT_ERR);
force_assert(POLLHUP == FDEVENT_HUP);
force_assert(POLLNVAL == FDEVENT_NVAL);
#ifdef POLLRDHUP
force_assert(POLLRDHUP == FDEVENT_RDHUP);
#endif
ev->type = FDEVENT_HANDLER_SOLARIS_PORT;
ev->event_set = fdevent_solaris_port_event_set;
ev->event_del = fdevent_solaris_port_event_del;
ev->poll = fdevent_solaris_port_poll;
ev->free = fdevent_solaris_port_free;
ev->port_events = malloc(ev->maxfds * sizeof(*ev->port_events));
force_assert(NULL != ev->port_events);
if ((ev->port_fd = port_create()) < 0) return -1;
return 0;
}
#endif /* FDEVENT_USE_SOLARIS_PORT */
#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
#include <sys/devpoll.h>
#include <sys/ioctl.h>
#include <fcntl.h>
static int
fdevent_solaris_devpoll_event_del (fdevents *ev, fdnode *fdn)
{
struct pollfd pfd;
pfd.fd = fdn->fd;
pfd.events = POLLREMOVE;
pfd.revents = 0;
return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
}
static int
fdevent_solaris_devpoll_event_set (fdevents *ev, fdnode *fdn, int events)
{
struct pollfd pfd;
pfd.fd = fdn->fde_ndx = fdn->fd;
#ifndef POLLRDHUP
events &= ~FDEVENT_RDHUP;
#endif
pfd.events = events;
pfd.revents = 0;
return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
}
static int
fdevent_solaris_devpoll_poll (fdevents *ev, int timeout_ms)
{
fdnode ** const fdarray = ev->fdarray;
struct pollfd * const devpollfds = ev->devpollfds;
struct dvpoll dopoll;
dopoll.dp_timeout = timeout_ms;
dopoll.dp_nfds = ev->maxfds - 1;
dopoll.dp_fds = devpollfds;
const int n = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
for (int i = 0; i < n; ++i) {
fdnode * const fdn = fdarray[devpollfds[i].fd];
int revents = devpollfds[i].revents;
if (0 == ((uintptr_t)fdn & 0x3))
(*fdn->handler)(fdn->ctx, revents);
}
return n;
}
__attribute_cold__
static int
fdevent_solaris_devpoll_reset (fdevents *ev)
{
/* a forked process does only inherit the filedescriptor,
* but every operation on the device will lead to a EACCES */
ev->devpoll_fd = fdevent_open_cloexec("/dev/poll", 1, O_RDWR, 0);
return (ev->devpoll_fd >= 0) ? 0 : -1;
}
__attribute_cold__
static void
fdevent_solaris_devpoll_free (fdevents *ev)
{
free(ev->devpollfds);
close(ev->devpoll_fd);
}
__attribute_cold__
static int
fdevent_solaris_devpoll_init (fdevents *ev)
{
force_assert(POLLIN == FDEVENT_IN);
force_assert(POLLPRI == FDEVENT_PRI);
force_assert(POLLOUT == FDEVENT_OUT);
force_assert(POLLERR == FDEVENT_ERR);
force_assert(POLLHUP == FDEVENT_HUP);
force_assert(POLLNVAL == FDEVENT_NVAL);
#ifdef POLLRDHUP
force_assert(POLLRDHUP == FDEVENT_RDHUP);
#endif
ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
ev->event_set = fdevent_solaris_devpoll_event_set;
ev->event_del = fdevent_solaris_devpoll_event_del;
ev->poll = fdevent_solaris_devpoll_poll;
ev->reset = fdevent_solaris_devpoll_reset;
ev->free = fdevent_solaris_devpoll_free;
ev->devpoll_fd = -1;
ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
force_assert(NULL != ev->devpollfds);
return 0;
}
#endif /* FDEVENT_USE_SOLARIS_DEVPOLL */
#ifdef FDEVENT_USE_LIBEV
#include <ev.h>
static void
fdevent_libev_io_watcher_cb (struct ev_loop *loop, ev_io *w, int revents)
{
fdevents *ev = w->data;
fdnode *fdn = ev->fdarray[w->fd];
int rv = 0;
UNUSED(loop);
if (revents & EV_READ) rv |= FDEVENT_IN;
if (revents & EV_WRITE) rv |= FDEVENT_OUT;
if (revents & EV_ERROR) rv |= FDEVENT_ERR;
if (0 == ((uintptr_t)fdn & 0x3))
(*fdn->handler)(fdn->ctx, rv);
}
static int
fdevent_libev_event_del (fdevents *ev, fdnode *fdn)
{
ev_io *watcher = fdn->handler_ctx;
if (!watcher) return 0;
fdn->handler_ctx = NULL;
ev_io_stop(ev->libev_loop, watcher);
free(watcher);
return 0;
}
static int
fdevent_libev_event_set (fdevents *ev, fdnode *fdn, int events)
{
ev_io *watcher = fdn->handler_ctx;
int ev_events = 0;
if (events & FDEVENT_IN) ev_events |= EV_READ;
if (events & FDEVENT_OUT) ev_events |= EV_WRITE;
if (!watcher) {
fdn->handler_ctx = watcher = calloc(1, sizeof(ev_io));
force_assert(watcher);
fdn->fde_ndx = fdn->fd;
ev_io_init(watcher, fdevent_libev_io_watcher_cb, fdn->fd, ev_events);
watcher->data = ev;
ev_io_start(ev->libev_loop, watcher);
}
else {
if ((watcher->events & (EV_READ | EV_WRITE)) != ev_events) {
ev_io_stop(ev->libev_loop, watcher);
ev_io_set(watcher, watcher->fd, ev_events);
ev_io_start(ev->libev_loop, watcher);
}
}
return 0;
}
static void
fdevent_libev_timeout_watcher_cb (struct ev_loop *loop, ev_timer *w, int revents)
{
UNUSED(loop);
UNUSED(w);
UNUSED(revents);
}
static ev_timer timeout_watcher;
static int
fdevent_libev_poll (fdevents *ev, int timeout_ms)
{
timeout_watcher.repeat = (timeout_ms > 0) ? timeout_ms/1000.0 : 0.001;
ev_timer_again(ev->libev_loop, &timeout_watcher);
ev_run(ev->libev_loop, EVRUN_ONCE);
return 0;
}
__attribute_cold__
static int
fdevent_libev_reset (fdevents *ev)
{
UNUSED(ev);
ev_default_fork();
return 0;
}
__attribute_cold__
static void
fdevent_libev_free (fdevents *ev)
{
UNUSED(ev);
}
__attribute_cold__
static int
fdevent_libev_init (fdevents *ev)
{
struct ev_timer * const timer = &timeout_watcher;
memset(timer, 0, sizeof(*timer));
ev->type = FDEVENT_HANDLER_LIBEV;
ev->event_set = fdevent_libev_event_set;
ev->event_del = fdevent_libev_event_del;
ev->poll = fdevent_libev_poll;
ev->reset = fdevent_libev_reset;
ev->free = fdevent_libev_free;
if (NULL == (ev->libev_loop = ev_default_loop(0))) return -1;
ev_timer_init(timer, fdevent_libev_timeout_watcher_cb, 0.0, 1.0);
return 0;
}
#endif /* FDEVENT_USE_LIBEV */
#ifdef FDEVENT_USE_POLL
#ifdef HAVE_POLL_H
#include <poll.h>
#else
#include <sys/poll.h>
#endif
static int
fdevent_poll_event_del (fdevents *ev, fdnode *fdn)
{
int fd = fdn->fd;
int k = fdn->fde_ndx;
if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd)
return (errno = EINVAL, -1);
ev->pollfds[k].fd = -1;
/* ev->pollfds[k].events = 0; */
/* ev->pollfds[k].revents = 0; */
if (ev->unused.size == ev->unused.used) {
ev->unused.size += 16;
ev->unused.ptr = realloc(ev->unused.ptr,
sizeof(*(ev->unused.ptr)) * ev->unused.size);
force_assert(NULL != ev->unused.ptr);
}
ev->unused.ptr[ev->unused.used++] = k;
return 0;
}
static int
fdevent_poll_event_set (fdevents *ev, fdnode *fdn, int events)
{
int fd = fdn->fd;
int k = fdn->fde_ndx;
#ifndef POLLRDHUP
events &= ~FDEVENT_RDHUP;
#endif
if (k >= 0) {
if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd)
return (errno = EINVAL, -1);
ev->pollfds[k].events = events;
return 0;
}
if (ev->unused.used > 0) {
k = ev->unused.ptr[--ev->unused.used];
}
else {
if (ev->size == ev->used) {
ev->size += 16;
ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
force_assert(NULL != ev->pollfds);
}
k = ev->used++;
}
fdn->fde_ndx = k;
ev->pollfds[k].fd = fd;
ev->pollfds[k].events = events;
return 0;
}
static int
fdevent_poll_poll (fdevents *ev, int timeout_ms)
{
struct pollfd * const restrict pfds = ev->pollfds;
fdnode ** const fdarray = ev->fdarray;
const int n = poll(pfds, ev->used, timeout_ms);
for (int i = 0, m = 0; m < n; ++i) {
if (0 == pfds[i].revents) continue;
fdnode *fdn = fdarray[pfds[i].fd];
if (0 == ((uintptr_t)fdn & 0x3))
(*fdn->handler)(fdn->ctx, pfds[i].revents);
++m;
}
return n;
}
__attribute_cold__
static void
fdevent_poll_free (fdevents *ev)
{
free(ev->pollfds);
if (ev->unused.ptr) free(ev->unused.ptr);
}
__attribute_cold__
static int
fdevent_poll_init (fdevents *ev)
{
force_assert(POLLIN == FDEVENT_IN);
force_assert(POLLPRI == FDEVENT_PRI);
force_assert(POLLOUT == FDEVENT_OUT);
force_assert(POLLERR == FDEVENT_ERR);
force_assert(POLLHUP == FDEVENT_HUP);
force_assert(POLLNVAL == FDEVENT_NVAL);
#ifdef POLLRDHUP
force_assert(POLLRDHUP == FDEVENT_RDHUP);
#endif
ev->type = FDEVENT_HANDLER_POLL;
ev->event_set = fdevent_poll_event_set;
ev->event_del = fdevent_poll_event_del;
ev->poll = fdevent_poll_poll;
ev->free = fdevent_poll_free;
return 0;
}
#endif /* FDEVENT_USE_POLL */
#ifdef FDEVENT_USE_SELECT
#include "sys-time.h"
__attribute_cold__
static int
fdevent_select_reset (fdevents *ev)
{
FD_ZERO(&(ev->select_set_read));
FD_ZERO(&(ev->select_set_write));
FD_ZERO(&(ev->select_set_error));
ev->select_max_fd = -1;
return 0;
}
static int
fdevent_select_event_del (fdevents *ev, fdnode *fdn)
{
int fd = fdn->fd;
FD_CLR(fd, &(ev->select_set_read));
FD_CLR(fd, &(ev->select_set_write));
FD_CLR(fd, &(ev->select_set_error));
return 0;
}
static int
fdevent_select_event_set (fdevents *ev, fdnode *fdn, int events)
{
int fd = fdn->fde_ndx = fdn->fd;
/* we should be protected by max-fds, but you never know */
force_assert(fd < ((int)FD_SETSIZE));
if (events & FDEVENT_IN)
FD_SET(fd, &(ev->select_set_read));
else
FD_CLR(fd, &(ev->select_set_read));
if (events & FDEVENT_OUT)
FD_SET(fd, &(ev->select_set_write));
else
FD_CLR(fd, &(ev->select_set_write));
FD_SET(fd, &(ev->select_set_error));
if (fd > ev->select_max_fd) ev->select_max_fd = fd;
return 0;
}
static int
fdevent_select_event_get_revent (const fdevents *ev, int ndx)
{
int revents = 0;
if (FD_ISSET(ndx, &ev->select_read)) revents |= FDEVENT_IN;
if (FD_ISSET(ndx, &ev->select_write)) revents |= FDEVENT_OUT;
if (FD_ISSET(ndx, &ev->select_error)) revents |= FDEVENT_ERR;
return revents;
}
static int
fdevent_select_event_next_fdndx (const fdevents *ev, int ndx)
{
const int max_fd = ev->select_max_fd + 1;
for (int i = (ndx < 0) ? 0 : ndx + 1; i < max_fd; ++i) {
if (FD_ISSET(i, &(ev->select_read))) return i;
if (FD_ISSET(i, &(ev->select_write))) return i;
if (FD_ISSET(i, &(ev->select_error))) return i;
}
return -1;
}
static int
fdevent_select_poll (fdevents *ev, int timeout_ms)
{
int n;
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
ev->select_read = ev->select_set_read;
ev->select_write = ev->select_set_write;
ev->select_error = ev->select_set_error;
n = select(ev->select_max_fd + 1,
&ev->select_read, &ev->select_write, &ev->select_error, &tv);
for (int ndx = -1, i = 0; i < n; ++i) {
fdnode *fdn;
ndx = fdevent_select_event_next_fdndx(ev, ndx);
if (-1 == ndx) break;
fdn = ev->fdarray[ndx];
if (0 == ((uintptr_t)fdn & 0x3)) {
int revents = fdevent_select_event_get_revent(ev, ndx);
(*fdn->handler)(fdn->ctx, revents);
}
}
return n;
}
__attribute_cold__
static int fdevent_select_init (fdevents *ev)
{
ev->type = FDEVENT_HANDLER_SELECT;
ev->event_set = fdevent_select_event_set;
ev->event_del = fdevent_select_event_del;
ev->poll = fdevent_select_poll;
ev->reset = fdevent_select_reset;
return 0;
}
#endif /* FDEVENT_USE_SELECT */

@ -132,19 +132,4 @@ struct fdevents {
fdevent_handler_t type;
};
__attribute_cold__
int fdevent_select_init(struct fdevents *ev);
__attribute_cold__
int fdevent_poll_init(struct fdevents *ev);
__attribute_cold__
int fdevent_linux_sysepoll_init(struct fdevents *ev);
__attribute_cold__
int fdevent_solaris_devpoll_init(struct fdevents *ev);
__attribute_cold__
int fdevent_solaris_port_init(struct fdevents *ev);
__attribute_cold__
int fdevent_freebsd_kqueue_init(struct fdevents *ev);
__attribute_cold__
int fdevent_libev_init(struct fdevents *ev);
#endif

@ -1,114 +0,0 @@
#include "first.h"
#include <string.h>
#include <stdlib.h>
#include "fdevent_impl.h"
#include "fdevent.h"
#include "buffer.h"
#ifdef FDEVENT_USE_LIBEV
# include <ev.h>
static void io_watcher_cb(struct ev_loop *loop, ev_io *w, int revents) {
fdevents *ev = w->data;
fdnode *fdn = ev->fdarray[w->fd];
int rv = 0;
UNUSED(loop);
if (revents & EV_READ) rv |= FDEVENT_IN;
if (revents & EV_WRITE) rv |= FDEVENT_OUT;
if (revents & EV_ERROR) rv |= FDEVENT_ERR;
if (0 == ((uintptr_t)fdn & 0x3)) {
(*fdn->handler)(fdn->ctx, rv);
}
}
__attribute_cold__
static void fdevent_libev_free(fdevents *ev) {
UNUSED(ev);
}
static int fdevent_libev_event_del(fdevents *ev, fdnode *fdn) {
ev_io *watcher = fdn->handler_ctx;
if (!watcher) return 0;
fdn->handler_ctx = NULL;
ev_io_stop(ev->libev_loop, watcher);
free(watcher);
return 0;
}
static int fdevent_libev_event_set(fdevents *ev, fdnode *fdn, int events) {
ev_io *watcher = fdn->handler_ctx;
int ev_events = 0;
if (events & FDEVENT_IN) ev_events |= EV_READ;
if (events & FDEVENT_OUT) ev_events |= EV_WRITE;
if (!watcher) {
fdn->handler_ctx = watcher = calloc(1, sizeof(ev_io));
force_assert(watcher);
fdn->fde_ndx = fdn->fd;
ev_io_init(watcher, io_watcher_cb, fdn->fd, ev_events);
watcher->data = ev;
ev_io_start(ev->libev_loop, watcher);
} else {
if ((watcher->events & (EV_READ | EV_WRITE)) != ev_events) {
ev_io_stop(ev->libev_loop, watcher);
ev_io_set(watcher, watcher->fd, ev_events);
ev_io_start(ev->libev_loop, watcher);
}
}
return 0;
}
static void timeout_watcher_cb(struct ev_loop *loop, ev_timer *w, int revents) {
UNUSED(loop);
UNUSED(w);
UNUSED(revents);
}
static ev_timer timeout_watcher;
static int fdevent_libev_poll(fdevents *ev, int timeout_ms) {
timeout_watcher.repeat = (timeout_ms > 0) ? timeout_ms/1000.0 : 0.001;
ev_timer_again(ev->libev_loop, &timeout_watcher);
ev_run(ev->libev_loop, EVRUN_ONCE);
return 0;
}
__attribute_cold__
static int fdevent_libev_reset(fdevents *ev) {
UNUSED(ev);
ev_default_fork();
return 0;
}
__attribute_cold__
int fdevent_libev_init(fdevents *ev) {
struct ev_timer * const timer = &timeout_watcher;
memset(timer, 0, sizeof(*timer));
ev->type = FDEVENT_HANDLER_LIBEV;
ev->event_set = fdevent_libev_event_set;
ev->event_del = fdevent_libev_event_del;
ev->poll = fdevent_libev_poll;
ev->reset = fdevent_libev_reset;
ev->free = fdevent_libev_free;
if (NULL == (ev->libev_loop = ev_default_loop(0))) return -1;
ev_timer_init(timer, timeout_watcher_cb, 0.0, 1.0);
return 0;
}
#endif

@ -1,80 +0,0 @@
#include "first.h"
#include "fdevent_impl.h"
#include "fdevent.h"
#include "buffer.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#ifdef FDEVENT_USE_LINUX_EPOLL
# include <sys/epoll.h>
__attribute_cold__
static void fdevent_linux_sysepoll_free(fdevents *ev) {
close(ev->epoll_fd);
free(ev->epoll_events);
}
static int fdevent_linux_sysepoll_event_del(fdevents *ev, fdnode *fdn) {
return epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fdn->fd, NULL);
}
static int fdevent_linux_sysepoll_event_set(fdevents *ev, fdnode *fdn, int events) {
int op = (-1 == fdn->fde_ndx) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
int fd = fdn->fde_ndx = fdn->fd;
struct epoll_event ep;
#ifndef EPOLLRDHUP
events &= ~FDEVENT_RDHUP;
#endif
ep.events = events | EPOLLERR | EPOLLHUP;
ep.data.ptr = fdn;
return epoll_ctl(ev->epoll_fd, op, fd, &ep);
}
static int fdevent_linux_sysepoll_poll(fdevents * const ev, int timeout_ms) {
struct epoll_event * const restrict epoll_events = ev->epoll_events;
int n = epoll_wait(ev->epoll_fd, epoll_events, ev->maxfds, timeout_ms);
for (int i = 0; i < n; ++i) {
fdnode * const fdn = (fdnode *)epoll_events[i].data.ptr;
int revents = epoll_events[i].events;
if ((fdevent_handler)NULL != fdn->handler) {
(*fdn->handler)(fdn->ctx, revents);
}
}
return n;
}
__attribute_cold__
int fdevent_linux_sysepoll_init(fdevents *ev) {
force_assert(EPOLLIN == FDEVENT_IN);
force_assert(EPOLLPRI == FDEVENT_PRI);
force_assert(EPOLLOUT == FDEVENT_OUT);
force_assert(EPOLLERR == FDEVENT_ERR);
force_assert(EPOLLHUP == FDEVENT_HUP);
#ifdef EPOLLRDHUP
force_assert(EPOLLRDHUP == FDEVENT_RDHUP);
#endif
ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
ev->event_set = fdevent_linux_sysepoll_event_set;
ev->event_del = fdevent_linux_sysepoll_event_del;
ev->poll = fdevent_linux_sysepoll_poll;
ev->free = fdevent_linux_sysepoll_free;
#ifdef EPOLL_CLOEXEC
if (-1 == (ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC))) return -1;
#else
if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) return -1;
fdevent_setfd_cloexec(ev->epoll_fd);
#endif
ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));
force_assert(NULL != ev->epoll_events);
return 0;
}
#endif

@ -1,114 +0,0 @@
#include "first.h"
#include "fdevent_impl.h"
#include "fdevent.h"
#include "buffer.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef FDEVENT_USE_POLL
# ifdef HAVE_POLL_H
# include <poll.h>
# else
# include <sys/poll.h>
# endif
__attribute_cold__
static void fdevent_poll_free(fdevents *ev) {
free(ev->pollfds);
if (ev->unused.ptr) free(ev->unused.ptr);
}
static int fdevent_poll_event_del(fdevents *ev, fdnode *fdn) {
int fd = fdn->fd;
int k = fdn->fde_ndx;
if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd) return (errno = EINVAL, -1);
ev->pollfds[k].fd = -1;
/* ev->pollfds[k].events = 0; */
/* ev->pollfds[k].revents = 0; */
if (ev->unused.size == ev->unused.used) {
ev->unused.size += 16;
ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
force_assert(NULL != ev->unused.ptr);
}
ev->unused.ptr[ev->unused.used++] = k;
return 0;
}
static int fdevent_poll_event_set(fdevents *ev, fdnode *fdn, int events) {
int fd = fdn->fd;
int k = fdn->fde_ndx;
#ifndef POLLRDHUP
events &= ~FDEVENT_RDHUP;
#endif
if (k >= 0) {
if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd) return (errno = EINVAL, -1);
ev->pollfds[k].events = events;
return 0;
}
if (ev->unused.used > 0) {
k = ev->unused.ptr[--ev->unused.used];
} else {
if (ev->size == ev->used) {
ev->size += 16;
ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
force_assert(NULL != ev->pollfds);
}
k = ev->used++;
}
fdn->fde_ndx = k;
ev->pollfds[k].fd = fd;
ev->pollfds[k].events = events;
return 0;
}
static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
struct pollfd * const restrict pfds = ev->pollfds;
fdnode ** const fdarray = ev->fdarray;
const int n = poll(pfds, ev->used, timeout_ms);
for (int i = 0, m = 0; m < n; ++i) {
if (0 == pfds[i].revents) continue;
fdnode *fdn = fdarray[pfds[i].fd];
if (0 == ((uintptr_t)fdn & 0x3))
(*fdn->handler)(fdn->ctx, pfds[i].revents);
++m;
}
return n;
}
__attribute_cold__
int fdevent_poll_init(fdevents *ev) {
force_assert(POLLIN == FDEVENT_IN);
force_assert(POLLPRI == FDEVENT_PRI);
force_assert(POLLOUT == FDEVENT_OUT);
force_assert(POLLERR == FDEVENT_ERR);
force_assert(POLLHUP == FDEVENT_HUP);
force_assert(POLLNVAL == FDEVENT_NVAL);
#ifdef POLLRDHUP
force_assert(POLLRDHUP == FDEVENT_RDHUP);
#endif
ev->type = FDEVENT_HANDLER_POLL;
ev->event_set = fdevent_poll_event_set;
ev->event_del = fdevent_poll_event_del;
ev->poll = fdevent_poll_poll;
ev->free = fdevent_poll_free;
return 0;
}
#endif

@ -1,108 +0,0 @@
#include "first.h"
#include "fdevent_impl.h"
#include "fdevent.h"
#include "buffer.h"
#include "sys-time.h"
#include <stdlib.h>
#include <string.h>
#ifdef FDEVENT_USE_SELECT
__attribute_cold__
static int fdevent_select_reset(fdevents *ev) {
FD_ZERO(&(ev->select_set_read));
FD_ZERO(&(ev->select_set_write));
FD_ZERO(&(ev->select_set_error));
ev->select_max_fd = -1;
return 0;
}
static int fdevent_select_event_del(fdevents *ev, fdnode *fdn) {
int fd = fdn->fd;
FD_CLR(fd, &(ev->select_set_read));
FD_CLR(fd, &(ev->select_set_write));
FD_CLR(fd, &(ev->select_set_error));
return 0;
}
static int fdevent_select_event_set(fdevents *ev, fdnode *fdn, int events) {
int fd = fdn->fde_ndx = fdn->fd;
/* we should be protected by max-fds, but you never know */
force_assert(fd < ((int)FD_SETSIZE));
if (events & FDEVENT_IN) {
FD_SET(fd, &(ev->select_set_read));
} else {
FD_CLR(fd, &(ev->select_set_read));
}
if (events & FDEVENT_OUT) {
FD_SET(fd, &(ev->select_set_write));
} else {
FD_CLR(fd, &(ev->select_set_write));
}
FD_SET(fd, &(ev->select_set_error));
if (fd > ev->select_max_fd) ev->select_max_fd = fd;
return 0;
}
static int fdevent_select_event_get_revent(const fdevents *ev, int ndx) {
int revents = 0;
if (FD_ISSET(ndx, &ev->select_read)) revents |= FDEVENT_IN;
if (FD_ISSET(ndx, &ev->select_write)) revents |= FDEVENT_OUT;
if (FD_ISSET(ndx, &ev->select_error)) revents |= FDEVENT_ERR;
return revents;
}
static int fdevent_select_event_next_fdndx(const fdevents *ev, int ndx) {
const int max_fd = ev->select_max_fd + 1;
for (int i = (ndx < 0) ? 0 : ndx + 1; i < max_fd; ++i) {
if (FD_ISSET(i, &(ev->select_read))) return i;
if (FD_ISSET(i, &(ev->select_write))) return i;
if (FD_ISSET(i, &(ev->select_error))) return i;
}
return -1;
}
static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
int n;
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
ev->select_read = ev->select_set_read;
ev->select_write = ev->select_set_write;
ev->select_error = ev->select_set_error;
n = select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
for (int ndx = -1, i = 0; i < n; ++i) {
fdnode *fdn;
ndx = fdevent_select_event_next_fdndx(ev, ndx);
if (-1 == ndx) break;
fdn = ev->fdarray[ndx];
if (0 == ((uintptr_t)fdn & 0x3)) {
int revents = fdevent_select_event_get_revent(ev, ndx);
(*fdn->handler)(fdn->ctx, revents);
}
}
return n;
}
__attribute_cold__
int fdevent_select_init(fdevents *ev) {
ev->type = FDEVENT_HANDLER_SELECT;
ev->event_set = fdevent_select_event_set;
ev->event_del = fdevent_select_event_del;
ev->poll = fdevent_select_poll;
ev->reset = fdevent_select_reset;
return 0;
}
#endif

@ -1,97 +0,0 @@
#include "first.h"
#include "fdevent_impl.h"
#include "fdevent.h"
#include "buffer.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
# include <sys/devpoll.h>
# include <sys/ioctl.h>
__attribute_cold__
static void fdevent_solaris_devpoll_free(fdevents *ev) {
free(ev->devpollfds);
close(ev->devpoll_fd);
}
/* return -1 is fine here */
static int fdevent_solaris_devpoll_event_del(fdevents *ev, fdnode *fdn) {
struct pollfd pfd;
pfd.fd = fdn->fd;
pfd.events = POLLREMOVE;
pfd.revents = 0;
return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
}
static int fdevent_solaris_devpoll_event_set(fdevents *ev, fdnode *fdn, int events) {
struct pollfd pfd;
pfd.fd = fdn->fde_ndx = fdn->fd;
#ifndef POLLRDHUP
events &= ~FDEVENT_RDHUP;
#endif
pfd.events = events;
pfd.revents = 0;
return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1;
}
static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
fdnode ** const fdarray = ev->fdarray;
struct pollfd * const devpollfds = ev->devpollfds;
struct dvpoll dopoll;
dopoll.dp_timeout = timeout_ms;
dopoll.dp_nfds = ev->maxfds - 1;
dopoll.dp_fds = devpollfds;
const int n = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);