mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	Refactored the deferring framework into a separate structure
This commit is contained in:
		@@ -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
									
								
							
							
						
						
									
										40
									
								
								lib/defer.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										48
									
								
								lib/defer.h
									
									
									
									
									
										Normal 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;
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
@@ -116,46 +117,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user