-src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
obj := $(src-o-files)
$(all-daemon)
--- /dev/null
+/*
+ * BIRD -- Deferring calls to the end of the task
+ *
+ * (c) 2024 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "lib/defer.h"
+
+_Thread_local struct deferred local_deferred = {};
+
+static void
+defer_execute(void *_ld)
+{
+ ASSERT_DIE(_ld == &local_deferred);
+
+ /* Run */
+ for (struct deferred_call *call = local_deferred.first; call; call = call->next)
+ call->hook(call);
+
+ /* Cleanup */
+ local_deferred.first = NULL;
+ local_deferred.last = &local_deferred.first;
+
+ lp_flush(local_deferred.lp);
+}
+
+void
+defer_init(linpool *lp)
+{
+ local_deferred = (struct deferred) {
+ .e = {
+ .hook = defer_execute,
+ .data = &local_deferred,
+ },
+ .lp = lp,
+ .last = &local_deferred.first,
+ };
+}
--- /dev/null
+/*
+ * BIRD -- Deferring calls to the end of the task
+ *
+ * (c) 2024 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/**
+ * There are cases when we need to just run something multiple times after the
+ * current task ends, mostly for cleanup reasons, and it doesn't need the
+ * full-blown event list overhead. Therefore, one just can use this tool
+ * instead. */
+
+#include "lib/birdlib.h"
+#include "lib/event.h"
+#include "lib/resource.h"
+#include "lib/io-loop.h"
+
+struct deferred_call {
+ struct deferred_call *next;
+ void (*hook)(struct deferred_call *);
+};
+
+struct deferred {
+ event e;
+ linpool *lp;
+ struct deferred_call *first, **last;
+};
+
+extern _Thread_local struct deferred local_deferred;
+void defer_init(linpool *lp);
+
+static inline void defer_call(struct deferred_call *call, size_t actual_size) {
+ /* Reallocate the call to the appropriate linpool */
+ ASSERT_DIE(actual_size < 128);
+ struct deferred_call *a = lp_alloc(local_deferred.lp, actual_size);
+ memcpy(a, call, actual_size);
+
+ /* If first, send the actual event to the local thread */
+ if (local_deferred.last == &local_deferred.first)
+ ev_send_this_thread(&local_deferred.e);
+
+ /* Add to list */
+ a->next = NULL;
+ *local_deferred.last = a;
+ local_deferred.last = &a->next;
+}
#define LOCAL_DEBUG
-_Thread_local struct lfuc_unlock_queue *lfuc_unlock_queue;
-
-void lfuc_unlock_deferred(void *_q)
+void lfuc_unlock_deferred(struct deferred_call *dc)
{
- struct lfuc_unlock_queue *q = _q;
- for (u32 i = 0; i < q->pos; i++)
- lfuc_unlock_immediately(q->block[i].c, q->block[i].el, q->block[i].ev);
-
- free_page(q);
- lfuc_unlock_queue = NULL;
+ struct lfuc_unlock_queue_item *luqi = SKIP_BACK(struct lfuc_unlock_queue_item, dc, dc);
+ lfuc_unlock_immediately(luqi->c, luqi->el, luqi->ev);
}
#if 0
#ifndef _BIRD_LOCKFREE_H_
#define _BIRD_LOCKFREE_H_
+#include "lib/defer.h"
#include "lib/event.h"
#include "lib/rcu.h"
#include "lib/settle.h"
// return uc - LFUC_IN_PROGRESS - 1;
}
-extern _Thread_local struct lfuc_unlock_queue {
- event e;
- u32 pos;
- struct lfuc_unlock_queue_block {
- struct lfuc *c;
- event_list *el;
- event *ev;
- } block[0];
-} *lfuc_unlock_queue;
+struct lfuc_unlock_queue_item {
+ struct deferred_call dc;
+ struct lfuc *c;
+ event_list *el;
+ event *ev;
+};
-void lfuc_unlock_deferred(void *queue);
+void lfuc_unlock_deferred(struct deferred_call *dc);
static inline void lfuc_unlock(struct lfuc *c, event_list *el, event *ev)
{
- static u32 queue_items = 0;
- if (queue_items == 0)
- {
- ASSERT_DIE((u64) page_size > sizeof(struct lfuc_unlock_queue) + sizeof(struct lfuc_unlock_queue_block));
- queue_items = (page_size - OFFSETOF(struct lfuc_unlock_queue, block))
- / sizeof lfuc_unlock_queue->block[0];
- }
-
- if (!lfuc_unlock_queue || (lfuc_unlock_queue->pos >= queue_items))
- {
- lfuc_unlock_queue = alloc_page();
- *lfuc_unlock_queue = (struct lfuc_unlock_queue) {
- .e = {
- .hook = lfuc_unlock_deferred,
- .data = lfuc_unlock_queue,
- },
- };
-
- ev_send_this_thread(&lfuc_unlock_queue->e);
- }
-
- lfuc_unlock_queue->block[lfuc_unlock_queue->pos++] = (struct lfuc_unlock_queue_block) {
+ struct lfuc_unlock_queue_item luqi = {
+ .dc.hook = lfuc_unlock_deferred,
.c = c,
.el = el,
.ev = ev,
};
+
+ defer_call(&luqi.dc, sizeof luqi);
}
/**
#include "nest/bird.h"
#include "lib/buffer.h"
+#include "lib/defer.h"
#include "lib/lists.h"
#include "lib/locking.h"
#include "lib/resource.h"
tmp_init(thr->pool, birdloop_domain(thr->meta));
init_list(&thr->loops);
+ defer_init(lp_new(thr->pool));
+
thr->sock_changed = 1;
struct pfd pfd;
birdloop_enter_locked(&main_birdloop);
this_birdloop = &main_birdloop;
this_thread = &main_thread;
+
+ defer_init(lp_new(&root_pool));
}
static void