Home | History | Annotate | Line # | Download | only in urcu
      1 // SPDX-FileCopyrightText: 2010-2012 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com>
      2 //
      3 // SPDX-License-Identifier: LGPL-2.1-or-later
      4 
      5 #ifndef _URCU_LFSTACK_H
      6 #define _URCU_LFSTACK_H
      7 
      8 /*
      9  * Userspace RCU library - Lock-Free Stack
     10  */
     11 
     12 #ifdef __cplusplus
     13 extern "C" {
     14 #endif
     15 
     16 #include <stdbool.h>
     17 #include <pthread.h>
     18 
     19 /*
     20  * Lock-free stack.
     21  *
     22  * Stack implementing push, pop, pop_all operations, as well as iterator
     23  * on the stack head returned by pop_all.
     24  *
     25  * Synchronization table:
     26  *
     27  * External synchronization techniques described in the API below is
     28  * required between pairs marked with "X". No external synchronization
     29  * required between pairs marked with "-".
     30  *
     31  *                      cds_lfs_push  __cds_lfs_pop  __cds_lfs_pop_all
     32  * cds_lfs_push               -              -                  -
     33  * __cds_lfs_pop              -              X                  X
     34  * __cds_lfs_pop_all          -              X                  -
     35  *
     36  * cds_lfs_pop_blocking and cds_lfs_pop_all_blocking use an internal
     37  * mutex to provide synchronization.
     38  */
     39 
     40 /*
     41  * struct cds_lfs_node is returned by cds_lfs_pop, and also used as
     42  * iterator on stack. It is not safe to dereference the node next
     43  * pointer when returned by cds_lfs_pop.
     44  */
     45 struct cds_lfs_node {
     46 	struct cds_lfs_node *next;
     47 };
     48 
     49 /*
     50  * struct cds_lfs_head is returned by __cds_lfs_pop_all, and can be used
     51  * to begin iteration on the stack. "node" needs to be the first field
     52  * of cds_lfs_head, so the end-of-stack pointer value can be used for
     53  * both types.
     54  */
     55 struct cds_lfs_head {
     56 	struct cds_lfs_node node;
     57 };
     58 
     59 struct __cds_lfs_stack {
     60 	struct cds_lfs_head *head;
     61 };
     62 
     63 struct cds_lfs_stack {
     64 	struct cds_lfs_head *head;
     65 	pthread_mutex_t lock;
     66 };
     67 
     68 /*
     69  * In C, the transparent union allows calling functions that work on
     70  * both struct cds_lfs_stack and struct __cds_lfs_stack on any of those
     71  * two types.
     72  *
     73  * In C++, implement static inline wrappers using function overloading
     74  * to obtain an API similar to C.
     75  *
     76  * Avoid complaints from clang++ not knowing the transparent union
     77  * attribute.
     78  */
     79 #if defined(__clang__)
     80 #pragma clang diagnostic push
     81 #pragma clang diagnostic ignored "-Wignored-attributes"
     82 #endif
     83 typedef union {
     84 	struct __cds_lfs_stack *_s;
     85 	struct cds_lfs_stack *s;
     86 } __attribute__((__transparent_union__)) cds_lfs_stack_ptr_t;
     87 
     88 typedef union {
     89 	const struct __cds_lfs_stack *_s;
     90 	const struct cds_lfs_stack *s;
     91 } __attribute__((__transparent_union__)) cds_lfs_stack_const_ptr_t;
     92 #if defined(__clang__)
     93 #pragma clang diagnostic pop
     94 #endif
     95 
     96 #ifdef _LGPL_SOURCE
     97 
     98 #include <urcu/static/lfstack.h>
     99 
    100 #define cds_lfs_node_init		_cds_lfs_node_init
    101 #define cds_lfs_init			_cds_lfs_init
    102 #define cds_lfs_destroy			_cds_lfs_destroy
    103 #define __cds_lfs_init			___cds_lfs_init
    104 #define cds_lfs_empty			_cds_lfs_empty
    105 #define cds_lfs_push			_cds_lfs_push
    106 
    107 /* Locking performed internally */
    108 #define cds_lfs_pop_blocking		_cds_lfs_pop_blocking
    109 #define cds_lfs_pop_all_blocking	_cds_lfs_pop_all_blocking
    110 
    111 /* Synchronize pop with internal mutex */
    112 #define cds_lfs_pop_lock		_cds_lfs_pop_lock
    113 #define cds_lfs_pop_unlock		_cds_lfs_pop_unlock
    114 
    115 /* Synchronization ensured by the caller. See synchronization table. */
    116 #define __cds_lfs_pop			___cds_lfs_pop
    117 #define __cds_lfs_pop_all		___cds_lfs_pop_all
    118 
    119 #else /* !_LGPL_SOURCE */
    120 
    121 /*
    122  * cds_lfs_node_init: initialize lock-free stack node.
    123  */
    124 extern void cds_lfs_node_init(struct cds_lfs_node *node);
    125 
    126 /*
    127  * cds_lfs_init: initialize lock-free stack (with locking). Pair with
    128  * cds_lfs_destroy().
    129  */
    130 extern void cds_lfs_init(struct cds_lfs_stack *s);
    131 
    132 /*
    133  * cds_lfs_destroy: destroy lock-free stack (with lock). Pair with
    134  * cds_lfs_init().
    135  */
    136 extern void cds_lfs_destroy(struct cds_lfs_stack *s);
    137 
    138 /*
    139  * __cds_lfs_init: initialize lock-free stack (without lock).
    140  * Don't pair with any destroy function.
    141  */
    142 extern void __cds_lfs_init(struct __cds_lfs_stack *s);
    143 
    144 /*
    145  * cds_lfs_empty: return whether lock-free stack is empty.
    146  *
    147  * No memory barrier is issued. No mutual exclusion is required.
    148  */
    149 extern bool cds_lfs_empty(cds_lfs_stack_const_ptr_t s);
    150 
    151 /*
    152  * cds_lfs_push: push a node into the stack.
    153  *
    154  * Does not require any synchronization with other push nor pop.
    155  *
    156  * Returns 0 if the stack was empty prior to adding the node.
    157  * Returns non-zero otherwise.
    158  */
    159 extern bool cds_lfs_push(cds_lfs_stack_ptr_t s,
    160 			struct cds_lfs_node *node);
    161 
    162 /*
    163  * cds_lfs_pop_blocking: pop a node from the stack.
    164  *
    165  * Calls __cds_lfs_pop with an internal pop mutex held.
    166  */
    167 extern struct cds_lfs_node *cds_lfs_pop_blocking(struct cds_lfs_stack *s);
    168 
    169 /*
    170  * cds_lfs_pop_all_blocking: pop all nodes from a stack.
    171  *
    172  * Calls __cds_lfs_pop_all with an internal pop mutex held.
    173  */
    174 extern struct cds_lfs_head *cds_lfs_pop_all_blocking(struct cds_lfs_stack *s);
    175 
    176 /*
    177  * cds_lfs_pop_lock: lock stack pop-protection mutex.
    178  */
    179 extern void cds_lfs_pop_lock(struct cds_lfs_stack *s);
    180 
    181 /*
    182  * cds_lfs_pop_unlock: unlock stack pop-protection mutex.
    183  */
    184 extern void cds_lfs_pop_unlock(struct cds_lfs_stack *s);
    185 
    186 /*
    187  * __cds_lfs_pop: pop a node from the stack.
    188  *
    189  * Returns NULL if stack is empty.
    190  *
    191  * __cds_lfs_pop needs to be synchronized using one of the following
    192  * techniques:
    193  *
    194  * 1) Calling __cds_lfs_pop under rcu read lock critical section.
    195  *    Both __cds_lfs_pop and __cds_lfs_pop_all callers must wait for a
    196  *    grace period to pass before freeing the returned node or pushing
    197  *    the node back into the stack. It is valid to overwrite the content
    198  *    of cds_lfs_node immediately after __cds_lfs_pop and
    199  *    __cds_lfs_pop_all.
    200  * 2) Using mutual exclusion (e.g. mutexes) to protect __cds_lfs_pop
    201  *    and __cds_lfs_pop_all callers.
    202  * 3) Ensuring that only ONE thread can call __cds_lfs_pop() and
    203  *    __cds_lfs_pop_all(). (multi-provider/single-consumer scheme).
    204  */
    205 extern struct cds_lfs_node *__cds_lfs_pop(cds_lfs_stack_ptr_t s);
    206 
    207 /*
    208  * __cds_lfs_pop_all: pop all nodes from a stack.
    209  *
    210  * __cds_lfs_pop_all does not require any synchronization with other
    211  * push, nor with other __cds_lfs_pop_all, but requires synchronization
    212  * matching the technique used to synchronize __cds_lfs_pop:
    213  *
    214  * 1) If __cds_lfs_pop is called under rcu read lock critical section,
    215  *    both __cds_lfs_pop and __cds_lfs_pop_all callers must wait for a
    216  *    grace period to pass before freeing the returned node or pushing
    217  *    the node back into the stack. It is valid to overwrite the content
    218  *    of cds_lfs_node immediately after __cds_lfs_pop and
    219  *    __cds_lfs_pop_all. No RCU read-side critical section is needed
    220  *    around __cds_lfs_pop_all.
    221  * 2) Using mutual exclusion (e.g. mutexes) to protect __cds_lfs_pop and
    222  *    __cds_lfs_pop_all callers.
    223  * 3) Ensuring that only ONE thread can call __cds_lfs_pop() and
    224  *    __cds_lfs_pop_all(). (multi-provider/single-consumer scheme).
    225  */
    226 extern struct cds_lfs_head *__cds_lfs_pop_all(cds_lfs_stack_ptr_t s);
    227 
    228 #endif /* !_LGPL_SOURCE */
    229 
    230 /*
    231  * cds_lfs_for_each: Iterate over all nodes returned by
    232  *                   __cds_lfs_pop_all.
    233  * @__head: node returned by __cds_lfs_pop_all (struct cds_lfs_head pointer).
    234  * @__node: node to use as iterator (struct cds_lfs_node pointer).
    235  *
    236  * Content written into each node before push is guaranteed to be
    237  * consistent, but no other memory ordering is ensured.
    238  */
    239 #define cds_lfs_for_each(__head, __node)	\
    240 	for (__node = &__head->node;		\
    241 		__node != NULL;			\
    242 		__node = __node->next)
    243 
    244 /*
    245  * cds_lfs_for_each_safe: Iterate over all nodes returned by
    246  *                        __cds_lfs_pop_all, safe against node deletion.
    247  * @__head: node returned by __cds_lfs_pop_all (struct cds_lfs_head pointer).
    248  * @__node: node to use as iterator (struct cds_lfs_node pointer).
    249  * @__n: struct cds_lfs_node pointer holding the next pointer (used
    250  *       internally).
    251  *
    252  * Content written into each node before push is guaranteed to be
    253  * consistent, but no other memory ordering is ensured.
    254  */
    255 #define cds_lfs_for_each_safe(__head, __node, __n)			   \
    256 	for (__node = &__head->node, __n = (__node ? __node->next : NULL); \
    257 		__node != NULL;						   \
    258 		__node = __n, __n = (__node ? __node->next : NULL))
    259 
    260 #ifdef __cplusplus
    261 }
    262 
    263 /*
    264  * In C++, implement static inline wrappers using function overloading
    265  * to obtain an API similar to C.
    266  */
    267 
    268 static inline cds_lfs_stack_ptr_t cds_lfs_stack_cast(struct __cds_lfs_stack *s)
    269 {
    270 	cds_lfs_stack_ptr_t ret = {
    271 		._s = s,
    272 	};
    273 	return ret;
    274 }
    275 
    276 static inline cds_lfs_stack_ptr_t cds_lfs_stack_cast(struct cds_lfs_stack *s)
    277 {
    278 	cds_lfs_stack_ptr_t ret = {
    279 		.s = s,
    280 	};
    281 	return ret;
    282 }
    283 
    284 static inline cds_lfs_stack_const_ptr_t cds_lfs_stack_const_cast(const struct __cds_lfs_stack *s)
    285 {
    286 	cds_lfs_stack_const_ptr_t ret = {
    287 		._s = s,
    288 	};
    289 	return ret;
    290 }
    291 
    292 static inline cds_lfs_stack_const_ptr_t cds_lfs_stack_const_cast(const struct cds_lfs_stack *s)
    293 {
    294 	cds_lfs_stack_const_ptr_t ret = {
    295 		.s = s,
    296 	};
    297 	return ret;
    298 }
    299 
    300 template<typename T> static inline bool cds_lfs_empty(T s)
    301 {
    302 	return cds_lfs_empty(cds_lfs_stack_const_cast(s));
    303 }
    304 
    305 template<typename T> static inline bool cds_lfs_push(T s,
    306 			struct cds_lfs_node *node)
    307 {
    308 	return cds_lfs_push(cds_lfs_stack_cast(s), node);
    309 }
    310 
    311 template<typename T> static inline struct cds_lfs_node *__cds_lfs_pop(T s)
    312 {
    313 	return __cds_lfs_pop(cds_lfs_stack_cast(s));
    314 }
    315 
    316 template<typename T> static inline struct cds_lfs_head *__cds_lfs_pop_all(T s)
    317 {
    318 	return __cds_lfs_pop_all(cds_lfs_stack_cast(s));
    319 }
    320 
    321 #endif	/* __cplusplus */
    322 
    323 #endif /* _URCU_LFSTACK_H */
    324