event loop for darwin

This commit is contained in:
pantonshire committed 2025-12-22 16:08:31 +00:00
1 parent 45284910cc
commit 9a00a29af6
7 files changed
+218 -26

No files matched your search

+108 -15
View File
@@ -1,28 +1,121 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include "eventloop.h"
#include "mem.h"
#include "container_of.h"
#include "list.h"
struct eventloop {
int kqueue_fd;
};
int owd_eventloop_init(struct owd_eventloop *el) {
intrusive_list_init_empty(&el->event_list);
struct eventloop *eventloop_new(void) {
MEM_SCOPED(struct eventloop, el);
if ((el->kqueue_fd = kqueue()) < 0)
return -1;
el->kqueue_timer_next = 0;
if (!(el = malloc(sizeof(struct eventloop)))) {
errno = ENOMEM;
return NULL;
}
return MEM_RELEASE(struct eventloop, &el);
return 0;
}
void eventloop_free(struct eventloop *el) {
static void event_cleanup(struct owd_eventloop *el, struct owd_event *e) {
if (!e)
return;
// TODO: any platform-specific cleanup
}
void owd_eventloop_cleanup(struct owd_eventloop *el) {
struct intrusive_list *li;
struct owd_event *e;
if (!el)
return;
INTRUSIVE_LIST_FOR_EACH_NO_REMOVE(li, &el->event_list) {
e = CONTAINER_OF(li, struct owd_event, list);
event_cleanup(el, e);
}
close(el->kqueue_fd);
free(el);
}
int owd_eventloop_wait(
struct owd_eventloop *el,
owd_event_id_t *id_out,
const struct timespec *timeout)
{
struct kevent kev;
int res;
do {
res = kevent(el->kqueue_fd, NULL, 0, &kev, 1, timeout);
} while ((res < 0) && (errno == EINTR));
if (res <= 0) {
if (!res)
errno = ETIMEDOUT;
return -1;
}
id_out->obj = kev.ident;
if (kev.filter & EVFILT_TIMER)
id_out->source = OWD_EVENT_SOURCE_TIMER;
else
id_out->source = OWD_EVENT_SOURCE_FD;
return 0;
}
int owd_eventloop_clear(struct owd_eventloop *el, struct owd_event *e) {
// TODO: read timerfd on linux
return 0;
}
void owd_eventloop_remove(struct owd_eventloop *el, struct owd_event *e) {
struct kevent kev;
memset(&kev, 0, sizeof(kev));
kev.ident = e->kqueue_ident;
kev.filter = e->kqueue_filter;
kev.flags = EV_DELETE;
kevent(el->kqueue_fd, &kev, 1, NULL, 0, NULL);
event_cleanup(el, e);
}
int owd_eventloop_add_timer(
struct owd_eventloop *el,
struct owd_event *e,
uint64_t millis,
bool oneshot)
{
struct kevent kev;
uintptr_t ident;
unsigned short kev_flags;
ident = el->kqueue_timer_next;
kev_flags = 0;
if (oneshot)
kev_flags |= EV_ONESHOT;
memset(&kev, 0, sizeof(kev));
kev.ident = ident;
kev.filter = EVFILT_TIMER;
kev.flags = EV_ADD | kev_flags;
kev.data = (int64_t)millis;
if (kevent(el->kqueue_fd, &kev, 1, NULL, 0, NULL))
return -1;
e->id.obj = ident;
e->id.source = OWD_EVENT_SOURCE_TIMER;
e->kqueue_ident = kev.ident;
e->kqueue_filter = kev.filter;
el->kqueue_timer_next++;
return 0;
}