2016-02-18 09:33:32 -08:00
|
|
|
#include <assert.h>
|
2016-02-25 23:37:37 -08:00
|
|
|
#include <stdlib.h>
|
2016-03-08 21:53:57 -08:00
|
|
|
#include <sys/timerfd.h>
|
|
|
|
|
#include <unistd.h>
|
2016-02-18 09:33:32 -08:00
|
|
|
|
2016-02-22 16:49:43 -08:00
|
|
|
#include "peer.h"
|
2016-02-22 16:33:00 -08:00
|
|
|
#include "rand.h"
|
2016-02-18 09:33:32 -08:00
|
|
|
|
|
|
|
|
#include "wakeup.h"
|
|
|
|
|
|
2016-03-08 21:53:57 -08:00
|
|
|
struct wakeup {
|
|
|
|
|
struct peer peer;
|
|
|
|
|
struct peer *inner_peer;
|
2016-03-02 19:10:31 -08:00
|
|
|
struct list_head wakeup_list;
|
2016-02-21 15:51:38 -08:00
|
|
|
};
|
|
|
|
|
|
2016-03-02 19:10:31 -08:00
|
|
|
static struct list_head wakeup_head = LIST_HEAD_INIT(wakeup_head);
|
2016-02-20 23:56:40 -08:00
|
|
|
|
2016-03-08 22:42:15 -08:00
|
|
|
static void wakeup_del(struct wakeup *wakeup) {
|
|
|
|
|
peer_close(&wakeup->peer);
|
|
|
|
|
list_del(&wakeup->wakeup_list);
|
|
|
|
|
free(wakeup);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 21:53:57 -08:00
|
|
|
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_call(wakeup->inner_peer);
|
2016-03-08 22:42:15 -08:00
|
|
|
wakeup_del(wakeup);
|
2016-02-21 15:51:38 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 14:37:00 -08:00
|
|
|
void wakeup_init() {
|
2016-02-21 15:51:38 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-22 14:37:00 -08:00
|
|
|
void wakeup_cleanup() {
|
2016-03-08 21:53:57 -08:00
|
|
|
struct wakeup *iter, *next;
|
2016-03-02 19:10:31 -08:00
|
|
|
list_for_each_entry_safe(iter, next, &wakeup_head, wakeup_list) {
|
2016-03-08 22:42:15 -08:00
|
|
|
wakeup_del(iter);
|
2016-02-20 23:56:40 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 21:53:57 -08:00
|
|
|
void wakeup_add(struct peer *peer, uint32_t delay_ms) {
|
|
|
|
|
struct wakeup *wakeup = malloc(sizeof(*wakeup));
|
|
|
|
|
wakeup->inner_peer = peer;
|
|
|
|
|
list_add(&wakeup->wakeup_list, &wakeup_head);
|
2016-02-20 23:56:40 -08:00
|
|
|
|
2016-03-08 21:53:57 -08:00
|
|
|
wakeup->peer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
|
|
|
|
assert(wakeup->peer.fd >= 0);
|
2016-02-18 09:33:32 -08:00
|
|
|
|
2016-03-08 21:53:57 -08:00
|
|
|
#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));
|
2016-02-21 15:51:38 -08:00
|
|
|
|
2016-03-08 21:53:57 -08:00
|
|
|
wakeup->peer.event_handler = wakeup_handler;
|
|
|
|
|
peer_epoll_add(&wakeup->peer, EPOLLIN);
|
2016-02-18 09:33:32 -08:00
|
|
|
}
|
2016-02-22 16:33:00 -08:00
|
|
|
|
|
|
|
|
#define RETRY_MIN_MS 2000
|
|
|
|
|
#define RETRY_MAX_MS 60000
|
|
|
|
|
uint32_t wakeup_get_retry_delay_ms(uint32_t attempt) {
|
|
|
|
|
uint32_t max_delay = RETRY_MIN_MS * (1 << attempt);
|
|
|
|
|
max_delay = max_delay > RETRY_MAX_MS ? RETRY_MAX_MS : max_delay;
|
|
|
|
|
|
|
|
|
|
uint32_t jitter;
|
|
|
|
|
rand_fill(&jitter, sizeof(jitter));
|
|
|
|
|
|
|
|
|
|
return jitter % max_delay;
|
|
|
|
|
}
|