rework timers so they fire more predictably.

this change also stops python coroutines from waking up very
late after their timeout has expired.

in filerefs, don't prime the timer until we actually have something
to expire, and kill the timer when the last ref drops.
This commit is contained in:
Joris Vink 2019-03-21 10:17:08 +01:00
parent ce012e7bd5
commit 8b0279879a
7 changed files with 77 additions and 56 deletions

View File

@ -75,6 +75,7 @@ extern int daemon(int, int);
#define KORE_TLS_VERSION_1_2 1
#define KORE_TLS_VERSION_BOTH 2
#define KORE_WAIT_INFINITE (u_int64_t)-1
#define KORE_RESEED_TIME (1800 * 1000)
#define errno_s strerror(errno)
@ -624,7 +625,8 @@ struct kore_auth *kore_auth_lookup(const char *);
#endif
void kore_timer_init(void);
u_int64_t kore_timer_run(u_int64_t);
void kore_timer_run(u_int64_t);
u_int64_t kore_timer_next_run(u_int64_t);
void kore_timer_remove(struct kore_timer *);
struct kore_timer *kore_timer_add(void (*cb)(void *, u_int64_t),
u_int64_t, void *, int);

View File

@ -119,12 +119,18 @@ kore_platform_event_wait(u_int64_t timer)
{
u_int32_t r;
struct kore_event *evt;
struct timespec timeo;
int n, i;
struct timespec timeo, *ts;
timeo.tv_sec = timer / 1000;
timeo.tv_nsec = (timer % 1000) * 1000000;
n = kevent(kfd, NULL, 0, events, event_count, &timeo);
if (timer == KORE_WAIT_INFINITE) {
ts = NULL;
} else {
timeo.tv_sec = timer / 1000;
timeo.tv_nsec = (timer % 1000) * 1000000;
ts = &timeo;
}
n = kevent(kfd, NULL, 0, events, event_count, ts);
if (n == -1) {
if (errno == EINTR)
return;

View File

@ -28,19 +28,20 @@
/* cached filerefs expire after 30 seconds of inactivity. */
#define FILEREF_EXPIRATION (1000 * 30)
static void fileref_timer_prime(void);
static void fileref_drop(struct kore_fileref *);
static void fileref_soft_remove(struct kore_fileref *);
static void fileref_expiration_check(void *, u_int64_t);
static TAILQ_HEAD(, kore_fileref) refs;
static struct kore_pool ref_pool;
static struct kore_timer *ref_timer = NULL;
void
kore_fileref_init(void)
{
TAILQ_INIT(&refs);
kore_pool_init(&ref_pool, "ref_pool", sizeof(struct kore_fileref), 100);
kore_timer_add(fileref_expiration_check, 10000, NULL, 0);
}
struct kore_fileref *
@ -48,6 +49,8 @@ kore_fileref_create(const char *path, int fd, off_t size, struct timespec *ts)
{
struct kore_fileref *ref;
fileref_timer_prime();
if ((ref = kore_fileref_get(path)) != NULL)
return (ref);
@ -151,6 +154,15 @@ kore_fileref_release(struct kore_fileref *ref)
}
}
static void
fileref_timer_prime(void)
{
if (ref_timer != NULL)
return;
ref_timer = kore_timer_add(fileref_expiration_check, 10000, NULL, 0);
}
static void
fileref_soft_remove(struct kore_fileref *ref)
{
@ -173,6 +185,7 @@ fileref_expiration_check(void *arg, u_int64_t now)
{
struct kore_fileref *ref, *next;
printf("ref timer run\n");
for (ref = TAILQ_FIRST(&refs); ref != NULL; ref = next) {
next = TAILQ_NEXT(ref, list);
@ -188,6 +201,12 @@ fileref_expiration_check(void *arg, u_int64_t now)
fileref_drop(ref);
}
if (TAILQ_EMPTY(&refs)) {
/* remove the timer. */
ref_timer->flags |= KORE_TIMER_ONESHOT;
ref_timer = NULL;
}
}
static void

View File

@ -598,7 +598,7 @@ kore_server_start(int argc, char *argv[])
u_int32_t tmp;
int quit;
struct kore_runtime_call *rcall;
u_int64_t now, netwait, timerwait;
u_int64_t netwait;
if (foreground == 0) {
if (daemon(1, 0) == -1)
@ -657,7 +657,7 @@ kore_server_start(int argc, char *argv[])
kore_timer_init();
#if !defined(KORE_NO_HTTP)
kore_timer_add(kore_accesslog_run, 10, NULL, 0);
kore_timer_add(kore_accesslog_run, 100, NULL, 0);
#endif
while (quit != 1) {
@ -686,20 +686,14 @@ kore_server_start(int argc, char *argv[])
sig_recv = 0;
}
netwait = 100;
now = kore_time_ms();
timerwait = kore_timer_run(now);
if (timerwait < netwait)
netwait = timerwait;
netwait = kore_timer_next_run(kore_time_ms());
kore_platform_event_wait(netwait);
kore_connection_prune(KORE_CONNECTION_PRUNE_DISCONNECT);
kore_timer_run(kore_time_ms());
}
now = kore_time_ms();
#if !defined(KORE_NO_HTTP)
kore_accesslog_gather(NULL, now, 1);
kore_accesslog_gather(NULL, kore_time_ms(), 1);
#endif
kore_platform_event_cleanup();

View File

@ -97,9 +97,14 @@ kore_platform_event_wait(u_int64_t timer)
{
u_int32_t r;
struct kore_event *evt;
int n, i;
int n, i, timeo;
n = epoll_wait(efd, events, event_count, timer);
if (timer == KORE_WAIT_INFINITE)
timeo = -1;
else
timeo = timer;
n = epoll_wait(efd, events, event_count, timeo);
if (n == -1) {
if (errno == EINTR)
return;

View File

@ -61,18 +61,32 @@ kore_timer_remove(struct kore_timer *timer)
}
u_int64_t
kore_timer_next_run(u_int64_t now)
{
struct kore_timer *timer;
if ((timer = TAILQ_FIRST(&kore_timers)) != NULL) {
if (timer->nextrun > now)
return (timer->nextrun - now);
return (0);
}
return (KORE_WAIT_INFINITE);
}
void
kore_timer_run(u_int64_t now)
{
struct kore_timer *timer, *t;
u_int64_t next_timer;
struct kore_timer *timer, *t, *prev;
next_timer = 1000;
prev = NULL;
while ((timer = TAILQ_FIRST(&kore_timers)) != NULL) {
if (timer->nextrun > now) {
next_timer = timer->nextrun - now;
if (timer == prev)
break;
if (timer->nextrun > now)
break;
}
TAILQ_REMOVE(&kore_timers, timer, list);
timer->cb(timer->arg, now);
@ -80,6 +94,7 @@ kore_timer_run(u_int64_t now)
if (timer->flags & KORE_TIMER_ONESHOT) {
kore_free(timer);
} else {
prev = timer;
timer->nextrun = now + timer->interval;
TAILQ_FOREACH(t, &kore_timers, list) {
if (t->nextrun > timer->nextrun) {
@ -92,9 +107,4 @@ kore_timer_run(u_int64_t now)
TAILQ_INSERT_TAIL(&kore_timers, timer, list);
}
}
if (next_timer > 1)
next_timer -= 1;
return (next_timer);
}

View File

@ -73,8 +73,8 @@ struct wlock {
static int worker_trylock(void);
static void worker_unlock(void);
static inline int worker_acceptlock_obtain(u_int64_t);
static inline int worker_acceptlock_release(u_int64_t);
static inline int worker_acceptlock_obtain(void);
static inline int worker_acceptlock_release(void);
#if !defined(KORE_NO_TLS)
static void worker_entropy_recv(struct kore_msg *, const void *);
@ -308,8 +308,7 @@ kore_worker_entry(struct kore_worker *kw)
struct kore_runtime_call *rcall;
char buf[16];
int quit, had_lock;
u_int64_t now, next_prune;
u_int64_t timerwait, netwait;
u_int64_t netwait, now, next_prune;
#if !defined(KORE_NO_TLS)
u_int64_t last_seed;
#endif
@ -396,7 +395,6 @@ kore_worker_entry(struct kore_worker *kw)
worker->restarted = 0;
for (;;) {
netwait = 100;
now = kore_time_ms();
#if !defined(KORE_NO_TLS)
@ -408,7 +406,7 @@ kore_worker_entry(struct kore_worker *kw)
#endif
if (!worker->has_lock && next_lock <= now) {
if (worker_acceptlock_obtain(now)) {
if (worker_acceptlock_obtain()) {
if (had_lock == 0) {
kore_platform_enable_accept();
had_lock = 1;
@ -418,25 +416,12 @@ kore_worker_entry(struct kore_worker *kw)
}
}
if (!worker->has_lock) {
if (worker_active_connections > 0) {
if (next_lock > now)
netwait = next_lock - now;
} else {
netwait = 10;
}
}
timerwait = kore_timer_run(now);
if (timerwait < netwait)
netwait = timerwait;
netwait = kore_timer_next_run(now);
kore_platform_event_wait(netwait);
now = kore_time_ms();
if (worker->has_lock) {
if (netwait > 10)
now = kore_time_ms();
if (worker_acceptlock_release(now))
if (worker_acceptlock_release())
next_lock = now + WORKER_LOCK_TIMEOUT;
}
@ -472,6 +457,8 @@ kore_worker_entry(struct kore_worker *kw)
if (quit)
break;
kore_timer_run(now);
#if !defined(KORE_NO_HTTP)
http_process();
#endif
@ -618,7 +605,7 @@ kore_worker_make_busy(void)
}
static inline int
worker_acceptlock_release(u_int64_t now)
worker_acceptlock_release(void)
{
if (worker_count == WORKER_SOLO_COUNT || worker_no_lock == 1)
return (0);
@ -637,7 +624,6 @@ worker_acceptlock_release(u_int64_t now)
#if defined(WORKER_DEBUG)
kore_log(LOG_DEBUG, "worker busy, releasing lock");
kore_log(LOG_DEBUG, "had lock for %lu ms", now - worker->time_locked);
#endif
worker_unlock();
@ -647,7 +633,7 @@ worker_acceptlock_release(u_int64_t now)
}
static inline int
worker_acceptlock_obtain(u_int64_t now)
worker_acceptlock_obtain(void)
{
int r;
@ -671,7 +657,6 @@ worker_acceptlock_obtain(u_int64_t now)
if (worker_trylock()) {
r = 1;
worker->has_lock = 1;
worker->time_locked = now;
#if defined(WORKER_DEBUG)
kore_log(LOG_DEBUG, "got lock");
#endif