diff --git a/include/eventloop.h b/include/eventloop.h index fbad995..7674215 100644 --- a/include/eventloop.h +++ b/include/eventloop.h @@ -4,7 +4,9 @@ #include #include +#include "platform.h" #include "list.h" +#include "scoped.h" #define OWD_EVENT_READABLE (1 << 0) #define OWD_EVENT_WRITABLE (1 << 1) @@ -22,16 +24,28 @@ typedef struct { struct owd_event { owd_event_id_t id; struct intrusive_list list; - + +#if defined(EVENTLOOP_KQUEUE) uintptr_t kqueue_ident; short kqueue_filter; + +#elif defined(EVENTLOOP_EPOLL) + int epoll_registered_fd; + +#endif }; struct owd_eventloop { struct intrusive_list event_list; +#if defined(EVENTLOOP_KQUEUE) uintptr_t kqueue_timer_next; int kqueue_fd; + +#elif defined(EVENTLOOP_EPOLL) + int epoll_fd; + +#endif }; static inline bool owd_event_id_eq(owd_event_id_t eid1, owd_event_id_t eid2) { @@ -45,3 +59,9 @@ int owd_eventloop_wait(struct owd_eventloop *el, owd_event_id_t *id_out, const s int owd_eventloop_clear(struct owd_eventloop *el, struct owd_event *e); void owd_eventloop_remove(struct owd_eventloop *el, struct owd_event *e); int owd_eventloop_add_timer(struct owd_eventloop *el, struct owd_event *e, uint64_t millis, bool oneshot); +int owd_eventloop_add_fd(struct owd_eventloop *el, struct owd_event *e, int fd, uint32_t flags); + +DEF_SCOPED_TYPE(eventloop_stack, struct owd_eventloop *, NULL, owd_eventloop_cleanup) + +#define EVENTLOOP_STACK_SCOPED(VAL) SCOPED(eventloop_stack, struct owd_eventloop *, VAL) +#define EVENTLOOP_STACK_CLOSE(EL) _scoped_eventloop_stack_cleanup(EL) diff --git a/include/eventloop_platform.h b/include/eventloop_platform.h new file mode 100644 index 0000000..4b2ffdf --- /dev/null +++ b/include/eventloop_platform.h @@ -0,0 +1,12 @@ +#pragma once + +#include "eventloop.h" + +int owd_platform_el_init(struct owd_eventloop *el); +void owd_platform_el_cleanup(struct owd_eventloop *el); +void owd_platform_el_event_remove(struct owd_eventloop *el, struct owd_event *e); +void owd_platform_el_event_cleanup(struct owd_eventloop *el, struct owd_event *e); +int owd_platform_el_event_clear(struct owd_eventloop *el, struct owd_event *e); +int owd_platform_el_wait(struct owd_eventloop *el, owd_event_id_t *id_out, const struct timespec *timeout); +int owd_platform_el_add_timer(struct owd_eventloop *el, struct owd_event *e, uint64_t millis, bool oneshot); +int owd_platform_el_add_fd(struct owd_eventloop *el, struct owd_event *e, int fd, uint32_t flags); diff --git a/src/eventloop.c b/src/eventloop.c index db775c0..b5b6492 100644 --- a/src/eventloop.c +++ b/src/eventloop.c @@ -1,31 +1,19 @@ -#include -#include -#include -#include -#include -#include - #include "eventloop.h" +#include "eventloop_platform.h" #include "container_of.h" #include "list.h" int owd_eventloop_init(struct owd_eventloop *el) { + int platform_res; + intrusive_list_init_empty(&el->event_list); - if ((el->kqueue_fd = kqueue()) < 0) - return -1; - el->kqueue_timer_next = 0; + if ((platform_res = owd_platform_el_init(el))) + return platform_res; return 0; } -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; @@ -35,10 +23,10 @@ void owd_eventloop_cleanup(struct owd_eventloop *el) { INTRUSIVE_LIST_FOR_EACH_NO_REMOVE(li, &el->event_list) { e = CONTAINER_OF(li, struct owd_event, list); - event_cleanup(el, e); + owd_platform_el_event_cleanup(el, e); } - close(el->kqueue_fd); + owd_platform_el_cleanup(el); } int owd_eventloop_wait( @@ -46,44 +34,16 @@ int owd_eventloop_wait( 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; + return owd_platform_el_wait(el, id_out, timeout); } int owd_eventloop_clear(struct owd_eventloop *el, struct owd_event *e) { - // TODO: read timerfd on linux - return 0; + return owd_platform_el_event_clear(el, e); } 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); + owd_platform_el_event_remove(el, e); + owd_platform_el_event_cleanup(el, e); } int owd_eventloop_add_timer( @@ -92,30 +52,24 @@ int owd_eventloop_add_timer( 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; + int res; - e->id.obj = ident; + if ((res = owd_platform_el_add_timer(el, e, millis, oneshot))) + return res; e->id.source = OWD_EVENT_SOURCE_TIMER; - e->kqueue_ident = kev.ident; - e->kqueue_filter = kev.filter; + return 0; +} + +int owd_eventloop_add_fd( + struct owd_eventloop *el, + struct owd_event *e, + int fd, + uint32_t flags) +{ + int res; - el->kqueue_timer_next++; + if ((res = owd_platform_el_add_fd(el, e, fd, flags))) + return res; + e->id.source = OWD_EVENT_SOURCE_FD; return 0; } diff --git a/src/eventloop_epoll.c b/src/eventloop_epoll.c new file mode 100644 index 0000000..e69de29 diff --git a/src/eventloop_kqueue.c b/src/eventloop_kqueue.c new file mode 100644 index 0000000..4ba7153 --- /dev/null +++ b/src/eventloop_kqueue.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include + +#include "eventloop_platform.h" + +int owd_platform_el_init(struct owd_eventloop *el) { + if ((el->kqueue_fd = kqueue()) < 0) + return -1; + el->kqueue_timer_next = 0; + return 0; +} + +void owd_platform_el_cleanup(struct owd_eventloop *el) { + close(el->kqueue_fd); +} + +void owd_platform_el_event_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); +} + +// TODO: close timerfd on linux +void owd_platform_el_event_cleanup(struct owd_eventloop *el, struct owd_event *e) { + (void)el; + (void)e; +} + +// TODO: read timerfd on linux +int owd_platform_el_event_clear(struct owd_eventloop *el, struct owd_event *e) { + (void)el; + (void)e; + return 0; +} + +int owd_platform_el_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; +} + +static int el_kqueue_add_one( + struct owd_eventloop *el, + struct owd_event *e, + uintptr_t ident, + uint16_t filter, + uint16_t flags, + int64_t data) +{ + struct kevent kev; + + memset(&kev, 0, sizeof(kev)); + kev.ident = ident; + kev.filter = filter; + kev.flags = flags; + kev.data = data; + + if (kevent(el->kqueue_fd, &kev, 1, NULL, 0, NULL)) + return -1; + + e->id.obj = ident; + e->kqueue_ident = ident; + e->kqueue_filter = filter; + + return 0; +} + +int owd_platform_el_add_timer( + struct owd_eventloop *el, + struct owd_event *e, + uint64_t millis, + bool oneshot) +{ + uint16_t kev_flags; + int res; + + kev_flags = 0; + if (oneshot) + kev_flags |= EV_ONESHOT; + + if ((res = el_kqueue_add_one(el, e, el->kqueue_timer_next, EVFILT_TIMER, EV_ADD | kev_flags, millis))) + return res; + + el->kqueue_timer_next++; + + return 0; +} + +int owd_platform_el_add_fd( + struct owd_eventloop *el, + struct owd_event *e, + int fd, + uint32_t flags) +{ + // TODO + return 0; +}