summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/birdlib.h4
-rw-r--r--lib/coro.h26
-rw-r--r--lib/lists.c2
-rw-r--r--lib/locking.h44
-rw-r--r--lib/timer.c76
-rw-r--r--lib/timer.h15
6 files changed, 97 insertions, 70 deletions
diff --git a/lib/birdlib.h b/lib/birdlib.h
index bdf69309..dbc754d4 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -93,10 +93,6 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define STATIC_ASSERT(EXP) _Static_assert(EXP, #EXP)
#define STATIC_ASSERT_MSG(EXP,MSG) _Static_assert(EXP, MSG)
-#ifndef HAVE_THREAD_LOCAL
-#define _Thread_local
-#endif
-
/* Microsecond time */
typedef s64 btime;
diff --git a/lib/coro.h b/lib/coro.h
new file mode 100644
index 00000000..51712b36
--- /dev/null
+++ b/lib/coro.h
@@ -0,0 +1,26 @@
+/*
+ * BIRD Coroutines
+ *
+ * (c) 2017 Martin Mares <mj@ucw.cz>
+ * (c) 2020 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_CORO_H_
+#define _BIRD_CORO_H_
+
+#include "lib/resource.h"
+
+/* A completely opaque coroutine handle. */
+struct coroutine;
+
+/* Coroutines are independent threads bound to pools.
+ * You request a coroutine by calling coro_run().
+ * It is forbidden to free a running coroutine from outside.
+ * The running coroutine must free itself by rfree() before returning.
+ */
+struct coroutine *coro_run(pool *, void (*entry)(void *), void *data);
+
+
+#endif
diff --git a/lib/lists.c b/lib/lists.c
index 1aa58085..8f95c7c2 100644
--- a/lib/lists.c
+++ b/lib/lists.c
@@ -26,7 +26,7 @@
#define _BIRD_LISTS_C_
-#include "nest/bird.h"
+#include "lib/birdlib.h"
#include "lib/lists.h"
LIST_INLINE int
diff --git a/lib/locking.h b/lib/locking.h
new file mode 100644
index 00000000..eef60154
--- /dev/null
+++ b/lib/locking.h
@@ -0,0 +1,44 @@
+/*
+ * BIRD Library -- Locking
+ *
+ * (c) 2020--2021 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_LOCKING_H_
+#define _BIRD_LOCKING_H_
+
+struct domain_generic;
+
+/* Here define the global lock order; first to last. */
+struct lock_order {
+ struct domain_generic *the_bird;
+};
+
+extern _Thread_local struct lock_order locking_stack;
+extern _Thread_local struct domain_generic **last_locked;
+
+#define DOMAIN(type) struct domain__##type
+#define DEFINE_DOMAIN(type) DOMAIN(type) { struct domain_generic *type; }
+
+#define DOMAIN_NEW(type, name) (DOMAIN(type)) { .type = domain_new(name, OFFSETOF(struct lock_order, type)) }
+struct domain_generic *domain_new(const char *name, uint order);
+
+#define DOMAIN_NULL(type) (DOMAIN(type)) {}
+
+#define LOCK_DOMAIN(type, d) do_lock(((d).type), &(locking_stack.type))
+#define UNLOCK_DOMAIN(type, d) do_unlock(((d).type), &(locking_stack.type))
+
+/* Internal for locking */
+void do_lock(struct domain_generic *dg, struct domain_generic **lsp);
+void do_unlock(struct domain_generic *dg, struct domain_generic **lsp);
+
+/* Use with care. To be removed in near future. */
+DEFINE_DOMAIN(the_bird);
+extern DOMAIN(the_bird) the_bird_domain;
+
+#define the_bird_lock() LOCK_DOMAIN(the_bird, the_bird_domain)
+#define the_bird_unlock() UNLOCK_DOMAIN(the_bird, the_bird_domain)
+
+#endif
diff --git a/lib/timer.c b/lib/timer.c
index c47e0bbc..295eeaef 100644
--- a/lib/timer.c
+++ b/lib/timer.c
@@ -32,6 +32,7 @@
#include "nest/bird.h"
+#include "lib/coro.h"
#include "lib/heap.h"
#include "lib/resource.h"
#include "lib/timer.h"
@@ -40,53 +41,16 @@
struct timeloop main_timeloop;
-#ifdef USE_PTHREADS
-
#include <pthread.h>
/* Data accessed and modified from proto/bfd/io.c */
-pthread_key_t current_time_key;
-
-static inline struct timeloop *
-timeloop_current(void)
-{
- return pthread_getspecific(current_time_key);
-}
+_Thread_local struct timeloop *local_timeloop;
-static inline void
-timeloop_init_current(void)
-{
- pthread_key_create(&current_time_key, NULL);
- pthread_setspecific(current_time_key, &main_timeloop);
-}
+_Atomic btime last_time;
+_Atomic btime real_time;
void wakeup_kick_current(void);
-#else
-
-/* Just use main timelooop */
-static inline struct timeloop * timeloop_current(void) { return &main_timeloop; }
-static inline void timeloop_init_current(void) { }
-
-#endif
-
-btime
-current_time(void)
-{
- return timeloop_current()->last_time;
-}
-
-btime
-current_real_time(void)
-{
- struct timeloop *loop = timeloop_current();
-
- if (!loop->real_time)
- times_update_real_time(loop);
-
- return loop->real_time;
-}
-
#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
@@ -138,30 +102,29 @@ tm_new(pool *p)
void
tm_set(timer *t, btime when)
{
- struct timeloop *loop = timeloop_current();
- uint tc = timers_count(loop);
+ uint tc = timers_count(local_timeloop);
if (!t->expires)
{
t->index = ++tc;
t->expires = when;
- BUFFER_PUSH(loop->timers) = t;
- HEAP_INSERT(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP);
+ BUFFER_PUSH(local_timeloop->timers) = t;
+ HEAP_INSERT(local_timeloop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP);
}
else if (t->expires < when)
{
t->expires = when;
- HEAP_INCREASE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
+ HEAP_INCREASE(local_timeloop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
}
else if (t->expires > when)
{
t->expires = when;
- HEAP_DECREASE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
+ HEAP_DECREASE(local_timeloop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
}
#ifdef CONFIG_BFD
/* Hack to notify BFD loops */
- if ((loop != &main_timeloop) && (t->index == 1))
+ if ((local_timeloop != &main_timeloop) && (t->index == 1))
wakeup_kick_current();
#endif
}
@@ -178,11 +141,10 @@ tm_stop(timer *t)
if (!t->expires)
return;
- struct timeloop *loop = timeloop_current();
- uint tc = timers_count(loop);
+ uint tc = timers_count(local_timeloop);
- HEAP_DELETE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
- BUFFER_POP(loop->timers);
+ HEAP_DELETE(local_timeloop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
+ BUFFER_POP(local_timeloop->timers);
t->index = -1;
t->expires = 0;
@@ -191,8 +153,6 @@ tm_stop(timer *t)
void
timers_init(struct timeloop *loop, pool *p)
{
- times_init(loop);
-
BUFFER_INIT(loop->timers, p, 4);
BUFFER_PUSH(loop->timers) = NULL;
}
@@ -205,8 +165,8 @@ timers_fire(struct timeloop *loop)
btime base_time;
timer *t;
- times_update(loop);
- base_time = loop->last_time;
+ times_update();
+ base_time = current_time();
while (t = timers_first(loop))
{
@@ -217,8 +177,8 @@ timers_fire(struct timeloop *loop)
{
btime when = t->expires + t->recurrent;
- if (when <= loop->last_time)
- when = loop->last_time + t->recurrent;
+ if (when <= base_time)
+ when = base_time + t->recurrent;
if (t->randomize)
when += random() % (t->randomize + 1);
@@ -241,7 +201,7 @@ void
timer_init(void)
{
timers_init(&main_timeloop, &root_pool);
- timeloop_init_current();
+ local_timeloop = &main_timeloop;
}
diff --git a/lib/timer.h b/lib/timer.h
index c5ea430c..b201b8c8 100644
--- a/lib/timer.h
+++ b/lib/timer.h
@@ -14,6 +14,10 @@
#include "lib/buffer.h"
#include "lib/resource.h"
+#include <stdatomic.h>
+
+extern _Atomic btime last_time;
+extern _Atomic btime real_time;
typedef struct timer
{
@@ -31,8 +35,6 @@ typedef struct timer
struct timeloop
{
BUFFER_(timer *) timers;
- btime last_time;
- btime real_time;
};
static inline uint timers_count(struct timeloop *loop)
@@ -42,9 +44,10 @@ static inline timer *timers_first(struct timeloop *loop)
{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
extern struct timeloop main_timeloop;
+extern _Thread_local struct timeloop *local_timeloop;
-btime current_time(void);
-btime current_real_time(void);
+#define current_time() atomic_load_explicit(&last_time, memory_order_acquire)
+#define current_real_time() atomic_load_explicit(&real_time, memory_order_acquire)
//#define now (current_time() TO_S)
//#define now_real (current_real_time() TO_S)
@@ -94,9 +97,7 @@ tm_start_max(timer *t, btime after)
}
/* In sysdep code */
-void times_init(struct timeloop *loop);
-void times_update(struct timeloop *loop);
-void times_update_real_time(struct timeloop *loop);
+void times_update(void);
/* For I/O loop */
void timers_init(struct timeloop *loop, pool *p);