1 // SPDX-FileCopyrightText: 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 // SPDX-License-Identifier: LGPL-2.1-or-later
5 #ifndef _URCU_WFSTACK_H
6 #define _URCU_WFSTACK_H
9 * Userspace RCU library - Stack with wait-free push, blocking traversal.
14 #include <urcu/compiler.h>
21 * Stack with wait-free push, blocking traversal.
23 * Stack implementing push, pop, pop_all operations, as well as iterator
24 * on the stack head returned by pop_all.
26 * Wait-free operations: cds_wfs_push, __cds_wfs_pop_all, cds_wfs_empty,
28 * Blocking operations: cds_wfs_pop, cds_wfs_pop_all, cds_wfs_next,
29 * iteration on stack head returned by pop_all.
31 * Synchronization table:
33 * External synchronization techniques described in the API below is
34 * required between pairs marked with "X". No external synchronization
35 * required between pairs marked with "-".
37 * cds_wfs_push __cds_wfs_pop __cds_wfs_pop_all
40 * __cds_wfs_pop_all - X -
42 * cds_wfs_pop and cds_wfs_pop_all use an internal mutex to provide
46 #define CDS_WFS_WOULDBLOCK ((struct cds_wfs_node *) -1UL)
49 CDS_WFS_STATE_LAST
= (1U << 0),
53 * struct cds_wfs_node is returned by __cds_wfs_pop, and also used as
54 * iterator on stack. It is not safe to dereference the node next
55 * pointer when returned by __cds_wfs_pop_blocking.
58 struct cds_wfs_node
*next
;
62 * struct cds_wfs_head is returned by __cds_wfs_pop_all, and can be used
63 * to begin iteration on the stack. "node" needs to be the first field of
64 * cds_wfs_head, so the end-of-stack pointer value can be used for both
68 struct cds_wfs_node node
;
71 struct __cds_wfs_stack
{
72 struct cds_wfs_head
*head
;
75 struct cds_wfs_stack
{
76 struct cds_wfs_head
*head
;
81 * In C, the transparent union allows calling functions that work on both
82 * struct cds_wfs_stack and struct __cds_wfs_stack on any of those two
85 * In C++, implement static inline wrappers using function overloading
86 * to obtain an API similar to C.
88 * Avoid complaints from clang++ not knowing the transparent union
91 #if defined(__clang__)
92 #pragma clang diagnostic push
93 #pragma clang diagnostic ignored "-Wignored-attributes"
96 struct __cds_wfs_stack
*_s
;
97 struct cds_wfs_stack
*s
;
98 } __attribute__((__transparent_union__
)) cds_wfs_stack_ptr_t
;
101 const struct __cds_wfs_stack
*_s
;
102 const struct cds_wfs_stack
*s
;
103 } __attribute__((__transparent_union__
)) cds_wfs_stack_const_ptr_t
;
104 #if defined(__clang__)
105 #pragma clang diagnostic pop
110 #include <urcu/static/wfstack.h>
112 #define cds_wfs_node_init _cds_wfs_node_init
113 #define cds_wfs_init _cds_wfs_init
114 #define cds_wfs_destroy _cds_wfs_destroy
115 #define __cds_wfs_init ___cds_wfs_init
116 #define cds_wfs_empty _cds_wfs_empty
117 #define cds_wfs_push _cds_wfs_push
119 /* Locking performed internally */
120 #define cds_wfs_pop_blocking _cds_wfs_pop_blocking
121 #define cds_wfs_pop_with_state_blocking _cds_wfs_pop_with_state_blocking
122 #define cds_wfs_pop_all_blocking _cds_wfs_pop_all_blocking
125 * For iteration on cds_wfs_head returned by __cds_wfs_pop_all or
126 * cds_wfs_pop_all_blocking.
128 #define cds_wfs_first _cds_wfs_first
129 #define cds_wfs_next_blocking _cds_wfs_next_blocking
130 #define cds_wfs_next_nonblocking _cds_wfs_next_nonblocking
132 /* Pop locking with internal mutex */
133 #define cds_wfs_pop_lock _cds_wfs_pop_lock
134 #define cds_wfs_pop_unlock _cds_wfs_pop_unlock
136 /* Synchronization ensured by the caller. See synchronization table. */
137 #define __cds_wfs_pop_blocking ___cds_wfs_pop_blocking
138 #define __cds_wfs_pop_with_state_blocking \
139 ___cds_wfs_pop_with_state_blocking
140 #define __cds_wfs_pop_nonblocking ___cds_wfs_pop_nonblocking
141 #define __cds_wfs_pop_with_state_nonblocking \
142 ___cds_wfs_pop_with_state_nonblocking
143 #define __cds_wfs_pop_all ___cds_wfs_pop_all
145 #else /* !_LGPL_SOURCE */
148 * cds_wfs_node_init: initialize wait-free stack node.
150 extern void cds_wfs_node_init(struct cds_wfs_node
*node
);
153 * cds_wfs_init: initialize wait-free stack (with lock). Pair with
156 extern void cds_wfs_init(struct cds_wfs_stack
*s
);
159 * cds_wfs_destroy: destroy wait-free stack (with lock). Pair with
162 extern void cds_wfs_destroy(struct cds_wfs_stack
*s
);
165 * __cds_wfs_init: initialize wait-free stack (no lock). Don't pair with
166 * any destroy function.
168 extern void __cds_wfs_init(struct __cds_wfs_stack
*s
);
171 * cds_wfs_empty: return whether wait-free stack is empty.
173 * No memory barrier is issued. No mutual exclusion is required.
175 extern bool cds_wfs_empty(cds_wfs_stack_const_ptr_t u_stack
);
178 * cds_wfs_push: push a node into the stack.
180 * Issues a full memory barrier before push. No mutual exclusion is
183 * Returns 0 if the stack was empty prior to adding the node.
184 * Returns non-zero otherwise.
186 extern int cds_wfs_push(cds_wfs_stack_ptr_t u_stack
, struct cds_wfs_node
*node
);
189 * cds_wfs_pop_blocking: pop a node from the stack.
191 * Calls __cds_wfs_pop_blocking with an internal pop mutex held.
193 extern struct cds_wfs_node
*cds_wfs_pop_blocking(struct cds_wfs_stack
*s
);
196 * cds_wfs_pop_with_state_blocking: pop a node from the stack, with state.
198 * Same as cds_wfs_pop_blocking, but stores whether the stack was
199 * empty into state (CDS_WFS_STATE_LAST).
201 extern struct cds_wfs_node
*
202 cds_wfs_pop_with_state_blocking(struct cds_wfs_stack
*s
, int *state
);
205 * cds_wfs_pop_all_blocking: pop all nodes from a stack.
207 * Calls __cds_wfs_pop_all with an internal pop mutex held.
209 extern struct cds_wfs_head
*cds_wfs_pop_all_blocking(struct cds_wfs_stack
*s
);
212 * cds_wfs_first: get first node of a popped stack.
214 * Content written into the node before enqueue is guaranteed to be
215 * consistent, but no other memory ordering is ensured.
217 * Used by for-like iteration macros in urcu/wfstack.h:
218 * cds_wfs_for_each_blocking()
219 * cds_wfs_for_each_blocking_safe()
221 * Returns NULL if popped stack is empty, top stack node otherwise.
223 extern struct cds_wfs_node
*cds_wfs_first(struct cds_wfs_head
*head
);
226 * cds_wfs_next_blocking: get next node of a popped stack.
228 * Content written into the node before enqueue is guaranteed to be
229 * consistent, but no other memory ordering is ensured.
231 * Used by for-like iteration macros in urcu/wfstack.h:
232 * cds_wfs_for_each_blocking()
233 * cds_wfs_for_each_blocking_safe()
235 * Returns NULL if reached end of popped stack, non-NULL next stack
238 extern struct cds_wfs_node
*cds_wfs_next_blocking(struct cds_wfs_node
*node
);
241 * cds_wfs_next_nonblocking: get next node of a popped stack.
243 * Same as cds_wfs_next_blocking, but returns CDS_WFS_WOULDBLOCK if it
246 extern struct cds_wfs_node
*cds_wfs_next_nonblocking(struct cds_wfs_node
*node
);
249 * cds_wfs_pop_lock: lock stack pop-protection mutex.
251 extern void cds_wfs_pop_lock(struct cds_wfs_stack
*s
);
254 * cds_wfs_pop_unlock: unlock stack pop-protection mutex.
256 extern void cds_wfs_pop_unlock(struct cds_wfs_stack
*s
);
259 * __cds_wfs_pop_blocking: pop a node from the stack.
261 * Returns NULL if stack is empty.
263 * __cds_wfs_pop_blocking needs to be synchronized using one of the
264 * following techniques:
266 * 1) Calling __cds_wfs_pop_blocking under rcu read lock critical
267 * section. The caller must wait for a grace period to pass before
268 * freeing the returned node or modifying the cds_wfs_node structure.
269 * 2) Using mutual exclusion (e.g. mutexes) to protect
270 * __cds_wfs_pop_blocking and __cds_wfs_pop_all callers.
271 * 3) Ensuring that only ONE thread can call __cds_wfs_pop_blocking()
272 * and __cds_wfs_pop_all(). (multi-provider/single-consumer scheme).
274 extern struct cds_wfs_node
*__cds_wfs_pop_blocking(cds_wfs_stack_ptr_t u_stack
);
277 * __cds_wfs_pop_with_state_blocking: pop a node from the stack, with state.
279 * Same as __cds_wfs_pop_blocking, but stores whether the stack was
280 * empty into state (CDS_WFS_STATE_LAST).
282 extern struct cds_wfs_node
*
283 __cds_wfs_pop_with_state_blocking(cds_wfs_stack_ptr_t u_stack
,
287 * __cds_wfs_pop_nonblocking: pop a node from the stack.
289 * Same as __cds_wfs_pop_blocking, but returns CDS_WFS_WOULDBLOCK if
292 extern struct cds_wfs_node
*__cds_wfs_pop_nonblocking(cds_wfs_stack_ptr_t u_stack
);
295 * __cds_wfs_pop_with_state_nonblocking: pop a node from the stack, with state.
297 * Same as __cds_wfs_pop_nonblocking, but stores whether the stack was
298 * empty into state (CDS_WFS_STATE_LAST).
300 extern struct cds_wfs_node
*
301 __cds_wfs_pop_with_state_nonblocking(cds_wfs_stack_ptr_t u_stack
,
305 * __cds_wfs_pop_all: pop all nodes from a stack.
307 * __cds_wfs_pop_all does not require any synchronization with other
308 * push, nor with other __cds_wfs_pop_all, but requires synchronization
309 * matching the technique used to synchronize __cds_wfs_pop_blocking:
311 * 1) If __cds_wfs_pop_blocking is called under rcu read lock critical
312 * section, both __cds_wfs_pop_blocking and cds_wfs_pop_all callers
313 * must wait for a grace period to pass before freeing the returned
314 * node or modifying the cds_wfs_node structure. However, no RCU
315 * read-side critical section is needed around __cds_wfs_pop_all.
316 * 2) Using mutual exclusion (e.g. mutexes) to protect
317 * __cds_wfs_pop_blocking and __cds_wfs_pop_all callers.
318 * 3) Ensuring that only ONE thread can call __cds_wfs_pop_blocking()
319 * and __cds_wfs_pop_all(). (multi-provider/single-consumer scheme).
321 extern struct cds_wfs_head
*__cds_wfs_pop_all(cds_wfs_stack_ptr_t u_stack
);
323 #endif /* !_LGPL_SOURCE */
326 * cds_wfs_for_each_blocking: Iterate over all nodes returned by
327 * __cds_wfs_pop_all().
328 * @head: head of the queue (struct cds_wfs_head pointer).
329 * @node: iterator (struct cds_wfs_node pointer).
331 * Content written into each node before enqueue is guaranteed to be
332 * consistent, but no other memory ordering is ensured.
334 #define cds_wfs_for_each_blocking(head, node) \
335 for (node = cds_wfs_first(head); \
337 node = cds_wfs_next_blocking(node))
340 * cds_wfs_for_each_blocking_safe: Iterate over all nodes returned by
341 * __cds_wfs_pop_all(). Safe against deletion.
342 * @head: head of the queue (struct cds_wfs_head pointer).
343 * @node: iterator (struct cds_wfs_node pointer).
344 * @n: struct cds_wfs_node pointer holding the next pointer (used
347 * Content written into each node before enqueue is guaranteed to be
348 * consistent, but no other memory ordering is ensured.
350 #define cds_wfs_for_each_blocking_safe(head, node, n) \
351 for (node = cds_wfs_first(head), \
352 n = (node ? cds_wfs_next_blocking(node) : NULL); \
354 node = n, n = (node ? cds_wfs_next_blocking(node) : NULL))
360 * In C++, implement static inline wrappers using function overloading
361 * to obtain an API similar to C.
364 static inline cds_wfs_stack_ptr_t
cds_wfs_stack_cast(struct __cds_wfs_stack
*s
)
366 cds_wfs_stack_ptr_t ret
= {
372 static inline cds_wfs_stack_ptr_t
cds_wfs_stack_cast(struct cds_wfs_stack
*s
)
374 cds_wfs_stack_ptr_t ret
= {
380 static inline cds_wfs_stack_const_ptr_t
cds_wfs_stack_const_cast(const struct __cds_wfs_stack
*s
)
382 cds_wfs_stack_const_ptr_t ret
= {
388 static inline cds_wfs_stack_const_ptr_t
cds_wfs_stack_const_cast(const struct cds_wfs_stack
*s
)
390 cds_wfs_stack_const_ptr_t ret
= {
396 template<typename T
> static inline bool cds_wfs_empty(T s
)
398 return cds_wfs_empty(cds_wfs_stack_const_cast(s
));
401 template<typename T
> static inline int cds_wfs_push(T s
, struct cds_wfs_node
*node
)
403 return cds_wfs_push(cds_wfs_stack_cast(s
), node
);
406 template<typename T
> static inline struct cds_wfs_node
*__cds_wfs_pop_blocking(T s
)
408 return __cds_wfs_pop_blocking(cds_wfs_stack_cast(s
));
411 template<typename T
> static inline struct cds_wfs_node
*
412 __cds_wfs_pop_with_state_blocking(T s
, int *state
)
414 return __cds_wfs_pop_with_state_blocking(cds_wfs_stack_cast(s
), state
);
417 template<typename T
> static inline struct cds_wfs_node
*__cds_wfs_pop_nonblocking(T s
)
420 return __cds_wfs_pop_nonblocking(cds_wfs_stack_cast(s
));
423 template<typename T
> static inline struct cds_wfs_node
*
424 __cds_wfs_pop_with_state_nonblocking(T s
, int *state
)
426 return __cds_wfs_pop_with_state_nonblocking(cds_wfs_stack_cast(s
), state
);
429 template<typename T
> static inline struct cds_wfs_head
*__cds_wfs_pop_all(T s
)
431 return __cds_wfs_pop_all(cds_wfs_stack_cast(s
));
436 #endif /* _URCU_WFSTACK_H */