1 // SPDX-FileCopyrightText: 2010-2012 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com> 2 // SPDX-FileCopyrightText: 2011-2012 Lai Jiangshan <laijs (at) cn.fujitsu.com> 3 // 4 // SPDX-License-Identifier: LGPL-2.1-or-later 5 6 #ifndef _URCU_WFCQUEUE_H 7 #define _URCU_WFCQUEUE_H 8 9 /* 10 * Userspace RCU library - Concurrent Queue with Wait-Free Enqueue/Blocking Dequeue 11 */ 12 13 #include <pthread.h> 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 * 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. 29 */ 30 31 #define CDS_WFCQ_WOULDBLOCK ((struct cds_wfcq_node *) -1UL) 32 33 enum cds_wfcq_ret { 34 CDS_WFCQ_RET_WOULDBLOCK = -1, 35 CDS_WFCQ_RET_DEST_EMPTY = 0, 36 CDS_WFCQ_RET_DEST_NON_EMPTY = 1, 37 CDS_WFCQ_RET_SRC_EMPTY = 2, 38 }; 39 40 enum cds_wfcq_state { 41 CDS_WFCQ_STATE_LAST = (1U << 0), 42 }; 43 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 */ 53 struct __cds_wfcq_head { 54 struct cds_wfcq_node node; 55 }; 56 57 struct cds_wfcq_head { 58 struct cds_wfcq_node node; 59 pthread_mutex_t lock; 60 }; 61 62 /* 63 * In C, the transparent union allows calling functions that work on both 64 * struct cds_wfcq_head and struct __cds_wfcq_head on any of those two 65 * types. 66 * 67 * In C++, implement static inline wrappers using function overloading 68 * to obtain an API similar to C. 69 * 70 * Avoid complaints from clang++ not knowing the transparent union 71 * attribute. 72 */ 73 #if defined(__clang__) 74 #pragma clang diagnostic push 75 #pragma clang diagnostic ignored "-Wignored-attributes" 76 #endif 77 typedef union { 78 struct __cds_wfcq_head *_h; 79 struct cds_wfcq_head *h; 80 } __attribute__((__transparent_union__)) cds_wfcq_head_ptr_t; 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; 86 #if defined(__clang__) 87 #pragma clang diagnostic pop 88 #endif 89 90 #ifndef __cplusplus 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 } 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 127 #else /* #ifndef __cplusplus */ 128 129 /* 130 * This static inline is used by internally in the static inline 131 * implementation of the API. 132 */ 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 } 138 139 /* 140 * This static inline is used by internally in the static inline 141 * implementation of the API. 142 */ 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 } 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 169 #endif /* #else #ifndef __cplusplus */ 170 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 181 #define __cds_wfcq_init ___cds_wfcq_init 182 #define cds_wfcq_destroy _cds_wfcq_destroy 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 192 #define cds_wfcq_dequeue_with_state_blocking \ 193 _cds_wfcq_dequeue_with_state_blocking 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 200 #define __cds_wfcq_dequeue_with_state_blocking \ 201 ___cds_wfcq_dequeue_with_state_blocking 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 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 212 #define __cds_wfcq_dequeue_with_state_nonblocking \ 213 ___cds_wfcq_dequeue_with_state_nonblocking 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 218 #else /* !_LGPL_SOURCE */ 219 220 /* 221 * Mutual exclusion of cds_wfcq_* / __cds_wfcq_* API 222 * 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 * 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. 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. 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 /* 261 * cds_wfcq_init: initialize wait-free queue. Pair with 262 * cds_wfcq_destroy(). 263 */ 264 extern void cds_wfcq_init(struct cds_wfcq_head *head, 265 struct cds_wfcq_tail *tail); 266 267 /* 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. 277 */ 278 extern void __cds_wfcq_init(struct __cds_wfcq_head *head, 279 struct cds_wfcq_tail *tail); 280 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 */ 286 extern bool cds_wfcq_empty(cds_wfcq_head_const_ptr_t head, 287 const struct cds_wfcq_tail *tail); 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. 306 * 307 * Returns false if the queue was empty prior to adding the node. 308 * Returns true otherwise. 309 */ 310 extern bool cds_wfcq_enqueue(cds_wfcq_head_ptr_t head, 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. 320 * Mutual exclusion with cds_wfcq_dequeue_blocking and dequeue lock is 321 * ensured. 322 */ 323 extern struct cds_wfcq_node *cds_wfcq_dequeue_blocking( 324 struct cds_wfcq_head *head, 325 struct cds_wfcq_tail *tail); 326 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 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. 345 * Mutual exclusion with cds_wfcq_dequeue_blocking and dequeue lock is 346 * ensured. 347 * 348 * Returns enum cds_wfcq_ret which indicates the state of the src or 349 * dest queue. 350 */ 351 extern enum cds_wfcq_ret cds_wfcq_splice_blocking( 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 /* 358 * __cds_wfcq_dequeue_blocking: dequeue a node from a wait-free queue. 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. 363 * Dequeue/splice/iteration mutual exclusion should be ensured by the 364 * caller. 365 */ 366 extern struct cds_wfcq_node *__cds_wfcq_dequeue_blocking( 367 cds_wfcq_head_ptr_t head, 368 struct cds_wfcq_tail *tail); 369 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( 377 cds_wfcq_head_ptr_t head, 378 struct cds_wfcq_tail *tail, 379 int *state); 380 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( 388 cds_wfcq_head_ptr_t head, 389 struct cds_wfcq_tail *tail); 390 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( 398 cds_wfcq_head_ptr_t head, 399 struct cds_wfcq_tail *tail, 400 int *state); 401 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. 407 * Mutual exclusion for src_q should be ensured by the caller as 408 * specified in the "Synchronisation table". 409 * Returns enum cds_wfcq_ret which indicates the state of the src or 410 * dest queue. Never returns CDS_WFCQ_RET_WOULDBLOCK. 411 */ 412 extern enum cds_wfcq_ret __cds_wfcq_splice_blocking( 413 cds_wfcq_head_ptr_t dest_q_head, 414 struct cds_wfcq_tail *dest_q_tail, 415 cds_wfcq_head_ptr_t src_q_head, 416 struct cds_wfcq_tail *src_q_tail); 417 418 /* 419 * __cds_wfcq_splice_nonblocking: enqueue all src_q nodes at the end of dest_q. 420 * 421 * Same as __cds_wfcq_splice_blocking, but returns 422 * CDS_WFCQ_RET_WOULDBLOCK if it needs to block. 423 */ 424 extern enum cds_wfcq_ret __cds_wfcq_splice_nonblocking( 425 cds_wfcq_head_ptr_t dest_q_head, 426 struct cds_wfcq_tail *dest_q_tail, 427 cds_wfcq_head_ptr_t src_q_head, 428 struct cds_wfcq_tail *src_q_tail); 429 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. 435 * Dequeue/splice/iteration mutual exclusion should be ensured by the 436 * caller. 437 * 438 * Used by for-like iteration macros: 439 * __cds_wfcq_for_each_blocking() 440 * __cds_wfcq_for_each_blocking_safe() 441 * 442 * Returns NULL if queue is empty, first node otherwise. 443 */ 444 extern struct cds_wfcq_node *__cds_wfcq_first_blocking( 445 cds_wfcq_head_ptr_t head, 446 struct cds_wfcq_tail *tail); 447 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( 455 cds_wfcq_head_ptr_t head, 456 struct cds_wfcq_tail *tail); 457 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. 463 * Dequeue/splice/iteration mutual exclusion should be ensured by the 464 * caller. 465 * 466 * Used by for-like iteration macros: 467 * __cds_wfcq_for_each_blocking() 468 * __cds_wfcq_for_each_blocking_safe() 469 * 470 * Returns NULL if reached end of queue, non-NULL next queue node 471 * otherwise. 472 */ 473 extern struct cds_wfcq_node *__cds_wfcq_next_blocking( 474 cds_wfcq_head_ptr_t head, 475 struct cds_wfcq_tail *tail, 476 struct cds_wfcq_node *node); 477 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( 485 cds_wfcq_head_ptr_t head, 486 struct cds_wfcq_tail *tail, 487 struct cds_wfcq_node *node); 488 489 #endif /* !_LGPL_SOURCE */ 490 491 /* 492 * __cds_wfcq_for_each_blocking: Iterate over all nodes in a queue, 493 * without dequeuing them. 494 * @head: head of the queue (struct cds_wfcq_head or __cds_wfcq_head pointer). 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. 500 * Dequeue/splice/iteration mutual exclusion should be ensured by the 501 * caller. 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. 511 * @head: head of the queue (struct cds_wfcq_head or __cds_wfcq_head pointer). 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. 519 * Dequeue/splice/iteration mutual exclusion should be ensured by the 520 * caller. 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 } 530 531 /* 532 * In C++, implement static inline wrappers using function overloading 533 * to obtain an API similar to C. 534 */ 535 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 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 560 template<typename T> static inline bool cds_wfcq_empty(T head, 561 const struct cds_wfcq_tail *tail) 562 { 563 return cds_wfcq_empty(cds_wfcq_head_const_cast_cpp(head), tail); 564 } 565 566 template<typename T> static inline bool cds_wfcq_enqueue(T head, 567 struct cds_wfcq_tail *tail, 568 struct cds_wfcq_node *node) 569 { 570 return cds_wfcq_enqueue(cds_wfcq_head_cast_cpp(head), tail, node); 571 } 572 573 template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_dequeue_blocking( 574 T head, struct cds_wfcq_tail *tail) 575 { 576 return __cds_wfcq_dequeue_blocking(cds_wfcq_head_cast_cpp(head), tail); 577 } 578 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) 581 { 582 return __cds_wfcq_dequeue_with_state_blocking(cds_wfcq_head_cast_cpp(head), 583 tail, state); 584 } 585 586 template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_dequeue_nonblocking( 587 T head, struct cds_wfcq_tail *tail) 588 { 589 return __cds_wfcq_dequeue_nonblocking(cds_wfcq_head_cast_cpp(head), tail); 590 } 591 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) 594 { 595 return __cds_wfcq_dequeue_with_state_nonblocking(cds_wfcq_head_cast_cpp(head), 596 tail, state); 597 } 598 599 template<typename T, typename U> static inline enum cds_wfcq_ret __cds_wfcq_splice_blocking( 600 T dest_q_head, 601 struct cds_wfcq_tail *dest_q_tail, 602 U src_q_head, 603 struct cds_wfcq_tail *src_q_tail) 604 { 605 return __cds_wfcq_splice_blocking(cds_wfcq_head_cast_cpp(dest_q_head), 606 dest_q_tail, 607 cds_wfcq_head_cast_cpp(src_q_head), 608 src_q_tail); 609 } 610 611 template<typename T, typename U> static inline enum cds_wfcq_ret __cds_wfcq_splice_nonblocking( 612 T dest_q_head, 613 struct cds_wfcq_tail *dest_q_tail, 614 U *src_q_head, 615 struct cds_wfcq_tail *src_q_tail) 616 { 617 return __cds_wfcq_splice_nonblocking(cds_wfcq_head_cast_cpp(dest_q_head), 618 dest_q_tail, 619 cds_wfcq_head_cast_cpp(src_q_head), 620 src_q_tail); 621 } 622 623 template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_first_blocking( 624 T head, struct cds_wfcq_tail *tail) 625 { 626 return __cds_wfcq_first_blocking(cds_wfcq_head_cast_cpp(head), tail); 627 } 628 629 template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_first_nonblocking( 630 T head, struct cds_wfcq_tail *tail) 631 { 632 return __cds_wfcq_first_nonblocking(cds_wfcq_head_cast_cpp(head), tail); 633 } 634 635 template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_next_blocking( 636 T head, 637 struct cds_wfcq_tail *tail, 638 struct cds_wfcq_node *node) 639 { 640 return __cds_wfcq_next_blocking(cds_wfcq_head_cast_cpp(head), tail, node); 641 } 642 643 template<typename T> static inline struct cds_wfcq_node *__cds_wfcq_next_nonblocking( 644 T head, 645 struct cds_wfcq_tail *tail, 646 struct cds_wfcq_node *node) 647 { 648 return __cds_wfcq_next_nonblocking(cds_wfcq_head_cast_cpp(head), tail, node); 649 } 650 651 #endif 652 653 #endif /* _URCU_WFCQUEUE_H */ 654