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