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