Truncated history

This commit is contained in:
bol-van
2024-10-28 09:32:24 +03:00
commit 2aaa2f7cf3
300 changed files with 43184 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
#ifndef SHIM_SYS_EPOLL_H
#define SHIM_SYS_EPOLL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <sys/types.h>
#include <fcntl.h>
#if defined(__NetBSD__)
#include <sys/sigtypes.h>
#elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__APPLE__)
#include <sys/signal.h>
#endif
#define EPOLL_CLOEXEC O_CLOEXEC
#define EPOLL_NONBLOCK O_NONBLOCK
enum EPOLL_EVENTS { __EPOLL_DUMMY };
#define EPOLLIN 0x001
#define EPOLLPRI 0x002
#define EPOLLOUT 0x004
#define EPOLLRDNORM 0x040
#define EPOLLNVAL 0x020
#define EPOLLRDBAND 0x080
#define EPOLLWRNORM 0x100
#define EPOLLWRBAND 0x200
#define EPOLLMSG 0x400
#define EPOLLERR 0x008
#define EPOLLHUP 0x010
#define EPOLLRDHUP 0x2000
#define EPOLLEXCLUSIVE (1U<<28)
#define EPOLLWAKEUP (1U<<29)
#define EPOLLONESHOT (1U<<30)
#define EPOLLET (1U<<31)
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events;
epoll_data_t data;
}
#ifdef __x86_64__
__attribute__ ((__packed__))
#endif
;
int epoll_create(int);
int epoll_create1(int);
int epoll_ctl(int, int, int, struct epoll_event *);
int epoll_wait(int, struct epoll_event *, int, int);
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
#ifndef SHIM_SYS_SHIM_HELPERS
#define SHIM_SYS_SHIM_HELPERS
#include <unistd.h> /* IWYU pragma: keep */
extern int epoll_shim_close(int);
#define close epoll_shim_close
#endif
#ifdef __cplusplus
}
#endif
#endif /* sys/epoll.h */

305
tpws/epoll-shim/src/epoll.c Normal file
View File

@@ -0,0 +1,305 @@
#include <sys/epoll.h>
#include <sys/event.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "epoll_shim_ctx.h"
#ifdef __NetBSD__
#define ppoll pollts
#endif
// TODO(jan): Remove this once the definition is exposed in <sys/time.h> in
// all supported FreeBSD versions.
#ifndef timespecsub
#define timespecsub(tsp, usp, vsp) \
do { \
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
if ((vsp)->tv_nsec < 0) { \
(vsp)->tv_sec--; \
(vsp)->tv_nsec += 1000000000L; \
} \
} while (0)
#endif
static errno_t
epollfd_close(FDContextMapNode *node)
{
return epollfd_ctx_terminate(&node->ctx.epollfd);
}
static FDContextVTable const epollfd_vtable = {
.read_fun = fd_context_default_read,
.write_fun = fd_context_default_write,
.close_fun = epollfd_close,
};
static FDContextMapNode *
epoll_create_impl(errno_t *ec)
{
FDContextMapNode *node;
node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec);
if (!node) {
return NULL;
}
node->flags = 0;
if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/
node->fd)) != 0) {
goto fail;
}
node->vtable = &epollfd_vtable;
return node;
fail:
epoll_shim_ctx_remove_node_explicit(&epoll_shim_ctx, node);
(void)fd_context_map_node_destroy(node);
return NULL;
}
static int
epoll_create_common(void)
{
FDContextMapNode *node;
errno_t ec;
node = epoll_create_impl(&ec);
if (!node) {
errno = ec;
return -1;
}
return node->fd;
}
int
epoll_create(int size)
{
if (size <= 0) {
errno = EINVAL;
return -1;
}
return epoll_create_common();
}
int
epoll_create1(int flags)
{
if (flags & ~EPOLL_CLOEXEC) {
errno = EINVAL;
return -1;
}
return epoll_create_common();
}
static errno_t
epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
{
if (!ev && op != EPOLL_CTL_DEL) {
return EFAULT;
}
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node || node->vtable != &epollfd_vtable) {
struct stat sb;
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
}
return epollfd_ctx_ctl(&node->ctx.epollfd, op, fd2, ev);
}
int
epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
{
errno_t ec = epoll_ctl_impl(fd, op, fd2, ev);
if (ec != 0) {
errno = ec;
return -1;
}
return 0;
}
static bool
is_no_wait_deadline(struct timespec const *deadline)
{
return (deadline && deadline->tv_sec == 0 && deadline->tv_nsec == 0);
}
static errno_t
epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs)
{
errno_t ec;
for (;;) {
if ((ec = epollfd_ctx_wait(epollfd, /**/
ev, cnt, actual_cnt)) != 0) {
return ec;
}
if (*actual_cnt || is_no_wait_deadline(deadline)) {
return 0;
}
struct timespec timeout;
if (deadline) {
struct timespec current_time;
if (clock_gettime(CLOCK_MONOTONIC, /**/
&current_time) < 0) {
return errno;
}
timespecsub(deadline, &current_time, &timeout);
if (timeout.tv_sec < 0 ||
is_no_wait_deadline(&timeout)) {
return 0;
}
}
(void)pthread_mutex_lock(&epollfd->mutex);
nfds_t nfds = (nfds_t)(1 + epollfd->poll_fds_size);
size_t size;
if (__builtin_mul_overflow(nfds, sizeof(struct pollfd),
&size)) {
ec = ENOMEM;
(void)pthread_mutex_unlock(&epollfd->mutex);
return ec;
}
struct pollfd *pfds = malloc(size);
if (!pfds) {
ec = errno;
(void)pthread_mutex_unlock(&epollfd->mutex);
return ec;
}
epollfd_ctx_fill_pollfds(epollfd, pfds);
(void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex);
++epollfd->nr_polling_threads;
(void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex);
(void)pthread_mutex_unlock(&epollfd->mutex);
/*
* This surfaced a race condition when
* registering/unregistering poll-only fds. The tests should
* still succeed if this is enabled.
*/
#if 0
usleep(500000);
#endif
int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs);
if (n < 0) {
ec = errno;
}
free(pfds);
(void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex);
--epollfd->nr_polling_threads;
if (epollfd->nr_polling_threads == 0) {
(void)pthread_cond_signal(
&epollfd->nr_polling_threads_cond);
}
(void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex);
if (n < 0) {
return ec;
}
}
}
static errno_t
timeout_to_deadline(struct timespec *deadline, int to)
{
assert(to >= 0);
if (to == 0) {
*deadline = (struct timespec){0, 0};
} else if (to > 0) {
if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0) {
return errno;
}
if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1,
&deadline->tv_sec)) {
return EINVAL;
}
deadline->tv_sec -= 1;
deadline->tv_nsec += (to % 1000) * 1000000L;
if (deadline->tv_nsec >= 1000000000) {
deadline->tv_nsec -= 1000000000;
deadline->tv_sec += 1;
}
}
return 0;
}
static errno_t
epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to,
sigset_t const *sigs, int *actual_cnt)
{
if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event))) {
return EINVAL;
}
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node || node->vtable != &epollfd_vtable) {
struct stat sb;
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
}
struct timespec deadline;
errno_t ec;
if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0) {
return ec;
}
return epollfd_ctx_wait_or_block(&node->ctx.epollfd, ev, cnt,
actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
}
int
epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
sigset_t const *sigs)
{
int actual_cnt;
errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt);
if (ec != 0) {
errno = ec;
return -1;
}
return actual_cnt;
}
int
epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
{
return epoll_pwait(fd, ev, cnt, to, NULL);
}

View File

@@ -0,0 +1,281 @@
#include "epoll_shim_ctx.h"
#include <sys/event.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
static void
fd_context_map_node_init(FDContextMapNode *node, int kq)
{
node->fd = kq;
node->vtable = NULL;
}
static FDContextMapNode *
fd_context_map_node_create(int kq, errno_t *ec)
{
FDContextMapNode *node;
node = malloc(sizeof(FDContextMapNode));
if (!node) {
*ec = errno;
return NULL;
}
fd_context_map_node_init(node, kq);
return node;
}
static errno_t
fd_context_map_node_terminate(FDContextMapNode *node, bool close_fd)
{
errno_t ec = node->vtable ? node->vtable->close_fun(node) : 0;
if (close_fd && close(node->fd) < 0) {
ec = ec ? ec : errno;
}
return ec;
}
errno_t
fd_context_map_node_destroy(FDContextMapNode *node)
{
errno_t ec = fd_context_map_node_terminate(node, true);
free(node);
return ec;
}
/**/
errno_t
fd_context_default_read(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred)
{
(void)node;
(void)buf;
(void)nbytes;
(void)bytes_transferred;
return EINVAL;
}
errno_t
fd_context_default_write(FDContextMapNode *node, /**/
void const *buf, size_t nbytes, size_t *bytes_transferred)
{
(void)node;
(void)buf;
(void)nbytes;
(void)bytes_transferred;
return EINVAL;
}
/**/
static int
fd_context_map_node_cmp(FDContextMapNode *e1, FDContextMapNode *e2)
{
return (e1->fd < e2->fd) ? -1 : (e1->fd > e2->fd);
}
RB_PROTOTYPE_STATIC(fd_context_map_, fd_context_map_node_, entry,
fd_context_map_node_cmp);
RB_GENERATE_STATIC(fd_context_map_, fd_context_map_node_, entry,
fd_context_map_node_cmp);
EpollShimCtx epoll_shim_ctx = {
.fd_context_map = RB_INITIALIZER(&fd_context_map),
.mutex = PTHREAD_MUTEX_INITIALIZER,
};
static FDContextMapNode *
epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
errno_t *ec)
{
FDContextMapNode *node;
{
FDContextMapNode find;
find.fd = kq;
node = RB_FIND(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, &find);
}
if (node) {
/*
* If we get here, someone must have already closed the old fd
* with a normal 'close()' call, i.e. not with our
* 'epoll_shim_close()' wrapper. The fd inside the node
* refers now to the new kq we are currently creating. We
* must not close it, but we must clean up the old context
* object!
*/
(void)fd_context_map_node_terminate(node, false);
fd_context_map_node_init(node, kq);
} else {
node = fd_context_map_node_create(kq, ec);
if (!node) {
return NULL;
}
void *colliding_node = RB_INSERT(fd_context_map_,
&epoll_shim_ctx->fd_context_map, node);
(void)colliding_node;
assert(colliding_node == NULL);
}
return node;
}
FDContextMapNode *
epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
{
FDContextMapNode *node;
int kq = kqueue();
if (kq < 0) {
*ec = errno;
return NULL;
}
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
node = epoll_shim_ctx_create_node_impl(epoll_shim_ctx, kq, ec);
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
if (!node) {
close(kq);
}
return node;
}
static FDContextMapNode *
epoll_shim_ctx_find_node_impl(EpollShimCtx *epoll_shim_ctx, int fd)
{
FDContextMapNode *node;
FDContextMapNode find;
find.fd = fd;
node = RB_FIND(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, &find);
return node;
}
FDContextMapNode *
epoll_shim_ctx_find_node(EpollShimCtx *epoll_shim_ctx, int fd)
{
FDContextMapNode *node;
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd);
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
return node;
}
FDContextMapNode *
epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
{
FDContextMapNode *node;
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd);
if (node) {
RB_REMOVE(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, node);
}
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
return node;
}
void
epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
FDContextMapNode *node)
{
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
RB_REMOVE(fd_context_map_, /**/
&epoll_shim_ctx->fd_context_map, node);
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
}
/**/
int
epoll_shim_close(int fd)
{
FDContextMapNode *node;
node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd);
if (!node) {
return close(fd);
}
errno_t ec = fd_context_map_node_destroy(node);
if (ec != 0) {
errno = ec;
return -1;
}
return 0;
}
ssize_t
epoll_shim_read(int fd, void *buf, size_t nbytes)
{
FDContextMapNode *node;
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node) {
return read(fd, buf, nbytes);
}
if (nbytes > SSIZE_MAX) {
errno = EINVAL;
return -1;
}
size_t bytes_transferred;
errno_t ec = node->vtable->read_fun(node, /**/
buf, nbytes, &bytes_transferred);
if (ec != 0) {
errno = ec;
return -1;
}
return (ssize_t)bytes_transferred;
}
ssize_t
epoll_shim_write(int fd, void const *buf, size_t nbytes)
{
FDContextMapNode *node;
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
if (!node) {
return write(fd, buf, nbytes);
}
if (nbytes > SSIZE_MAX) {
errno = EINVAL;
return -1;
}
size_t bytes_transferred;
errno_t ec = node->vtable->write_fun(node, /**/
buf, nbytes, &bytes_transferred);
if (ec != 0) {
errno = ec;
return -1;
}
return (ssize_t)bytes_transferred;
}

View File

@@ -0,0 +1,76 @@
#ifndef EPOLL_SHIM_CTX_H_
#define EPOLL_SHIM_CTX_H_
#include "fix.h"
#include <sys/tree.h>
#include <unistd.h>
#include "epollfd_ctx.h"
#include "eventfd_ctx.h"
#include "signalfd_ctx.h"
#include "timerfd_ctx.h"
struct fd_context_map_node_;
typedef struct fd_context_map_node_ FDContextMapNode;
typedef errno_t (*fd_context_read_fun)(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred);
typedef errno_t (*fd_context_write_fun)(FDContextMapNode *node, /**/
const void *buf, size_t nbytes, size_t *bytes_transferred);
typedef errno_t (*fd_context_close_fun)(FDContextMapNode *node);
typedef struct {
fd_context_read_fun read_fun;
fd_context_write_fun write_fun;
fd_context_close_fun close_fun;
} FDContextVTable;
errno_t fd_context_default_read(FDContextMapNode *node, /**/
void *buf, size_t nbytes, size_t *bytes_transferred);
errno_t fd_context_default_write(FDContextMapNode *node, /**/
void const *buf, size_t nbytes, size_t *bytes_transferred);
struct fd_context_map_node_ {
RB_ENTRY(fd_context_map_node_) entry;
int fd;
int flags;
union {
EpollFDCtx epollfd;
EventFDCtx eventfd;
TimerFDCtx timerfd;
SignalFDCtx signalfd;
} ctx;
FDContextVTable const *vtable;
};
errno_t fd_context_map_node_destroy(FDContextMapNode *node);
/**/
typedef RB_HEAD(fd_context_map_, fd_context_map_node_) FDContextMap;
typedef struct {
FDContextMap fd_context_map;
pthread_mutex_t mutex;
} EpollShimCtx;
extern EpollShimCtx epoll_shim_ctx;
FDContextMapNode *epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx,
errno_t *ec);
FDContextMapNode *epoll_shim_ctx_find_node(EpollShimCtx *epoll_shim_ctx,
int fd);
FDContextMapNode *epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx,
int fd);
void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
FDContextMapNode *node);
/**/
int epoll_shim_close(int fd);
ssize_t epoll_shim_read(int fd, void *buf, size_t nbytes);
ssize_t epoll_shim_write(int fd, void const *buf, size_t nbytes);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
#ifndef EPOLLFD_CTX_H_
#define EPOLLFD_CTX_H_
#include "fix.h"
#define SHIM_SYS_SHIM_HELPERS
#include <sys/epoll.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <poll.h>
#include <pthread.h>
struct registered_fds_node_;
typedef struct registered_fds_node_ RegisteredFDsNode;
typedef enum {
EOF_STATE_READ_EOF = 0x01,
EOF_STATE_WRITE_EOF = 0x02,
} EOFState;
typedef enum {
NODE_TYPE_FIFO = 1,
NODE_TYPE_SOCKET = 2,
NODE_TYPE_KQUEUE = 3,
NODE_TYPE_OTHER = 4,
NODE_TYPE_POLL = 5,
} NodeType;
struct registered_fds_node_ {
RB_ENTRY(registered_fds_node_) entry;
TAILQ_ENTRY(registered_fds_node_) pollfd_list_entry;
int fd;
epoll_data_t data;
bool is_registered;
bool has_evfilt_read;
bool has_evfilt_write;
bool has_evfilt_except;
bool got_evfilt_read;
bool got_evfilt_write;
bool got_evfilt_except;
NodeType node_type;
union {
struct {
bool readable;
bool writable;
} fifo;
} node_data;
int eof_state;
bool pollpri_active;
uint16_t events;
uint32_t revents;
bool is_edge_triggered;
bool is_oneshot;
bool is_on_pollfd_list;
int self_pipe[2];
};
typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList;
typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet;
typedef struct {
int kq; // non owning
pthread_mutex_t mutex;
PollFDList poll_fds;
size_t poll_fds_size;
RegisteredFDsSet registered_fds;
size_t registered_fds_size;
struct kevent *kevs;
size_t kevs_length;
struct pollfd *pfds;
size_t pfds_length;
pthread_mutex_t nr_polling_threads_mutex;
pthread_cond_t nr_polling_threads_cond;
unsigned long nr_polling_threads;
int self_pipe[2];
} EpollFDCtx;
errno_t epollfd_ctx_init(EpollFDCtx *epollfd, int kq);
errno_t epollfd_ctx_terminate(EpollFDCtx *epollfd);
void epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds);
errno_t epollfd_ctx_ctl(EpollFDCtx *epollfd, int op, int fd2,
struct epoll_event *ev);
errno_t epollfd_ctx_wait(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
int *actual_cnt);
#endif

View File

@@ -0,0 +1,31 @@
#ifndef EVENTFD_CTX_H_
#define EVENTFD_CTX_H_
#include "fix.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0)
typedef struct {
int kq_; // non owning
int flags_;
pthread_mutex_t mutex_;
bool is_signalled_;
int self_pipe_[2]; // only used if EVFILT_USER is not available
uint_least64_t counter_;
} EventFDCtx;
errno_t eventfd_ctx_init(EventFDCtx *eventfd, int kq, unsigned int counter,
int flags);
errno_t eventfd_ctx_terminate(EventFDCtx *eventfd);
errno_t eventfd_ctx_write(EventFDCtx *eventfd, uint64_t value);
errno_t eventfd_ctx_read(EventFDCtx *eventfd, uint64_t *value);
#endif

19
tpws/epoll-shim/src/fix.c Normal file
View File

@@ -0,0 +1,19 @@
#include "fix.h"
#ifdef __APPLE__
#include <errno.h>
int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask)
{
// macos does not implement ppoll
// this is a hacky ppoll shim. only for tpws which does not require sigmask
if (sigmask)
{
errno = EINVAL;
return -1;
}
return poll(fds,nfds,tmo_p ? tmo_p->tv_sec*1000 + tmo_p->tv_nsec/1000000 : -1);
}
#endif

20
tpws/epoll-shim/src/fix.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#ifndef _ERRNO_T_DEFINED
#define _ERRNO_T_DEFINED
typedef int errno_t;
#endif
#ifdef __APPLE__
#include <time.h>
#include <signal.h>
#include <poll.h>
struct itimerspec {
struct timespec it_interval;
struct timespec it_value;
};
int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask);
#endif

View File

@@ -0,0 +1,19 @@
#ifndef SIGNALFD_CTX_H_
#define SIGNALFD_CTX_H_
#include "fix.h"
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
int kq; // non owning
} SignalFDCtx;
errno_t signalfd_ctx_init(SignalFDCtx *signalfd, int kq, const sigset_t *sigs);
errno_t signalfd_ctx_terminate(SignalFDCtx *signalfd);
errno_t signalfd_ctx_read(SignalFDCtx *signalfd, uint32_t *ident);
#endif

View File

@@ -0,0 +1,38 @@
#ifndef TIMERFD_CTX_H_
#define TIMERFD_CTX_H_
#include "fix.h"
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
typedef struct {
int kq; // non owning
int flags;
pthread_mutex_t mutex;
int clockid;
/*
* Next expiration time, absolute (clock given by clockid).
* If it_interval is != 0, it is a periodic timer.
* If it_value is == 0, the timer is disarmed.
*/
struct itimerspec current_itimerspec;
uint64_t nr_expirations;
} TimerFDCtx;
errno_t timerfd_ctx_init(TimerFDCtx *timerfd, int kq, int clockid);
errno_t timerfd_ctx_terminate(TimerFDCtx *timerfd);
errno_t timerfd_ctx_settime(TimerFDCtx *timerfd, int flags,
struct itimerspec const *new, struct itimerspec *old);
errno_t timerfd_ctx_gettime(TimerFDCtx *timerfd, struct itimerspec *cur);
errno_t timerfd_ctx_read(TimerFDCtx *timerfd, uint64_t *value);
#endif