Commit | Line | Data |
---|---|---|
d3d3857f MJ |
1 | // SPDX-FileCopyrightText: 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
2 | // SPDX-FileCopyrightText: 2011-2012 Lai Jiangshan <laijs@cn.fujitsu.com> | |
3 | // | |
4 | // SPDX-License-Identifier: LGPL-2.1-or-later | |
5 | ||
8ad4ce58 MD |
6 | #ifndef _URCU_WFCQUEUE_H |
7 | #define _URCU_WFCQUEUE_H | |
8 | ||
9 | /* | |
8ad4ce58 | 10 | * Userspace RCU library - Concurrent Queue with Wait-Free Enqueue/Blocking Dequeue |
8ad4ce58 MD |
11 | */ |
12 | ||
13 | #include <pthread.h> | |
8ad4ce58 MD |
14 | #include <stdbool.h> |
15 | #include <urcu/compiler.h> | |
16 | #include <urcu/arch.h> | |
17 | ||
18 | #ifdef __cplusplus | |
19 | extern "C" { | |
20 | #endif | |
21 | ||
22 | /* | |
23 | * Concurrent queue with wait-free enqueue/blocking dequeue. | |
24 | * | |
ebfd2673 MD |
25 | * This queue has been designed and implemented collaboratively by |
26 | * Mathieu Desnoyers and Lai Jiangshan. Inspired from | |
27 | * half-wait-free/half-blocking queue implementation done by Paul E. | |
28 | * McKenney. | |
8ad4ce58 MD |
29 | */ |
30 | ||
0b73c819 | 31 | #define CDS_WFCQ_WOULDBLOCK ((struct cds_wfcq_node *) -1UL) |
47215721 | 32 | |
23773356 | 33 | enum cds_wfcq_ret { |
f878b49e | 34 | CDS_WFCQ_RET_WOULDBLOCK = -1, |
23773356 MD |
35 | CDS_WFCQ_RET_DEST_EMPTY = 0, |
36 | CDS_WFCQ_RET_DEST_NON_EMPTY = 1, | |
37 | CDS_WFCQ_RET_SRC_EMPTY = 2, | |
38 | }; | |
39 | ||
eec791af MD |
40 | enum cds_wfcq_state { |
41 | CDS_WFCQ_STATE_LAST = (1U << 0), | |
42 | }; | |
43 | ||
8ad4ce58 MD |
44 | struct cds_wfcq_node { |
45 | struct cds_wfcq_node *next; | |
46 | }; | |
47 | ||
48 | /* | |
49 | * Do not put head and tail on the same cache-line if concurrent | |
50 | * enqueue/dequeue are expected from many CPUs. This eliminates | |
51 | * false-sharing between enqueue and dequeue. | |
52 | */ | |
f637f191 MD |
53 | struct __cds_wfcq_head { |
54 | struct cds_wfcq_node node; | |
55 | }; | |
56 | ||
8ad4ce58 MD |
57 | struct cds_wfcq_head { |
58 | struct cds_wfcq_node node; | |
59 | pthread_mutex_t lock; | |
60 | }; | |
61 | ||
f637f191 | 62 | /* |
0cdbb569 | 63 | * In C, the transparent union allows calling functions that work on both |
f637f191 MD |
64 | * struct cds_wfcq_head and struct __cds_wfcq_head on any of those two |
65 | * types. | |
0cdbb569 MD |
66 | * |
67 | * In C++, implement static inline wrappers using function overloading | |
68 | * to obtain an API similar to C. | |
087bce43 MD |
69 | * |
70 | * Avoid complaints from clang++ not knowing the transparent union | |
71 | * attribute. | |
f637f191 | 72 | */ |
087bce43 MD |
73 | #if defined(__clang__) |
74 | #pragma clang diagnostic push | |
75 | #pragma clang diagnostic ignored "-Wignored-attributes" | |
76 | #endif | |
5135c0fd | 77 | typedef union { |
f637f191 MD |
78 | struct __cds_wfcq_head *_h; |
79 | struct cds_wfcq_head *h; | |
087bce43 | 80 | } __attribute__((__transparent_union__)) cds_wfcq_head_ptr_t; |
c0775411 MD |
81 | |
82 | typedef union { | |
83 | const struct __cds_wfcq_head *_h; | |
84 | const struct cds_wfcq_head *h; | |
85 | } __attribute__((__transparent_union__)) cds_wfcq_head_const_ptr_t; | |
087bce43 MD |
86 | #if defined(__clang__) |
87 | #pragma clang diagnostic pop | |
88 | #endif | |
f637f191 | 89 | |
0cdbb569 | 90 | #ifndef __cplusplus |
4d0d7cbc MD |
91 | /* |
92 | * This static inline is only present for compatibility with C++. It is | |
93 | * effect-less in C. | |
94 | */ | |
95 | static inline struct __cds_wfcq_head *__cds_wfcq_head_cast(struct __cds_wfcq_head *head) | |
96 | { | |
97 | return head; | |
98 | } | |
99 | ||
100 | /* | |
101 | * This static inline is only present for compatibility with C++. It is | |
102 | * effect-less in C. | |
103 | */ | |
104 | static inline struct cds_wfcq_head *cds_wfcq_head_cast(struct cds_wfcq_head *head) | |
105 | { | |
106 | return head; | |
107 | } | |
c0775411 MD |
108 | |
109 | /* | |
110 | * This static inline is only present for compatibility with C++. It is | |
111 | * effect-less in C. | |
112 | */ | |
113 | static inline const struct __cds_wfcq_head *__cds_wfcq_head_const_cast(const struct __cds_wfcq_head *head) | |
114 | { | |
115 | return head; | |
116 | } | |
117 | ||
118 | /* | |
119 | * This static inline is only present for compatibility with C++. It is | |
120 | * effect-less in C. | |
121 | */ | |
122 | static inline const struct cds_wfcq_head *cds_wfcq_head_const_cast(const struct cds_wfcq_head *head) | |
123 | { | |
124 | return head; | |
125 | } | |
126 | ||
4d0d7cbc MD |
127 | #else /* #ifndef __cplusplus */ |
128 | ||
0cdbb569 | 129 | /* |
aaf0064b MD |
130 | * This static inline is used by internally in the static inline |
131 | * implementation of the API. | |
0cdbb569 | 132 | */ |
4d0d7cbc MD |
133 | static inline cds_wfcq_head_ptr_t __cds_wfcq_head_cast(struct __cds_wfcq_head *head) |
134 | { | |
135 | cds_wfcq_head_ptr_t ret = { ._h = head }; | |
136 | return ret; | |
137 | } | |
0cdbb569 MD |
138 | |
139 | /* | |
aaf0064b MD |
140 | * This static inline is used by internally in the static inline |
141 | * implementation of the API. | |
0cdbb569 | 142 | */ |
4d0d7cbc MD |
143 | static inline cds_wfcq_head_ptr_t cds_wfcq_head_cast(struct cds_wfcq_head *head) |
144 | { | |
145 | cds_wfcq_head_ptr_t ret = { .h = head }; | |
146 | return ret; | |
147 | } | |
c0775411 MD |
148 | |
149 | /* | |
150 | * This static inline is used by internally in the static inline | |
151 | * implementation of the API. | |
152 | */ | |
153 | static inline cds_wfcq_head_const_ptr_t __cds_wfcq_head_const_cast(const struct __cds_wfcq_head *head) | |
154 | { | |
155 | cds_wfcq_head_const_ptr_t ret = { ._h = head }; | |
156 | return ret; | |
157 | } | |
158 | ||
159 | /* | |
160 | * This static inline is used by internally in the static inline | |
161 | * implementation of the API. | |
162 | */ | |
163 | static inline cds_wfcq_head_const_ptr_t cds_wfcq_head_const_cast(const struct cds_wfcq_head *head) | |
164 | { | |
165 | cds_wfcq_head_const_ptr_t ret = { .h = head }; | |
166 | return ret; | |
167 | } | |
168 | ||
4d0d7cbc MD |
169 | #endif /* #else #ifndef __cplusplus */ |
170 | ||
8ad4ce58 MD |
171 | struct cds_wfcq_tail { |
172 | struct cds_wfcq_node *p; | |
173 | }; | |
174 | ||
175 | #ifdef _LGPL_SOURCE | |
176 | ||
177 | #include <urcu/static/wfcqueue.h> | |
178 | ||
179 | #define cds_wfcq_node_init _cds_wfcq_node_init | |
180 | #define cds_wfcq_init _cds_wfcq_init | |
b4edfa81 | 181 | #define __cds_wfcq_init ___cds_wfcq_init |
200d100e | 182 | #define cds_wfcq_destroy _cds_wfcq_destroy |
8ad4ce58 MD |
183 | #define cds_wfcq_empty _cds_wfcq_empty |
184 | #define cds_wfcq_enqueue _cds_wfcq_enqueue | |
185 | ||
186 | /* Dequeue locking */ | |
187 | #define cds_wfcq_dequeue_lock _cds_wfcq_dequeue_lock | |
188 | #define cds_wfcq_dequeue_unlock _cds_wfcq_dequeue_unlock | |
189 | ||
190 | /* Locking performed within cds_wfcq calls. */ | |
191 | #define cds_wfcq_dequeue_blocking _cds_wfcq_dequeue_blocking | |
eec791af MD |
192 | #define cds_wfcq_dequeue_with_state_blocking \ |
193 | _cds_wfcq_dequeue_with_state_blocking | |
8ad4ce58 MD |
194 | #define cds_wfcq_splice_blocking _cds_wfcq_splice_blocking |
195 | #define cds_wfcq_first_blocking _cds_wfcq_first_blocking | |
196 | #define cds_wfcq_next_blocking _cds_wfcq_next_blocking | |
197 | ||
198 | /* Locking ensured by caller by holding cds_wfcq_dequeue_lock() */ | |
199 | #define __cds_wfcq_dequeue_blocking ___cds_wfcq_dequeue_blocking | |
eec791af MD |
200 | #define __cds_wfcq_dequeue_with_state_blocking \ |
201 | ___cds_wfcq_dequeue_with_state_blocking | |
8ad4ce58 MD |
202 | #define __cds_wfcq_splice_blocking ___cds_wfcq_splice_blocking |
203 | #define __cds_wfcq_first_blocking ___cds_wfcq_first_blocking | |
204 | #define __cds_wfcq_next_blocking ___cds_wfcq_next_blocking | |
205 | ||
47215721 MD |
206 | /* |
207 | * Locking ensured by caller by holding cds_wfcq_dequeue_lock(). | |
208 | * Non-blocking: deque, first, next return CDS_WFCQ_WOULDBLOCK if they | |
209 | * need to block. splice returns nonzero if it needs to block. | |
210 | */ | |
211 | #define __cds_wfcq_dequeue_nonblocking ___cds_wfcq_dequeue_nonblocking | |
eec791af MD |
212 | #define __cds_wfcq_dequeue_with_state_nonblocking \ |
213 | ___cds_wfcq_dequeue_with_state_nonblocking | |
47215721 MD |
214 | #define __cds_wfcq_splice_nonblocking ___cds_wfcq_splice_nonblocking |
215 | #define __cds_wfcq_first_nonblocking ___cds_wfcq_first_nonblocking | |
216 | #define __cds_wfcq_next_nonblocking ___cds_wfcq_next_nonblocking | |
217 | ||
8ad4ce58 MD |
218 | #else /* !_LGPL_SOURCE */ |
219 | ||
220 | /* | |
221 | * Mutual exclusion of cds_wfcq_* / __cds_wfcq_* API | |
222 | * | |
f878b49e MD |
223 | * Synchronization table: |
224 | * | |
225 | * External synchronization techniques described in the API below is | |
226 | * required between pairs marked with "X". No external synchronization | |
227 | * required between pairs marked with "-". | |
228 | * | |
229 | * Legend: | |
230 | * [1] cds_wfcq_enqueue | |
231 | * [2] __cds_wfcq_splice (destination queue) | |
232 | * [3] __cds_wfcq_dequeue | |
233 | * [4] __cds_wfcq_splice (source queue) | |
234 | * [5] __cds_wfcq_first | |
235 | * [6] __cds_wfcq_next | |
236 | * | |
237 | * [1] [2] [3] [4] [5] [6] | |
238 | * [1] - - - - - - | |
239 | * [2] - - - - - - | |
240 | * [3] - - X X X X | |
241 | * [4] - - X - X X | |
242 | * [5] - - X X - - | |
243 | * [6] - - X X - - | |
244 | * | |
8ad4ce58 MD |
245 | * Mutual exclusion can be ensured by holding cds_wfcq_dequeue_lock(). |
246 | * | |
247 | * For convenience, cds_wfcq_dequeue_blocking() and | |
248 | * cds_wfcq_splice_blocking() hold the dequeue lock. | |
1fe734e1 MD |
249 | * |
250 | * Besides locking, mutual exclusion of dequeue, splice and iteration | |
251 | * can be ensured by performing all of those operations from a single | |
252 | * thread, without requiring any lock. | |
8ad4ce58 MD |
253 | */ |
254 | ||
255 | /* | |
256 | * cds_wfcq_node_init: initialize wait-free queue node. | |
257 | */ | |
258 | extern void cds_wfcq_node_init(struct cds_wfcq_node *node); | |
259 | ||
260 | /* | |
200d100e MD |
261 | * cds_wfcq_init: initialize wait-free queue. Pair with |
262 | * cds_wfcq_destroy(). | |
8ad4ce58 MD |
263 | */ |
264 | extern void cds_wfcq_init(struct cds_wfcq_head *head, | |
265 | struct cds_wfcq_tail *tail); | |
266 | ||
f637f191 | 267 | /* |
200d100e MD |
268 | * cds_wfcq_destroy: destroy wait-free queue. Pair with |
269 | * cds_wfcq_init(). | |
270 | */ | |
271 | extern void cds_wfcq_destroy(struct cds_wfcq_head *head, | |
272 | struct cds_wfcq_tail *tail); | |
273 | ||
274 | /* | |
275 | * __cds_wfcq_init: initialize wait-free queue (without lock). Don't | |
276 | * pair with any destroy function. | |
f637f191 MD |
277 | */ |
278 | extern void __cds_wfcq_init(struct __cds_wfcq_head *head, | |
279 | struct cds_wfcq_tail *tail); | |
280 | ||
8ad4ce58 MD |
281 | /* |
282 | * cds_wfcq_empty: return whether wait-free queue is empty. | |
283 | * | |
284 | * No memory barrier is issued. No mutual exclusion is required. | |
285 | */ | |
c0775411 MD |
286 | extern bool cds_wfcq_empty(cds_wfcq_head_const_ptr_t head, |
287 | const struct cds_wfcq_tail *tail); | |
8ad4ce58 MD |
288 | |
289 | /* | |
290 | * cds_wfcq_dequeue_lock: take the dequeue mutual exclusion lock. | |
291 | */ | |
292 | extern void cds_wfcq_dequeue_lock(struct cds_wfcq_head *head, | |
293 | struct cds_wfcq_tail *tail); | |
294 | ||
295 | /* | |
296 | * cds_wfcq_dequeue_unlock: release the dequeue mutual exclusion lock. | |
297 | */ | |
298 | extern void cds_wfcq_dequeue_unlock(struct cds_wfcq_head *head, | |
299 | struct cds_wfcq_tail *tail); | |
300 | ||
301 | /* | |
302 | * cds_wfcq_enqueue: enqueue a node into a wait-free queue. | |
303 | * | |
304 | * Issues a full memory barrier before enqueue. No mutual exclusion is | |
305 | * required. | |
23773356 MD |
306 | * |
307 | * Returns false if the queue was empty prior to adding the node. | |
308 | * Returns true otherwise. | |
8ad4ce58 | 309 | */ |
f637f191 | 310 | extern bool cds_wfcq_enqueue(cds_wfcq_head_ptr_t head, |
8ad4ce58 MD |
311 | struct cds_wfcq_tail *tail, |
312 | struct cds_wfcq_node *node); | |
313 | ||
314 | /* | |
315 | * cds_wfcq_dequeue_blocking: dequeue a node from a wait-free queue. | |
316 | * | |
317 | * Content written into the node before enqueue is guaranteed to be | |
318 | * consistent, but no other memory ordering is ensured. | |
319 | * It is valid to reuse and free a dequeued node immediately. | |
ffa11a18 | 320 | * Mutual exclusion with cds_wfcq_dequeue_blocking and dequeue lock is |
1fe734e1 | 321 | * ensured. |
8ad4ce58 MD |
322 | */ |
323 | extern struct cds_wfcq_node *cds_wfcq_dequeue_blocking( | |
324 | struct cds_wfcq_head *head, | |
325 | struct cds_wfcq_tail *tail); | |
326 | ||
eec791af MD |
327 | /* |
328 | * cds_wfcq_dequeue_with_state_blocking: dequeue with state. | |
329 | * | |
330 | * Same as cds_wfcq_dequeue_blocking, but saves whether dequeueing the | |
331 | * last node of the queue into state (CDS_WFCQ_STATE_LAST). | |
332 | */ | |
333 | extern struct cds_wfcq_node *cds_wfcq_dequeue_with_state_blocking( | |
334 | struct cds_wfcq_head *head, | |
335 | struct cds_wfcq_tail *tail, | |
336 | int *state); | |
337 | ||
8ad4ce58 MD |
338 | /* |
339 | * cds_wfcq_splice_blocking: enqueue all src_q nodes at the end of dest_q. | |
340 | * | |
341 | * Dequeue all nodes from src_q. | |
342 | * dest_q must be already initialized. | |
343 | * Content written into the node before enqueue is guaranteed to be | |
344 | * consistent, but no other memory ordering is ensured. | |
ffa11a18 | 345 | * Mutual exclusion with cds_wfcq_dequeue_blocking and dequeue lock is |
1fe734e1 | 346 | * ensured. |
23773356 MD |
347 | * |
348 | * Returns enum cds_wfcq_ret which indicates the state of the src or | |
b94aaf6f | 349 | * dest queue. |
8ad4ce58 | 350 | */ |
23773356 | 351 | extern enum cds_wfcq_ret cds_wfcq_splice_blocking( |
8ad4ce58 MD |
352 | struct cds_wfcq_head *dest_q_head, |
353 | struct cds_wfcq_tail *dest_q_tail, | |
354 | struct cds_wfcq_head *src_q_head, | |
355 | struct cds_wfcq_tail *src_q_tail); | |
356 | ||
357 | /* | |
47215721 | 358 | * __cds_wfcq_dequeue_blocking: dequeue a node from a wait-free queue. |
8ad4ce58 MD |
359 | * |
360 | * Content written into the node before enqueue is guaranteed to be | |
361 | * consistent, but no other memory ordering is ensured. | |
362 | * It is valid to reuse and free a dequeued node immediately. | |
1fe734e1 MD |
363 | * Dequeue/splice/iteration mutual exclusion should be ensured by the |
364 | * caller. | |
8ad4ce58 MD |
365 | */ |
366 | extern struct cds_wfcq_node *__cds_wfcq_dequeue_blocking( | |
f637f191 | 367 | cds_wfcq_head_ptr_t head, |
8ad4ce58 MD |
368 | struct cds_wfcq_tail *tail); |
369 | ||
eec791af MD |
370 | /* |
371 | * __cds_wfcq_dequeue_with_state_blocking: dequeue with state. | |
372 | * | |
373 | * Same as __cds_wfcq_dequeue_blocking, but saves whether dequeueing the | |
374 | * last node of the queue into state (CDS_WFCQ_STATE_LAST). | |
375 | */ | |
376 | extern struct cds_wfcq_node *__cds_wfcq_dequeue_with_state_blocking( | |
f637f191 | 377 | cds_wfcq_head_ptr_t head, |
eec791af MD |
378 | struct cds_wfcq_tail *tail, |
379 | int *state); | |
380 | ||
47215721 MD |
381 | /* |
382 | * __cds_wfcq_dequeue_nonblocking: dequeue a node from a wait-free queue. | |
383 | * | |
384 | * Same as __cds_wfcq_dequeue_blocking, but returns CDS_WFCQ_WOULDBLOCK | |
385 | * if it needs to block. | |
386 | */ | |
387 | extern struct cds_wfcq_node *__cds_wfcq_dequeue_nonblocking( | |
f637f191 | 388 | cds_wfcq_head_ptr_t head, |
47215721 MD |
389 | struct cds_wfcq_tail *tail); |
390 | ||
eec791af MD |
391 | /* |
392 | * __cds_wfcq_dequeue_with_state_blocking: dequeue with state. | |
393 | * | |
394 | * Same as __cds_wfcq_dequeue_nonblocking, but saves whether dequeueing | |
395 | * the last node of the queue into state (CDS_WFCQ_STATE_LAST). | |
396 | */ | |
397 | extern struct cds_wfcq_node *__cds_wfcq_dequeue_with_state_nonblocking( | |
f637f191 | 398 | cds_wfcq_head_ptr_t head, |
eec791af MD |
399 | struct cds_wfcq_tail *tail, |
400 | int *state); | |
401 | ||
8ad4ce58 MD |
402 | /* |
403 | * __cds_wfcq_splice_blocking: enqueue all src_q nodes at the end of dest_q. | |
404 | * | |
405 | * Dequeue all nodes from src_q. | |
406 | * dest_q must be already initialized. | |
f878b49e MD |
407 | * Mutual exclusion for src_q should be ensured by the caller as |
408 | * specified in the "Synchronisation table". | |
23773356 | 409 | * Returns enum cds_wfcq_ret which indicates the state of the src or |
f878b49e | 410 | * dest queue. Never returns CDS_WFCQ_RET_WOULDBLOCK. |
8ad4ce58 | 411 | */ |
23773356 | 412 | extern enum cds_wfcq_ret __cds_wfcq_splice_blocking( |
f637f191 | 413 | cds_wfcq_head_ptr_t dest_q_head, |
8ad4ce58 | 414 | struct cds_wfcq_tail *dest_q_tail, |
f637f191 | 415 | cds_wfcq_head_ptr_t src_q_head, |
8ad4ce58 MD |
416 | struct cds_wfcq_tail *src_q_tail); |
417 | ||
47215721 MD |
418 | /* |
419 | * __cds_wfcq_splice_nonblocking: enqueue all src_q nodes at the end of dest_q. | |
420 | * | |
23773356 MD |
421 | * Same as __cds_wfcq_splice_blocking, but returns |
422 | * CDS_WFCQ_RET_WOULDBLOCK if it needs to block. | |
47215721 | 423 | */ |
23773356 | 424 | extern enum cds_wfcq_ret __cds_wfcq_splice_nonblocking( |
f637f191 | 425 | cds_wfcq_head_ptr_t dest_q_head, |
47215721 | 426 | struct cds_wfcq_tail *dest_q_tail, |
f637f191 | 427 | cds_wfcq_head_ptr_t src_q_head, |
47215721 MD |
428 | struct cds_wfcq_tail *src_q_tail); |
429 | ||
8ad4ce58 MD |
430 | /* |
431 | * __cds_wfcq_first_blocking: get first node of a queue, without dequeuing. | |
432 | * | |
433 | * Content written into the node before enqueue is guaranteed to be | |
434 | * consistent, but no other memory ordering is ensured. | |
1fe734e1 MD |
435 | * Dequeue/splice/iteration mutual exclusion should be ensured by the |
436 | * caller. | |
f94061a3 MD |
437 | * |
438 | * Used by for-like iteration macros: | |
439 | * __cds_wfcq_for_each_blocking() | |
440 | * __cds_wfcq_for_each_blocking_safe() | |
131a29a6 MD |
441 | * |
442 | * Returns NULL if queue is empty, first node otherwise. | |
8ad4ce58 MD |
443 | */ |
444 | extern struct cds_wfcq_node *__cds_wfcq_first_blocking( | |
f637f191 | 445 | cds_wfcq_head_ptr_t head, |
8ad4ce58 MD |
446 | struct cds_wfcq_tail *tail); |
447 | ||
47215721 MD |
448 | /* |
449 | * __cds_wfcq_first_nonblocking: get first node of a queue, without dequeuing. | |
450 | * | |
451 | * Same as __cds_wfcq_first_blocking, but returns CDS_WFCQ_WOULDBLOCK if | |
452 | * it needs to block. | |
453 | */ | |
454 | extern struct cds_wfcq_node *__cds_wfcq_first_nonblocking( | |
f637f191 | 455 | cds_wfcq_head_ptr_t head, |
47215721 MD |
456 | struct cds_wfcq_tail *tail); |
457 | ||
8ad4ce58 MD |
458 | /* |
459 | * __cds_wfcq_next_blocking: get next node of a queue, without dequeuing. | |
460 | * | |
461 | * Content written into the node before enqueue is guaranteed to be | |
462 | * consistent, but no other memory ordering is ensured. | |
1fe734e1 MD |
463 | * Dequeue/splice/iteration mutual exclusion should be ensured by the |
464 | * caller. | |
f94061a3 MD |
465 | * |
466 | * Used by for-like iteration macros: | |
467 | * __cds_wfcq_for_each_blocking() | |
468 | * __cds_wfcq_for_each_blocking_safe() | |
131a29a6 MD |
469 | * |
470 | * Returns NULL if reached end of queue, non-NULL next queue node | |
471 | * otherwise. | |
8ad4ce58 MD |
472 | */ |
473 | extern struct cds_wfcq_node *__cds_wfcq_next_blocking( | |
f637f191 | 474 | cds_wfcq_head_ptr_t head, |
8ad4ce58 MD |
475 | struct cds_wfcq_tail *tail, |
476 | struct cds_wfcq_node *node); | |
477 | ||
47215721 MD |
478 | /* |
479 | * __cds_wfcq_next_blocking: get next node of a queue, without dequeuing. | |
480 | * | |
481 | * Same as __cds_wfcq_next_blocking, but returns CDS_WFCQ_WOULDBLOCK if | |
482 | * it needs to block. | |
483 | */ | |
484 | extern struct cds_wfcq_node *__cds_wfcq_next_nonblocking( | |
f637f191 | 485 | cds_wfcq_head_ptr_t head, |
47215721 MD |
486 | struct cds_wfcq_tail *tail, |
487 | struct cds_wfcq_node *node); | |
488 | ||
8ad4ce58 MD |
489 | #endif /* !_LGPL_SOURCE */ |
490 | ||
491 | /* | |
492 | * __cds_wfcq_for_each_blocking: Iterate over all nodes in a queue, | |
493 | * without dequeuing them. | |
f637f191 | 494 | * @head: head of the queue (struct cds_wfcq_head or __cds_wfcq_head pointer). |
8ad4ce58 MD |
495 | * @tail: tail of the queue (struct cds_wfcq_tail pointer). |
496 | * @node: iterator on the queue (struct cds_wfcq_node pointer). | |
497 | * | |
498 | * Content written into each node before enqueue is guaranteed to be | |
499 | * consistent, but no other memory ordering is ensured. | |
1fe734e1 MD |
500 | * Dequeue/splice/iteration mutual exclusion should be ensured by the |
501 | * caller. | |
8ad4ce58 MD |
502 | */ |
503 | #define __cds_wfcq_for_each_blocking(head, tail, node) \ | |
504 | for (node = __cds_wfcq_first_blocking(head, tail); \ | |
505 | node != NULL; \ | |
506 | node = __cds_wfcq_next_blocking(head, tail, node)) | |
507 | ||
508 | /* | |
509 | * __cds_wfcq_for_each_blocking_safe: Iterate over all nodes in a queue, | |
510 | * without dequeuing them. Safe against deletion. | |
f637f191 | 511 | * @head: head of the queue (struct cds_wfcq_head or __cds_wfcq_head pointer). |
8ad4ce58 MD |
512 | * @tail: tail of the queue (struct cds_wfcq_tail pointer). |
513 | * @node: iterator on the queue (struct cds_wfcq_node pointer). | |
514 | * @n: struct cds_wfcq_node pointer holding the next pointer (used | |
515 | * internally). | |
516 | * | |
517 | * Content written into each node before enqueue is guaranteed to be | |
518 | * consistent, but no other memory ordering is ensured. | |
1fe734e1 MD |
519 | * Dequeue/splice/iteration mutual exclusion should be ensured by the |
520 | * caller. | |
8ad4ce58 MD |
521 | */ |
522 | #define __cds_wfcq_for_each_blocking_safe(head, tail, node, n) \ | |
523 | for (node = __cds_wfcq_first_blocking(head, tail), \ | |
524 | n = (node ? __cds_wfcq_next_blocking(head, tail, node) : NULL); \ | |
525 | node != NULL; \ | |
526 | node = n, n = (node ? __cds_wfcq_next_blocking(head, tail, node) : NULL)) | |
527 | ||
528 | #ifdef __cplusplus | |
529 | } | |
0cdbb569 MD |
530 | |
531 | /* | |
532 | * In C++, implement static inline wrappers using function overloading | |
533 | * to obtain an API similar to C. | |
534 | */ | |
535 | ||
aaf0064b MD |
536 | static inline cds_wfcq_head_ptr_t cds_wfcq_head_cast_cpp(struct __cds_wfcq_head *head) |
537 | { | |
538 | cds_wfcq_head_ptr_t ret = { ._h = head }; | |
539 | return ret; | |
540 | } | |
541 | ||
542 | static inline cds_wfcq_head_ptr_t cds_wfcq_head_cast_cpp(struct cds_wfcq_head *head) | |
543 | { | |
544 | cds_wfcq_head_ptr_t ret = { .h = head }; | |
545 | return ret; | |
546 | } | |
547 | ||
c0775411 MD |
548 | static inline cds_wfcq_head_const_ptr_t cds_wfcq_head_const_cast_cpp(const struct __cds_wfcq_head *head) |
549 | { | |
550 | cds_wfcq_head_const_ptr_t ret = { ._h = head }; | |
551 | return ret; | |
552 | } | |
553 | ||
554 | static inline cds_wfcq_head_const_ptr_t cds_wfcq_head_const_cast_cpp(const struct cds_wfcq_head *head) | |
555 | { | |
556 | cds_wfcq_head_const_ptr_t ret = { .h = head }; | |
557 | return ret; | |
558 | } | |
559 | ||
ee990cac | 560 | template<typename T> static inline bool cds_wfcq_empty(T head, |
c0775411 | 561 | const struct cds_wfcq_tail *tail) |
0cdbb569 | 562 | { |
c0775411 | 563 | return cds_wfcq_empty(cds_wfcq_head_const_cast_cpp(head), tail); |
0cdbb569 MD |
564 | } |
565 | ||
ee990cac | 566 | template<typename T> static inline bool cds_wfcq_enqueue(T head, |
0cdbb569 MD |
567 | struct cds_wfcq_tail *tail, |
568 | struct cds_wfcq_node *node) | |
569 | { | |
aaf0064b | 570 | return cds_wfcq_enqueue(cds_wfcq_head_cast_cpp(head), tail, node); |
0cdbb569 MD |
571 | } |
572 | ||
ee990cac MD |
573 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_dequeue_blocking( |
574 | T head, struct cds_wfcq_tail *tail) | |
0cdbb569 | 575 | { |
aaf0064b | 576 | return __cds_wfcq_dequeue_blocking(cds_wfcq_head_cast_cpp(head), tail); |
0cdbb569 MD |
577 | } |
578 | ||
ee990cac MD |
579 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_dequeue_with_state_blocking( |
580 | T head, struct cds_wfcq_tail *tail, int *state) | |
0cdbb569 | 581 | { |
aaf0064b | 582 | return __cds_wfcq_dequeue_with_state_blocking(cds_wfcq_head_cast_cpp(head), |
0cdbb569 MD |
583 | tail, state); |
584 | } | |
585 | ||
ee990cac MD |
586 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_dequeue_nonblocking( |
587 | T head, struct cds_wfcq_tail *tail) | |
0cdbb569 | 588 | { |
aaf0064b | 589 | return __cds_wfcq_dequeue_nonblocking(cds_wfcq_head_cast_cpp(head), tail); |
0cdbb569 MD |
590 | } |
591 | ||
ee990cac MD |
592 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_dequeue_with_state_nonblocking( |
593 | T head, struct cds_wfcq_tail *tail, int *state) | |
0cdbb569 | 594 | { |
aaf0064b | 595 | return __cds_wfcq_dequeue_with_state_nonblocking(cds_wfcq_head_cast_cpp(head), |
0cdbb569 MD |
596 | tail, state); |
597 | } | |
598 | ||
ee990cac MD |
599 | template<typename T, typename U> static inline enum cds_wfcq_ret __cds_wfcq_splice_blocking( |
600 | T dest_q_head, | |
0cdbb569 | 601 | struct cds_wfcq_tail *dest_q_tail, |
ee990cac | 602 | U src_q_head, |
0cdbb569 MD |
603 | struct cds_wfcq_tail *src_q_tail) |
604 | { | |
aaf0064b | 605 | return __cds_wfcq_splice_blocking(cds_wfcq_head_cast_cpp(dest_q_head), |
0cdbb569 | 606 | dest_q_tail, |
aaf0064b | 607 | cds_wfcq_head_cast_cpp(src_q_head), |
0cdbb569 MD |
608 | src_q_tail); |
609 | } | |
610 | ||
ee990cac MD |
611 | template<typename T, typename U> static inline enum cds_wfcq_ret __cds_wfcq_splice_nonblocking( |
612 | T dest_q_head, | |
0cdbb569 | 613 | struct cds_wfcq_tail *dest_q_tail, |
ee990cac | 614 | U *src_q_head, |
0cdbb569 MD |
615 | struct cds_wfcq_tail *src_q_tail) |
616 | { | |
aaf0064b | 617 | return __cds_wfcq_splice_nonblocking(cds_wfcq_head_cast_cpp(dest_q_head), |
0cdbb569 | 618 | dest_q_tail, |
aaf0064b | 619 | cds_wfcq_head_cast_cpp(src_q_head), |
0cdbb569 MD |
620 | src_q_tail); |
621 | } | |
622 | ||
ee990cac MD |
623 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_first_blocking( |
624 | T head, struct cds_wfcq_tail *tail) | |
0cdbb569 | 625 | { |
aaf0064b | 626 | return __cds_wfcq_first_blocking(cds_wfcq_head_cast_cpp(head), tail); |
0cdbb569 MD |
627 | } |
628 | ||
ee990cac MD |
629 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_first_nonblocking( |
630 | T head, struct cds_wfcq_tail *tail) | |
0cdbb569 | 631 | { |
aaf0064b | 632 | return __cds_wfcq_first_nonblocking(cds_wfcq_head_cast_cpp(head), tail); |
0cdbb569 MD |
633 | } |
634 | ||
ee990cac MD |
635 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_next_blocking( |
636 | T head, | |
0cdbb569 MD |
637 | struct cds_wfcq_tail *tail, |
638 | struct cds_wfcq_node *node) | |
639 | { | |
aaf0064b | 640 | return __cds_wfcq_next_blocking(cds_wfcq_head_cast_cpp(head), tail, node); |
0cdbb569 MD |
641 | } |
642 | ||
ee990cac MD |
643 | template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_next_nonblocking( |
644 | T head, | |
0cdbb569 MD |
645 | struct cds_wfcq_tail *tail, |
646 | struct cds_wfcq_node *node) | |
647 | { | |
aaf0064b | 648 | return __cds_wfcq_next_nonblocking(cds_wfcq_head_cast_cpp(head), tail, node); |
0cdbb569 MD |
649 | } |
650 | ||
8ad4ce58 MD |
651 | #endif |
652 | ||
653 | #endif /* _URCU_WFCQUEUE_H */ |