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