From ad541c67761b8aa6da1566802c347cac4018d0c2 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Mon, 2 Nov 2026 20:50:24 +0100 Subject: Move the build sources into src/ --- ot_event.c | 357 ------------------------------------------------------------- 1 file changed, 357 deletions(-) delete mode 100644 ot_event.c (limited to 'ot_event.c') diff --git a/ot_event.c b/ot_event.c deleted file mode 100644 index 6062f70..0000000 --- a/ot_event.c +++ /dev/null @@ -1,357 +0,0 @@ -/* This software was written by Dirk Engling - It is considered beerware. Prost. Skol. Cheers or whatever. */ - -/* System */ -#include -#include -#include -#include - -/* Opentracker */ -#include "ot_event.h" - -/* One caller waits, so the scratch the mechanism needs is kept here rather - than allocated per call. */ - -/* poll works everywhere and is what the BSDs get until kqueue is written. - Defining OT_EVENT_FORCE_POLL picks it on a platform that would otherwise - use something better, which is how both are exercised by the tests. */ -#if defined(OT_EVENT_FORCE_POLL) -#define OT_EVENT_POLL -#elif defined(OT_EVENT_FORCE_KQUEUE) -#define OT_EVENT_KQUEUE -#elif defined(__linux__) -#define OT_EVENT_EPOLL -#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) -#define OT_EVENT_KQUEUE -#else -#define OT_EVENT_POLL -#endif - -#ifdef OT_EVENT_EPOLL -/* ------------------------------------------------------------- epoll */ - -#include - -static int g_epoll = -1; -static struct epoll_event *g_ready; -static int g_ready_space; - -const char *event_mechanism(void) { return "epoll"; } -/* The set lives in the kernel, and epoll_ctl during another thread's - epoll_wait is what it is for */ -int event_can_share(void) { return 1; } - -int event_init(void) { - g_ready = NULL; - g_ready_space = 0; - return (g_epoll = epoll_create1(EPOLL_CLOEXEC)) == -1 ? -1 : 0; -} - -void event_deinit(void) { - if (g_epoll != -1) - close(g_epoll); - free(g_ready); - g_epoll = -1; - g_ready = NULL; - g_ready_space = 0; -} - -static int event_ctl(int op, int fd, int what, uint32_t generation) { - struct epoll_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.events = (what & EVENT_IN ? (uint32_t)EPOLLIN : 0) | (what & EVENT_OUT ? (uint32_t)EPOLLOUT : 0); - /* The generation rides along inside the kernel, so an event says which - connection it belongs to without anybody looking it up */ - ev.data.u64 = ((uint64_t)generation << 32) | (uint32_t)fd; - return epoll_ctl(g_epoll, op, fd, &ev); -} - -int event_add(int fd, int what, uint32_t generation) { return event_ctl(EPOLL_CTL_ADD, fd, what, generation); } -int event_modify(int fd, int what, uint32_t generation) { return event_ctl(EPOLL_CTL_MOD, fd, what, generation); } -int event_del(int fd) { return epoll_ctl(g_epoll, EPOLL_CTL_DEL, fd, NULL); } - -/* A descriptor leaves the interest list when the last reference to its open - file description is closed, and the tracker never duplicates one */ -int event_close(int fd) { return close(fd); } - -int event_wait(ot_event *out, int max, int timeout_ms) { - int count, i; - - if (max > g_ready_space) { - struct epoll_event *grown = realloc(g_ready, (size_t)max * sizeof(struct epoll_event)); - - if (!grown) - return -1; - g_ready = grown; - g_ready_space = max; - } - - /* An interrupted wait is reported as no events rather than retried here, - so that the caller gets to look at whatever the signal was about */ - if ((count = epoll_wait(g_epoll, g_ready, max, timeout_ms)) == -1) - return errno == EINTR ? 0 : -1; - for (i = 0; i < count; ++i) { - uint32_t events = g_ready[i].events; - - out[i].fd = (int)(uint32_t)g_ready[i].data.u64; - out[i].generation = (uint32_t)(g_ready[i].data.u64 >> 32); - /* A hangup or an error is reported as both, so whichever side the caller - was waiting on gets to notice */ - out[i].what = (events & (EPOLLIN | EPOLLHUP | EPOLLERR) ? EVENT_IN : 0) | - (events & (EPOLLOUT | EPOLLHUP | EPOLLERR) ? EVENT_OUT : 0); - } - return count; -} - -#endif /* OT_EVENT_EPOLL */ - -#ifdef OT_EVENT_KQUEUE -/* ------------------------------------------------------------ kqueue */ - -#include -#include -#include - -static int g_kqueue = -1; -static struct kevent *g_ready; -static int g_ready_space; - -const char *event_mechanism(void) { return "kqueue"; } -/* The set lives in the kernel, and kevent may be called from any thread */ -int event_can_share(void) { return 1; } - -int event_init(void) { - g_ready = NULL; - g_ready_space = 0; - return (g_kqueue = kqueue()) == -1 ? -1 : 0; -} - -void event_deinit(void) { - if (g_kqueue != -1) - close(g_kqueue); - free(g_ready); - g_kqueue = -1; - g_ready = NULL; - g_ready_space = 0; -} - -/* kqueue keeps one registration per filter, so reading and writing are two - entries. A change of interest is an add of the one wanted and a delete - of the one not. The generation travels in udata, which the kernel passes - back untouched. */ -static int event_change(int fd, int what, uint32_t generation, int deleting) { - struct kevent change[2], result[2]; - void *udata = (void *)(uintptr_t)(((uint64_t)generation << 32) | (uint32_t)fd); - int succeeded = 0, count, i; - - EV_SET(&change[0], (uintptr_t)fd, EVFILT_READ, - EV_RECEIPT | ((deleting || !(what & EVENT_IN)) ? EV_DELETE : EV_ADD), 0, 0, udata); - EV_SET(&change[1], (uintptr_t)fd, EVFILT_WRITE, - EV_RECEIPT | ((deleting || !(what & EVENT_OUT)) ? EV_DELETE : EV_ADD), 0, 0, udata); - - if ((count = kevent(g_kqueue, change, 2, result, 2, NULL)) == -1) - return -1; - - for (i = 0; i < count && i < 2; ++i) { - if (!result[i].data) { - ++succeeded; - continue; - } - /* Dropping interest we never registered is not a failure */ - if ((change[i].flags & EV_DELETE) && result[i].data == ENOENT) - continue; - errno = (int)result[i].data; - return -1; - } - - /* Nothing at all was registered or removed, so the descriptor is unknown */ - if (!succeeded) { - errno = ENOENT; - return -1; - } - return 0; -} - -int event_add(int fd, int what, uint32_t generation) { return what ? event_change(fd, what, generation, 0) : 0; } -int event_modify(int fd, int what, uint32_t generation) { return event_change(fd, what, generation, 0); } -int event_del(int fd) { return event_change(fd, 0, 0, 1); } - -/* Closing a descriptor removes every kevent that references it */ -int event_close(int fd) { return close(fd); } - -int event_wait(ot_event *out, int max, int timeout_ms) { - struct timespec timeout; - struct timespec *deadline = NULL; - int count, i; - - if (max > g_ready_space) { - struct kevent *grown = realloc(g_ready, (size_t)max * sizeof(struct kevent)); - - if (!grown) - return -1; - g_ready = grown; - g_ready_space = max; - } - - if (timeout_ms >= 0) { - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_nsec = (long)(timeout_ms % 1000) * 1000000; - deadline = &timeout; - } - - /* An interrupted wait is reported as no events rather than retried here, - so that the caller gets to look at whatever the signal was about */ - if ((count = kevent(g_kqueue, NULL, 0, g_ready, max, deadline)) == -1) - return errno == EINTR ? 0 : -1; - for (i = 0; i < count; ++i) { - uint64_t udata = (uint64_t)(uintptr_t)g_ready[i].udata; - int eof = (g_ready[i].flags & (EV_EOF | EV_ERROR)) != 0; - - out[i].fd = (int)(uint32_t)udata; - out[i].generation = (uint32_t)(udata >> 32); - out[i].what = ((g_ready[i].filter == EVFILT_READ || eof) ? EVENT_IN : 0) | - ((g_ready[i].filter == EVFILT_WRITE || eof) ? EVENT_OUT : 0); - } - return count; -} - -#endif /* OT_EVENT_KQUEUE */ - -#ifdef OT_EVENT_POLL -/* -------------------------------------------------------------- poll */ - -#include - -/* poll wants its descriptors packed, so the registered ones live in one - array and a second maps a descriptor number to its place in it. */ -static struct pollfd *g_pfds; -static uint32_t *g_generation; -static int *g_where; -static int g_count, g_space, g_where_space; - -const char *event_mechanism(void) { return "poll"; } -/* The arrays below are ours and nothing guards them */ -int event_can_share(void) { return 0; } - -int event_init(void) { - g_pfds = NULL, g_generation = NULL, g_where = NULL; - g_count = g_space = g_where_space = 0; - return 0; -} - -void event_deinit(void) { - free(g_pfds), free(g_generation), free(g_where); - g_pfds = NULL, g_generation = NULL, g_where = NULL; - g_count = g_space = g_where_space = 0; -} - -static short event_to_poll(int what) { - return (short)((what & EVENT_IN ? POLLIN : 0) | (what & EVENT_OUT ? POLLOUT : 0)); -} - -static int event_room_for(int fd) { - if (fd >= g_where_space) { - int space = g_where_space ? g_where_space : 64; - int *grown; - - while (space <= fd) - space *= 2; - if (!(grown = realloc(g_where, (size_t)space * sizeof(int)))) - return -1; - while (g_where_space < space) - grown[g_where_space++] = -1; - g_where = grown; - } - - if (g_count == g_space) { - int space = g_space ? g_space * 2 : 64; - struct pollfd *pfds = realloc(g_pfds, (size_t)space * sizeof(struct pollfd)); - uint32_t *gens; - - if (!pfds) - return -1; - g_pfds = pfds; - if (!(gens = realloc(g_generation, (size_t)space * sizeof(uint32_t)))) - return -1; - g_generation = gens; - g_space = space; - } - return 0; -} - -int event_add(int fd, int what, uint32_t generation) { - if (fd < 0 || event_room_for(fd) == -1) - return -1; - if (g_where[fd] != -1) { - errno = EEXIST; - return -1; - } - - g_pfds[g_count].fd = fd; - g_pfds[g_count].events = event_to_poll(what); - g_pfds[g_count].revents = 0; - g_generation[g_count] = generation; - g_where[fd] = g_count++; - return 0; -} - -int event_modify(int fd, int what, uint32_t generation) { - if (fd < 0 || fd >= g_where_space || g_where[fd] == -1) { - errno = ENOENT; - return -1; - } - g_pfds[g_where[fd]].events = event_to_poll(what); - g_generation[g_where[fd]] = generation; - return 0; -} - -int event_del(int fd) { - int at; - - if (fd < 0 || fd >= g_where_space || (at = g_where[fd]) == -1) { - errno = ENOENT; - return -1; - } - - /* The last one moves into the gap, so the array stays packed */ - g_pfds[at] = g_pfds[--g_count]; - g_generation[at] = g_generation[g_count]; - g_where[g_pfds[at].fd] = at; - g_where[fd] = -1; - return 0; -} - -/* Nothing here lives in the kernel, so the entry has to come out by hand - before the descriptor goes, or poll reports POLLNVAL for it forever */ -int event_close(int fd) { - event_del(fd); - return close(fd); -} - -int event_wait(ot_event *out, int max, int timeout_ms) { - int ready, found = 0, i; - - /* An interrupted wait is reported as no events rather than retried here, - so that the caller gets to look at whatever the signal was about */ - if ((ready = poll(g_pfds, (nfds_t)g_count, timeout_ms)) == -1) - return errno == EINTR ? 0 : -1; - if (ready <= 0) - return ready; - - for (i = 0; i < g_count && found < max; ++i) { - short revents = g_pfds[i].revents; - - if (!revents) - continue; - out[found].fd = g_pfds[i].fd; - out[found].generation = g_generation[i]; - out[found].what = (revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL) ? EVENT_IN : 0) | - (revents & (POLLOUT | POLLHUP | POLLERR | POLLNVAL) ? EVENT_OUT : 0); - ++found; - } - return found; -} - -#endif /* OT_EVENT_POLL */ -- cgit v1.3