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