0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-10-18 09:58:43 +00:00

Refactored the deferring framework into a separate structure

This commit is contained in:
Maria Matejka 2024-04-23 17:35:00 +02:00 committed by Katerina Kubecova
parent e39a76d6f6
commit bff3b7eb2c
6 changed files with 109 additions and 42 deletions

View File

@ -1,4 +1,4 @@
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)

40
lib/defer.c Normal file
View File

@ -0,0 +1,40 @@
/*
* 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,
};
}

48
lib/defer.h Normal file
View File

@ -0,0 +1,48 @@
/*
* 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;
}

View File

@ -12,16 +12,10 @@
#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

View File

@ -10,6 +10,7 @@
#ifndef _BIRD_LOCKFREE_H_
#define _BIRD_LOCKFREE_H_
#include "lib/defer.h"
#include "lib/event.h"
#include "lib/rcu.h"
#include "lib/settle.h"
@ -108,46 +109,25 @@ static inline void lfuc_unlock_immediately(struct lfuc *c, event_list *el, event
// 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);
}
/**

View File

@ -17,6 +17,7 @@
#include "nest/bird.h"
#include "lib/buffer.h"
#include "lib/defer.h"
#include "lib/lists.h"
#include "lib/locking.h"
#include "lib/resource.h"
@ -794,6 +795,8 @@ bird_thread_main(void *arg)
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;
@ -1377,6 +1380,8 @@ birdloop_init(void)
birdloop_enter_locked(&main_birdloop);
this_birdloop = &main_birdloop;
this_thread = &main_thread;
defer_init(lp_new(&root_pool));
}
static void