From b915f38dcaee15de2cc66bce69745c88249f8712 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Tue, 8 Mar 2016 21:53:57 -0800 Subject: [PATCH] Switch out custom wakeup system for timerfd. --- adsbus/outgoing.c | 2 +- adsbus/peer.c | 5 +-- adsbus/wakeup.c | 92 ++++++++++++++++++++--------------------------- adsbus/wakeup.h | 2 -- 4 files changed, 41 insertions(+), 60 deletions(-) diff --git a/adsbus/outgoing.c b/adsbus/outgoing.c index 2df996a..fb1124b 100644 --- a/adsbus/outgoing.c +++ b/adsbus/outgoing.c @@ -111,7 +111,7 @@ static void outgoing_connect_result(struct outgoing *outgoing, int result) { default: LOG(outgoing->id, "Can't connect to %s/%s: %s", hbuf, sbuf, strerror(result)); - peer_close(&outgoing->peer); + assert(!close(outgoing->peer.fd)); outgoing->addr = outgoing->addr->ai_next; // Tail recursion :/ outgoing_connect_next(outgoing); diff --git a/adsbus/peer.c b/adsbus/peer.c index f1aa29a..92a2785 100644 --- a/adsbus/peer.c +++ b/adsbus/peer.c @@ -10,7 +10,6 @@ #include "log.h" #include "server.h" -#include "wakeup.h" #include "peer.h" @@ -118,7 +117,7 @@ void peer_loop() { } #define MAX_EVENTS 10 struct epoll_event events[MAX_EVENTS]; - int delay = list_is_empty(&peer_always_trigger_head) ? wakeup_get_delay() : 0; + int delay = list_is_empty(&peer_always_trigger_head) ? -1 : 0; int nfds = epoll_wait(peer_epoll_fd, events, MAX_EVENTS, delay); if (nfds == -1 && errno == EINTR) { continue; @@ -136,7 +135,5 @@ void peer_loop() { peer_call(iter); } } - - wakeup_dispatch(); } } diff --git a/adsbus/wakeup.c b/adsbus/wakeup.c index 5360a27..8aff73c 100644 --- a/adsbus/wakeup.c +++ b/adsbus/wakeup.c @@ -1,83 +1,69 @@ #include #include #include -#include +#include +#include #include "peer.h" #include "rand.h" #include "wakeup.h" -struct wakeup_entry { - int fd; - uint64_t absolute_time_ms; - struct peer *peer; +struct wakeup { + struct peer peer; + struct peer *inner_peer; struct list_head wakeup_list; }; static struct list_head wakeup_head = LIST_HEAD_INIT(wakeup_head); -static uint64_t wakeup_get_time_ms() { - struct timespec tp; - assert(!clock_gettime(CLOCK_MONOTONIC_COARSE, &tp)); -#define MS_PER_S UINT64_C(1000) -#define NS_PER_MS UINT64_C(1000000) - assert(tp.tv_sec >= 0); - assert(tp.tv_nsec >= 0); - return ((uint64_t) tp.tv_sec * MS_PER_S) + ((uint64_t) tp.tv_nsec / NS_PER_MS); +static void wakeup_handler(struct peer *peer) { + struct wakeup *wakeup = container_of(peer, struct wakeup, peer); + + uint64_t events; + assert(read(wakeup->peer.fd, &events, sizeof(events)) == sizeof(events)); + assert(events == 1); + + peer_close(&wakeup->peer); + peer_call(wakeup->inner_peer); + list_del(&wakeup->wakeup_list); + free(wakeup); } void wakeup_init() { } void wakeup_cleanup() { - struct wakeup_entry *iter, *next; + struct wakeup *iter, *next; list_for_each_entry_safe(iter, next, &wakeup_head, wakeup_list) { free(iter); } } -int wakeup_get_delay() { - if (list_is_empty(&wakeup_head)) { - return -1; - } - uint64_t now = wakeup_get_time_ms(); - struct wakeup_entry *next_to_fire = list_entry(wakeup_head.next, struct wakeup_entry, wakeup_list); - if (next_to_fire->absolute_time_ms > now) { - uint64_t delta = next_to_fire->absolute_time_ms - now; - assert(delta < INT_MAX); - return (int) delta; - } else { - return 0; - } -} - -void wakeup_dispatch() { - uint64_t now = wakeup_get_time_ms(); - struct wakeup_entry *iter, *next; - list_for_each_entry_safe(iter, next, &wakeup_head, wakeup_list) { - if (iter->absolute_time_ms > now) { - break; - } - peer_call(iter->peer); - list_del(&iter->wakeup_list); - free(iter); - } -} - void wakeup_add(struct peer *peer, uint32_t delay_ms) { - struct wakeup_entry *entry = malloc(sizeof(*entry)); - entry->absolute_time_ms = wakeup_get_time_ms() + delay_ms; - entry->peer = peer; + struct wakeup *wakeup = malloc(sizeof(*wakeup)); + wakeup->inner_peer = peer; + list_add(&wakeup->wakeup_list, &wakeup_head); - struct wakeup_entry *iter, *next; - list_for_each_entry_safe(iter, next, &wakeup_head, wakeup_list) { - if (iter->absolute_time_ms > entry->absolute_time_ms) { - list_add(&entry->wakeup_list, &iter->wakeup_list); - return; - } - } - list_add(&entry->wakeup_list, &wakeup_head); + wakeup->peer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + assert(wakeup->peer.fd >= 0); + +#define MS_PER_S UINT64_C(1000) +#define NS_PER_MS UINT64_C(1000000) + const struct itimerspec ts = { + .it_interval = { + .tv_sec = 0, + .tv_nsec = 0, + }, + .it_value = { + .tv_sec = delay_ms / MS_PER_S, + .tv_nsec = (delay_ms % MS_PER_S) * NS_PER_MS, + }, + }; + assert(!timerfd_settime(wakeup->peer.fd, 0, &ts, NULL)); + + wakeup->peer.event_handler = wakeup_handler; + peer_epoll_add(&wakeup->peer, EPOLLIN); } #define RETRY_MIN_MS 2000 diff --git a/adsbus/wakeup.h b/adsbus/wakeup.h index 77ffb3b..c11f7e3 100644 --- a/adsbus/wakeup.h +++ b/adsbus/wakeup.h @@ -6,7 +6,5 @@ struct peer; void wakeup_init(void); void wakeup_cleanup(void); -int wakeup_get_delay(void); -void wakeup_dispatch(void); void wakeup_add(struct peer *, uint32_t); uint32_t wakeup_get_retry_delay_ms(uint32_t);