]> git.ozlabs.org Git - ccan/blobdiff - ccan/timer/timer.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / timer / timer.c
index 8d220a6a8c6f44893f12c76e95090c6f0998321d..ef6b27742679f4cbccc006d1db81d4cc83ec09fa 100644 (file)
@@ -2,7 +2,6 @@
 #include <ccan/timer/timer.h>
 #include <ccan/array_size/array_size.h>
 #include <ccan/ilog/ilog.h>
-#include <ccan/likely/likely.h>
 #include <stdlib.h>
 #include <stdio.h>
 
@@ -12,15 +11,39 @@ struct timer_level {
        struct list_head list[PER_LEVEL];
 };
 
-static uint64_t time_to_grains(struct timeabs t)
+static void *timer_default_alloc(struct timers *timers, size_t len)
+{
+       return malloc(len);
+}
+
+static void timer_default_free(struct timers *timers, void *p)
+{
+       free(p);
+}
+
+static void *(*timer_alloc)(struct timers *, size_t) = timer_default_alloc;
+static void (*timer_free)(struct timers *, void *) = timer_default_free;
+
+void timers_set_allocator(void *(*alloc)(struct timers *, size_t len),
+                         void (*free)(struct timers *, void *p))
+{
+       if (!alloc)
+               alloc = timer_default_alloc;
+       if (!free)
+               free = timer_default_free;
+       timer_alloc = alloc;
+       timer_free = free;
+}
+
+static uint64_t time_to_grains(struct timemono t)
 {
        return t.ts.tv_sec * ((uint64_t)1000000000 / TIMER_GRANULARITY)
                + (t.ts.tv_nsec / TIMER_GRANULARITY);
 }
 
-static struct timeabs grains_to_time(uint64_t grains)
+static struct timemono grains_to_time(uint64_t grains)
 {
-       struct timeabs t;
+       struct timemono t;
 
        t.ts.tv_sec = grains / (1000000000 / TIMER_GRANULARITY);
        t.ts.tv_nsec = (grains % (1000000000 / TIMER_GRANULARITY))
@@ -28,7 +51,7 @@ static struct timeabs grains_to_time(uint64_t grains)
        return t;
 }
 
-void timers_init(struct timers *timers, struct timeabs start)
+void timers_init(struct timers *timers, struct timemono start)
 {
        unsigned int i;
 
@@ -74,12 +97,28 @@ void timer_init(struct timer *t)
        list_node_init(&t->list);
 }
 
-static bool list_node_initted(const struct list_node *n)
+static inline bool list_node_initted(const struct list_node *n)
 {
        return n->prev == n;
 }
 
-void timer_add(struct timers *timers, struct timer *t, struct timeabs when)
+void timer_addrel(struct timers *timers, struct timer *t, struct timerel rel)
+{
+       assert(list_node_initted(&t->list));
+
+       t->time = time_to_grains(timemono_add(time_mono(), rel));
+
+       /* Added in the past?  Treat it as imminent. */
+       if (t->time < timers->base)
+               t->time = timers->base;
+
+       if (t->time < timers->first)
+               timers->first = t->time;
+
+       timer_add_raw(timers, t);
+}
+
+void timer_addmono(struct timers *timers, struct timer *t, struct timemono when)
 {
        assert(list_node_initted(&t->list));
 
@@ -95,7 +134,7 @@ void timer_add(struct timers *timers, struct timer *t, struct timeabs when)
 }
 
 /* FIXME: inline */
-void timer_del(struct timers *timers, struct timer *t)
+void timer_del(struct timers *timers UNNEEDED, struct timer *t)
 {
        list_del_init(&t->list);
 }
@@ -121,7 +160,7 @@ static void add_level(struct timers *timers, unsigned int level)
        unsigned int i;
        struct list_head from_far;
 
-       l = malloc(sizeof(*l));
+       l = timer_alloc(timers, sizeof(*l));
        if (!l)
                return;
 
@@ -241,7 +280,7 @@ static bool update_first(struct timers *timers)
        return true;
 }
 
-bool timer_earliest(struct timers *timers, struct timeabs *first)
+bool timer_earliest(struct timers *timers, struct timemono *first)
 {
        if (!update_first(timers))
                return false;
@@ -298,13 +337,17 @@ static void timer_fast_forward(struct timers *timers, uint64_t time)
 }
 
 /* Returns an expired timer. */
-struct timer *timers_expire(struct timers *timers, struct timeabs expire)
+struct timer *timers_expire(struct timers *timers, struct timemono expire)
 {
        uint64_t now = time_to_grains(expire);
        unsigned int off;
        struct timer *t;
 
-       assert(now >= timers->base);
+       /* This can happen without TIME_HAVE_MONOTONIC, but I also have
+        * a report of OpenBSD 6.8 under virtualbox doing this. */
+       if (now < timers->base) {
+               return NULL;
+       }
 
        if (!timers->level[0]) {
                if (list_empty(&timers->far))
@@ -502,5 +545,5 @@ void timers_cleanup(struct timers *timers)
        unsigned int l;
 
        for (l = 0; l < ARRAY_SIZE(timers->level); l++)
-               free(timers->level[l]);
+               timer_free(timers, timers->level[l]);
 }