From def4cf26f4153a674820b0b28c60c9f09678d88b Mon Sep 17 00:00:00 2001 From: Stefan Reif Date: Mon, 1 Jul 2019 12:53:10 +0200 Subject: [PATCH] timer --- prrt/proto/timer.c | 64 ++++++++++++++++++++++++++++++++++++++-------- prrt/proto/timer.h | 4 +++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/prrt/proto/timer.c b/prrt/proto/timer.c index e3f891c1..4e88f4ef 100644 --- a/prrt/proto/timer.c +++ b/prrt/proto/timer.c @@ -133,7 +133,7 @@ struct prrtTimer { atomic_int wait; _Atomic(TimerNode *) new; _Atomic(TimerNode *) old; - _Atomic(TimerNode *) del; + _Atomic(TimerNode *) cur; TimerDateUDiff_t precision; TimerDateUDiff_t lcp; TimerDateUDiff_t osp; @@ -143,7 +143,7 @@ struct prrtTimer { typedef struct prrtTimer Timer; -static bool timer_date_is_due(Timer *self, TimerDate *when, const TimerDate *now) +static bool timer_date_is_due(Timer *self, const TimerDate *when, const TimerDate *now) { // TODO: use self->precision to check whether now and *when are similar enough (void) self; @@ -208,6 +208,8 @@ static void *timer_worker_loop(void *arg) TimerNode *task = atomic_load(&self->new); assert(task != NULL && "task list contains NULL node"); + atomic_store(&self->cur, task); + if (timer_date_is_inf(&task->date)) { if (!atomic_load_explicit(&self->alive, memory_order_acquire)) { if (task == atomic_load(&self->new)) @@ -260,11 +262,9 @@ static void *timer_worker_loop(void *arg) task->done = true; } - atomic_store(&self->del, task); TimerNode *next = atomic_load(&task->next); TimerNode *temp = task; atomic_compare_exchange_strong(&self->new, &temp, next); - atomic_store(&self->del, NULL); if (slept && !learned) { clock_gettime(CLOCK_REALTIME, &td1); @@ -306,7 +306,7 @@ PrrtTimer *PrrtTimer_create(unsigned int core) atomic_store_explicit(&self->wait, 0, memory_order_relaxed); atomic_store_explicit(&self->new, node, memory_order_relaxed); atomic_store_explicit(&self->old, node, memory_order_relaxed); - atomic_store_explicit(&self->del, NULL, memory_order_relaxed); + atomic_store_explicit(&self->cur, node, memory_order_relaxed); self->precision = timer_measure_clock_precision(); for (int i = 0; i < OSP_WINDOW_SIZE; i++) @@ -364,7 +364,7 @@ PrrtTimer *PrrtTimer_create(unsigned int core) int PrrtTimer_submit(PrrtTimer *self, const TimerDate *when, const PrrtTimerTask *what) { - TimerNode *iter, *stop, *next; + TimerNode *iter, *stop, *next, *hold; TimerNode *node = malloc(sizeof(TimerNode)); if (!node) return -1; @@ -380,13 +380,14 @@ int PrrtTimer_submit(PrrtTimer *self, const TimerDate *when, const PrrtTimerTask iter = atomic_load(&self->old); stop = atomic_load(&self->new); - while (iter != stop) { + hold = atomic_load(&self->cur); + while (iter != stop && iter != hold) { next = iter->next; assert(iter->done && "cleanup task that is not marked as done"); free(iter); iter = next; } - atomic_store(&self->old, stop); + atomic_store(&self->old, iter); _Atomic(TimerNode *) *addr = &self->old; while (1) { @@ -407,9 +408,8 @@ int PrrtTimer_submit(PrrtTimer *self, const TimerDate *when, const PrrtTimerTask atomic_store(&node->next, iter); atomic_store(addr, node); - TimerNode *del = atomic_load(&self->del); TimerNode *tail = atomic_load(&self->new); - if (del == tail || timer_date_is_lt(&node->date, &tail->date)) { + if (timer_date_is_lt(&node->date, &tail->date) || (addr == &tail->next && atomic_load(&tail->done))) { atomic_store(&self->new, node); timer_wake_worker(self, false); } @@ -417,6 +417,50 @@ int PrrtTimer_submit(PrrtTimer *self, const TimerDate *when, const PrrtTimerTask return -1; } +static void wake_sleeping_thread(void *arg) +{ + atomic_int *ip = (atomic_int *) arg; + atomic_store_explicit(ip, 1, memory_order_release); + futex((int *) ip, FUTEX_WAKE|FUTEX_PRIVATE_FLAG, 1, NULL, NULL, 0); +} + +void PrrtTimer_sleep_until(PrrtTimer *self, const TimerDate *end) +{ + atomic_int cond; + atomic_store_explicit(&cond, 0, memory_order_release); + + TimerDate now; + TimerDate care = *end; + PrrtTimerTask what; + what.fun = wake_sleeping_thread; + what.arg = &cond; + timer_date_sub(&care, 2*self->osp); + clock_gettime(CLOCK_REALTIME, &now); + if (!timer_date_is_due(self, &care, &now)) { + PrrtTimer_submit(self, &care, &what); + while (!atomic_load(&cond)) { + clock_gettime(CLOCK_REALTIME, &now); + if (!timer_date_is_due(self, &care, &now)) + //futex(&cond, FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG|FUTEX_CLOCK_REALTIME, 1, care, NULL, FUTEX_BITSET_MATCH_ANY); + futex(&cond, FUTEX_WAIT|FUTEX_PRIVATE_FLAG, 0, NULL, NULL, 0); + } + } + + while (1) { + clock_gettime(CLOCK_REALTIME, &now); + if (timer_date_is_due(self, end, &now)) + break; + } +} + +void PrrtTimer_sleep_nanos(PrrtTimer *self, TimerDateUDiff_t nanos) +{ + TimerDate when; + clock_gettime(CLOCK_REALTIME, &when); + timer_date_add(&when, nanos); + PrrtTimer_sleep_until(self, &when); +} + void PrrtTimer_end(PrrtTimer *self) { atomic_store_explicit(&self->alive, false, memory_order_release); diff --git a/prrt/proto/timer.h b/prrt/proto/timer.h index 9bee379a..0c0570cf 100644 --- a/prrt/proto/timer.h +++ b/prrt/proto/timer.h @@ -10,6 +10,7 @@ typedef void *prrtTimerTaskArg; typedef void (*prrtTimerTaskFun)(prrtTimerTaskArg); typedef struct timespec prrtTimerDate; +typedef unsigned long long TimerDateUDiff_t; typedef struct prrtTimerTask { prrtTimerTaskFun fun; @@ -24,4 +25,7 @@ int PrrtTimer_submit(PrrtTimer *timer, const prrtTimerDate *when, const PrrtTime void PrrtTimer_end(PrrtTimer *timer); +void PrrtTimer_sleep_until(PrrtTimer *self, const prrtTimerDate *end); +void PrrtTimer_sleep_nanos(PrrtTimer *self, TimerDateUDiff_t nanos); + #endif // PRRT_TIMER_H -- GitLab