mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			89 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *	BIRD Library -- Safe Linked Lists
 | 
						|
 *
 | 
						|
 *	(c) 1998 Martin Mares <mj@ucw.cz>
 | 
						|
 *
 | 
						|
 *	Can be freely distributed and used under the terms of the GNU GPL.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef _BIRD_SLISTS_H_
 | 
						|
#define _BIRD_SLISTS_H_
 | 
						|
 | 
						|
/*
 | 
						|
 *  These linked lists work in a way similar to standard lists defined
 | 
						|
 *  in lib/lists.h, but in addition to all usual list functions they
 | 
						|
 *  provide fast deletion/insertion/everything-safe asynchronous
 | 
						|
 *  walking.
 | 
						|
 *
 | 
						|
 *  Example:
 | 
						|
 *		slist l;
 | 
						|
 *		siterator i;
 | 
						|
 *		snode *n;
 | 
						|
 *
 | 
						|
 *	       	s_init(&i, &l);		// Initialize iteration
 | 
						|
 *		...
 | 
						|
 *		n = s_get(&i);		// Some time later, fetch present
 | 
						|
 *					// value of the iterator and unlink it
 | 
						|
 *					// from the list.
 | 
						|
 *		while (n->next) {
 | 
						|
 *		     ...
 | 
						|
 *		     if (decided_to_stop) {
 | 
						|
 *			s_put(&i, n);	// Store current position (maybe even
 | 
						|
 *					// that we stay at list end)
 | 
						|
 *			return;		// and return
 | 
						|
 *		     }
 | 
						|
 *		     ...
 | 
						|
 *		}
 | 
						|
 *		// After finishing, don't link the iterator back
 | 
						|
 */
 | 
						|
 | 
						|
typedef struct snode {
 | 
						|
  struct snode *next, *prev;
 | 
						|
  struct siterator *readers;
 | 
						|
} snode;
 | 
						|
 | 
						|
typedef struct slist {			/* In fact two overlayed snodes */
 | 
						|
  struct snode *head, *null, *tail;
 | 
						|
  struct siterator *tail_readers;
 | 
						|
} slist;
 | 
						|
 | 
						|
typedef struct siterator {
 | 
						|
  /*
 | 
						|
   * Caution: Layout of this structure depends hard on layout of the
 | 
						|
   *	      snode. Our `next' must be at position of snode `readers'
 | 
						|
   *	      field, our `null' must be at position of `prev' and it must
 | 
						|
   *	      contain NULL in order to distinguish between siterator
 | 
						|
   *	      and snode (snodes with NULL `prev' field never carry
 | 
						|
   *	      iterators). You are not expected to understand this.
 | 
						|
   */
 | 
						|
  struct siterator *prev, *null, *next;
 | 
						|
  /*
 | 
						|
   * For recently merged nodes this can be NULL, but then it's NULL
 | 
						|
   * for all successors as well. This is done to speed up iterator
 | 
						|
   * merging when there are lots of deletions.
 | 
						|
   */
 | 
						|
  snode *node;
 | 
						|
} siterator;
 | 
						|
 | 
						|
#define SNODE (snode *)
 | 
						|
#define SHEAD(list) ((void *)((list).head))
 | 
						|
#define STAIL(list) ((void *)((list).tail))
 | 
						|
#define WALK_SLIST(n,list) for(n=SHEAD(list);(SNODE (n))->next; \
 | 
						|
				n=(void *)((SNODE (n))->next))
 | 
						|
#define WALK_SLIST_DELSAFE(n,nxt,list) \
 | 
						|
     for(n=SHEAD(list); nxt=(void *)((SNODE (n))->next); n=(void *) nxt)
 | 
						|
#define EMPTY_SLIST(list) (!(list).head->next)
 | 
						|
 | 
						|
void s_add_tail(slist *, snode *);
 | 
						|
void s_add_head(slist *, snode *);
 | 
						|
void s_rem_node(snode *);
 | 
						|
void s_add_tail_list(slist *, slist *);
 | 
						|
void s_init_list(slist *);
 | 
						|
void s_insert_node(snode *, snode *);
 | 
						|
 | 
						|
snode *s_get(siterator *);
 | 
						|
void s_put(siterator *, snode *n);
 | 
						|
static inline void s_init(siterator *i, slist *l) { s_put(i, SHEAD(*l)); }
 | 
						|
 | 
						|
#endif
 |