timer: add hook for allocation functions.
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 4 Mar 2019 09:12:57 +0000 (19:42 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 4 Mar 2019 09:12:57 +0000 (19:42 +1030)
malloc and free aren't for everyone.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/timer/test/run-allocator.c [new file with mode: 0644]
ccan/timer/timer.c
ccan/timer/timer.h

diff --git a/ccan/timer/test/run-allocator.c b/ccan/timer/test/run-allocator.c
new file mode 100644 (file)
index 0000000..75e1af0
--- /dev/null
@@ -0,0 +1,62 @@
+#define CCAN_TIMER_DEBUG
+/* Include the C files directly. */
+#include <ccan/timer/timer.c>
+#include <ccan/tap/tap.h>
+
+static void *test_alloc(size_t len, void *arg)
+{
+       (*(size_t *)arg)++;
+       return malloc(len);
+}
+
+static void test_free(const void *p, void *arg)
+{
+       if (p) {
+               (*(size_t *)arg)--;
+               free((void *)p);
+       }
+}
+
+static struct timemono timemono_from_nsec(unsigned long long nsec)
+{
+       struct timemono epoch = { { 0, 0 } };
+       return timemono_add(epoch, time_from_nsec(nsec));
+}
+
+int main(void)
+{
+       struct timers timers;
+       struct timer t[64];
+       size_t num_allocs = 0;
+       const struct timemono epoch = { { 0, 0 } };
+
+       plan_tests(7);
+
+       timers_set_allocator(test_alloc, test_free, &num_allocs);
+       timers_init(&timers, epoch);
+       timer_init(&t[0]);
+
+       timer_addmono(&timers, &t[0],
+                     timemono_from_nsec(TIMER_GRANULARITY << TIMER_LEVEL_BITS));
+       timers_expire(&timers, timemono_from_nsec(1));
+       ok1(num_allocs == 1);
+       timer_del(&timers, &t[0]);
+       ok1(num_allocs == 1);
+       timers_cleanup(&timers);
+       ok1(num_allocs == 0);
+
+       /* Should restore defaults */
+       timers_set_allocator(NULL, NULL, NULL);
+       ok1(timer_alloc == timer_default_alloc);
+       ok1(timer_free == timer_default_free);
+
+       timers_init(&timers, epoch);
+       timer_addmono(&timers, &t[0],
+                     timemono_from_nsec(TIMER_GRANULARITY << TIMER_LEVEL_BITS));
+       ok1(num_allocs == 0);
+       timers_cleanup(&timers);
+       ok1(num_allocs == 0);
+
+       /* This exits depending on whether all tests passed */
+       return exit_status();
+}
index 84d7aa1454a24383fd0aff6e635d3bfe1d073cbc..607415620c6223d9620d70606d851c70da00af74 100644 (file)
@@ -11,6 +11,33 @@ struct timer_level {
        struct list_head list[PER_LEVEL];
 };
 
+static void *timer_default_alloc(size_t len, void *arg)
+{
+       return malloc(len);
+}
+
+static void timer_default_free(const void *p, void *arg)
+{
+       free((void *)p);
+}
+
+static void *(*timer_alloc)(size_t, void *) = timer_default_alloc;
+static void (*timer_free)(const void *, void *) = timer_default_free;
+static void *timer_arg;
+
+void timers_set_allocator(void *(*alloc)(size_t len, void *arg),
+                         void (*free)(const void *p, void *arg),
+                         void *arg)
+{
+       if (!alloc)
+               alloc = timer_default_alloc;
+       if (!free)
+               free = timer_default_free;
+       timer_alloc = alloc;
+       timer_free = free;
+       timer_arg = arg;
+}
+
 static uint64_t time_to_grains(struct timemono t)
 {
        return t.ts.tv_sec * ((uint64_t)1000000000 / TIMER_GRANULARITY)
@@ -139,7 +166,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(sizeof(*l), timer_arg);
        if (!l)
                return;
 
@@ -520,5 +547,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->level[l], timer_arg);
 }
index 5c40a3bbc1c9979251ad5c2b76ca6a0443c5926a..5b193250da58308f63ec98b46d3d15496e1fe049 100644 (file)
@@ -162,6 +162,19 @@ struct timer *timers_expire(struct timers *timers, struct timemono expire);
  */
 struct timers *timers_check(const struct timers *t, const char *abortstr);
 
+/**
+ * timers_set_allocator - set malloc/free functions.
+ * @alloc: allocator to use
+ * @free: unallocator to use (@p is NULL or a return from @alloc)
+ * @arg: argument to pass.
+ *
+ * This replaces the underlying malloc/free with these allocators.
+ * Setting either one to NULL restores the default allocators.
+ */
+void timers_set_allocator(void *(*alloc)(size_t len, void *arg),
+                         void (*free)(const void *p, void *arg),
+                         void *arg);
+
 #ifdef CCAN_TIMER_DEBUG
 #include <stdio.h>