1 1.1 christos // SPDX-FileCopyrightText: 2010-2012 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com> 2 1.1 christos // SPDX-FileCopyrightText: 2011-2012 Lai Jiangshan <laijs (at) cn.fujitsu.com> 3 1.1 christos // 4 1.1 christos // SPDX-License-Identifier: LGPL-2.1-or-later 5 1.1 christos 6 1.1 christos #ifndef _URCU_WFCQUEUE_STATIC_H 7 1.1 christos #define _URCU_WFCQUEUE_STATIC_H 8 1.1 christos 9 1.1 christos /* 10 1.1 christos * Userspace RCU library - Concurrent Queue with Wait-Free Enqueue/Blocking Dequeue 11 1.1 christos * 12 1.1 christos * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See urcu/wfcqueue.h for 13 1.1 christos * linking dynamically with the userspace rcu library. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos #include <pthread.h> 17 1.1 christos #include <poll.h> 18 1.1 christos #include <stdbool.h> 19 1.1 christos #include <urcu/assert.h> 20 1.1 christos #include <urcu/compiler.h> 21 1.1 christos #include <urcu/uatomic.h> 22 1.1 christos 23 1.1 christos #ifdef __cplusplus 24 1.1 christos extern "C" { 25 1.1 christos #endif 26 1.1 christos 27 1.1 christos /* 28 1.1 christos * Concurrent queue with wait-free enqueue/blocking dequeue. 29 1.1 christos * 30 1.1 christos * This queue has been designed and implemented collaboratively by 31 1.1 christos * Mathieu Desnoyers and Lai Jiangshan. Inspired from 32 1.1 christos * half-wait-free/half-blocking queue implementation done by Paul E. 33 1.1 christos * McKenney. 34 1.1 christos * 35 1.1 christos * Mutual exclusion of cds_wfcq_* / __cds_wfcq_* API 36 1.1 christos * 37 1.1 christos * Synchronization table: 38 1.1 christos * 39 1.1 christos * External synchronization techniques described in the API below is 40 1.1 christos * required between pairs marked with "X". No external synchronization 41 1.1 christos * required between pairs marked with "-". 42 1.1 christos * 43 1.1 christos * Legend: 44 1.1 christos * [1] cds_wfcq_enqueue 45 1.1 christos * [2] __cds_wfcq_splice (destination queue) 46 1.1 christos * [3] __cds_wfcq_dequeue 47 1.1 christos * [4] __cds_wfcq_splice (source queue) 48 1.1 christos * [5] __cds_wfcq_first 49 1.1 christos * [6] __cds_wfcq_next 50 1.1 christos * 51 1.1 christos * [1] [2] [3] [4] [5] [6] 52 1.1 christos * [1] - - - - - - 53 1.1 christos * [2] - - - - - - 54 1.1 christos * [3] - - X X X X 55 1.1 christos * [4] - - X - X X 56 1.1 christos * [5] - - X X - - 57 1.1 christos * [6] - - X X - - 58 1.1 christos * 59 1.1 christos * Mutual exclusion can be ensured by holding cds_wfcq_dequeue_lock(). 60 1.1 christos * 61 1.1 christos * For convenience, cds_wfcq_dequeue_blocking() and 62 1.1 christos * cds_wfcq_splice_blocking() hold the dequeue lock. 63 1.1 christos * 64 1.1 christos * Besides locking, mutual exclusion of dequeue, splice and iteration 65 1.1 christos * can be ensured by performing all of those operations from a single 66 1.1 christos * thread, without requiring any lock. 67 1.1 christos */ 68 1.1 christos 69 1.1 christos #define WFCQ_ADAPT_ATTEMPTS 10 /* Retry if being set */ 70 1.1 christos #define WFCQ_WAIT 10 /* Wait 10 ms if being set */ 71 1.1 christos 72 1.1 christos /* 73 1.1 christos * cds_wfcq_node_init: initialize wait-free queue node. 74 1.1 christos */ 75 1.1 christos static inline void _cds_wfcq_node_init(struct cds_wfcq_node *node) 76 1.1 christos { 77 1.1 christos node->next = NULL; 78 1.1 christos } 79 1.1 christos 80 1.1 christos static inline void _cds_wfcq_node_init_atomic(struct cds_wfcq_node *node) 81 1.1 christos { 82 1.1 christos uatomic_store(&node->next, NULL, CMM_RELAXED); 83 1.1 christos } 84 1.1 christos 85 1.1 christos /* 86 1.1 christos * cds_wfcq_init: initialize wait-free queue (with lock). Pair with 87 1.1 christos * cds_wfcq_destroy(). 88 1.1 christos */ 89 1.1 christos static inline void _cds_wfcq_init(struct cds_wfcq_head *head, 90 1.1 christos struct cds_wfcq_tail *tail) 91 1.1 christos { 92 1.1 christos int ret; 93 1.1 christos 94 1.1 christos /* Set queue head and tail */ 95 1.1 christos _cds_wfcq_node_init(&head->node); 96 1.1 christos tail->p = &head->node; 97 1.1 christos ret = pthread_mutex_init(&head->lock, NULL); 98 1.1 christos urcu_posix_assert(!ret); 99 1.1 christos } 100 1.1 christos 101 1.1 christos /* 102 1.1 christos * cds_wfcq_destroy: destroy wait-free queue (with lock). Pair with 103 1.1 christos * cds_wfcq_init(). 104 1.1 christos */ 105 1.1 christos static inline void _cds_wfcq_destroy(struct cds_wfcq_head *head, 106 1.1 christos struct cds_wfcq_tail *tail __attribute__((unused))) 107 1.1 christos { 108 1.1 christos int ret = pthread_mutex_destroy(&head->lock); 109 1.1 christos urcu_posix_assert(!ret); 110 1.1 christos } 111 1.1 christos 112 1.1 christos /* 113 1.1 christos * __cds_wfcq_init: initialize wait-free queue (without lock). Don't 114 1.1 christos * pair with any destroy function. 115 1.1 christos */ 116 1.1 christos static inline void ___cds_wfcq_init(struct __cds_wfcq_head *head, 117 1.1 christos struct cds_wfcq_tail *tail) 118 1.1 christos { 119 1.1 christos /* Set queue head and tail */ 120 1.1 christos _cds_wfcq_node_init(&head->node); 121 1.1 christos tail->p = &head->node; 122 1.1 christos } 123 1.1 christos 124 1.1 christos /* 125 1.1 christos * cds_wfcq_empty: return whether wait-free queue is empty. 126 1.1 christos * 127 1.1 christos * No memory barrier is issued. No mutual exclusion is required. 128 1.1 christos * 129 1.1 christos * We perform the test on head->node.next to check if the queue is 130 1.1 christos * possibly empty, but we confirm this by checking if the tail pointer 131 1.1 christos * points to the head node because the tail pointer is the linearisation 132 1.1 christos * point of the enqueuers. Just checking the head next pointer could 133 1.1 christos * make a queue appear empty if an enqueuer is preempted for a long time 134 1.1 christos * between xchg() and setting the previous node's next pointer. 135 1.1 christos */ 136 1.1 christos static inline bool _cds_wfcq_empty(cds_wfcq_head_const_ptr_t u_head, 137 1.1 christos const struct cds_wfcq_tail *tail) 138 1.1 christos { 139 1.1 christos const struct __cds_wfcq_head *head = u_head._h; 140 1.1 christos /* 141 1.1 christos * Queue is empty if no node is pointed by head->node.next nor 142 1.1 christos * tail->p. Even though the tail->p check is sufficient to find 143 1.1 christos * out of the queue is empty, we first check head->node.next as a 144 1.1 christos * common case to ensure that dequeuers do not frequently access 145 1.1 christos * enqueuer's tail->p cache line. 146 1.1 christos */ 147 1.1 christos return uatomic_load(&head->node.next, CMM_CONSUME) == NULL 148 1.1 christos && uatomic_load(&tail->p, CMM_CONSUME) == &head->node; 149 1.1 christos } 150 1.1 christos 151 1.1 christos static inline void _cds_wfcq_dequeue_lock(struct cds_wfcq_head *head, 152 1.1 christos struct cds_wfcq_tail *tail __attribute__((unused))) 153 1.1 christos { 154 1.1 christos int ret; 155 1.1 christos 156 1.1 christos ret = pthread_mutex_lock(&head->lock); 157 1.1 christos urcu_posix_assert(!ret); 158 1.1 christos } 159 1.1 christos 160 1.1 christos static inline void _cds_wfcq_dequeue_unlock(struct cds_wfcq_head *head, 161 1.1 christos struct cds_wfcq_tail *tail __attribute__((unused))) 162 1.1 christos { 163 1.1 christos int ret; 164 1.1 christos 165 1.1 christos ret = pthread_mutex_unlock(&head->lock); 166 1.1 christos urcu_posix_assert(!ret); 167 1.1 christos } 168 1.1 christos 169 1.1 christos static inline bool ___cds_wfcq_append(cds_wfcq_head_ptr_t u_head, 170 1.1 christos struct cds_wfcq_tail *tail, 171 1.1 christos struct cds_wfcq_node *new_head, 172 1.1 christos struct cds_wfcq_node *new_tail) 173 1.1 christos { 174 1.1 christos struct __cds_wfcq_head *head = u_head._h; 175 1.1 christos struct cds_wfcq_node *old_tail; 176 1.1 christos 177 1.1 christos /* 178 1.1 christos * Implicit memory barrier before uatomic_xchg() orders earlier 179 1.1 christos * stores to data structure containing node and setting 180 1.1 christos * node->next to NULL before publication. 181 1.1 christos */ 182 1.1 christos old_tail = uatomic_xchg_mo(&tail->p, new_tail, CMM_SEQ_CST); 183 1.1 christos 184 1.1 christos /* 185 1.1 christos * Implicit memory barrier after uatomic_xchg() orders store to 186 1.1 christos * q->tail before store to old_tail->next. 187 1.1 christos * 188 1.1 christos * At this point, dequeuers see a NULL tail->p->next, which 189 1.1 christos * indicates that the queue is being appended to. The following 190 1.1 christos * store will append "node" to the queue from a dequeuer 191 1.1 christos * perspective. 192 1.1 christos */ 193 1.1 christos uatomic_store(&old_tail->next, new_head, CMM_RELEASE); 194 1.1 christos 195 1.1 christos /* 196 1.1 christos * Return false if queue was empty prior to adding the node, 197 1.1 christos * else return true. 198 1.1 christos */ 199 1.1 christos return old_tail != &head->node; 200 1.1 christos } 201 1.1 christos 202 1.1 christos /* 203 1.1 christos * cds_wfcq_enqueue: enqueue a node into a wait-free queue. 204 1.1 christos * 205 1.1 christos * Operations prior to enqueue are consistant with respect to dequeuing or 206 1.1 christos * splicing and iterating. 207 1.1 christos * 208 1.1 christos * Returns false if the queue was empty prior to adding the node. 209 1.1 christos * Returns true otherwise. 210 1.1 christos */ 211 1.1 christos static inline bool _cds_wfcq_enqueue(cds_wfcq_head_ptr_t head, 212 1.1 christos struct cds_wfcq_tail *tail, 213 1.1 christos struct cds_wfcq_node *new_tail) 214 1.1 christos { 215 1.1 christos cmm_emit_legacy_smp_mb(); 216 1.1 christos 217 1.1 christos return ___cds_wfcq_append(head, tail, new_tail, new_tail); 218 1.1 christos } 219 1.1 christos 220 1.1 christos /* 221 1.1 christos * CDS_WFCQ_WAIT_SLEEP: 222 1.1 christos * 223 1.1 christos * By default, this sleeps for the given @msec milliseconds. 224 1.1 christos * This is a macro which LGPL users may #define themselves before 225 1.1 christos * including wfcqueue.h to override the default behavior (e.g. 226 1.1 christos * to log a warning or perform other background work). 227 1.1 christos */ 228 1.1 christos #ifndef CDS_WFCQ_WAIT_SLEEP 229 1.1 christos #define CDS_WFCQ_WAIT_SLEEP(msec) ___cds_wfcq_wait_sleep(msec) 230 1.1 christos #endif 231 1.1 christos 232 1.1 christos static inline void ___cds_wfcq_wait_sleep(int msec) 233 1.1 christos { 234 1.1 christos (void) poll(NULL, 0, msec); 235 1.1 christos } 236 1.1 christos 237 1.1 christos /* 238 1.1 christos * ___cds_wfcq_busy_wait: adaptative busy-wait. 239 1.1 christos * 240 1.1 christos * Returns 1 if nonblocking and needs to block, 0 otherwise. 241 1.1 christos */ 242 1.1 christos static inline bool 243 1.1 christos ___cds_wfcq_busy_wait(int *attempt, int blocking) 244 1.1 christos { 245 1.1 christos if (!blocking) 246 1.1 christos return 1; 247 1.1 christos if (++(*attempt) >= WFCQ_ADAPT_ATTEMPTS) { 248 1.1 christos CDS_WFCQ_WAIT_SLEEP(WFCQ_WAIT); /* Wait for 10ms */ 249 1.1 christos *attempt = 0; 250 1.1 christos } else { 251 1.1 christos caa_cpu_relax(); 252 1.1 christos } 253 1.1 christos return 0; 254 1.1 christos } 255 1.1 christos 256 1.1 christos /* 257 1.1 christos * Waiting for enqueuer to complete enqueue and return the next node. 258 1.1 christos */ 259 1.1 christos static inline struct cds_wfcq_node * 260 1.1 christos ___cds_wfcq_node_sync_next(struct cds_wfcq_node *node, int blocking) 261 1.1 christos { 262 1.1 christos struct cds_wfcq_node *next; 263 1.1 christos int attempt = 0; 264 1.1 christos 265 1.1 christos /* 266 1.1 christos * Adaptative busy-looping waiting for enqueuer to complete enqueue. 267 1.1 christos * 268 1.1 christos * Load node.next before loading node's content 269 1.1 christos */ 270 1.1 christos while ((next = uatomic_load(&node->next, CMM_CONSUME)) == NULL) { 271 1.1 christos if (___cds_wfcq_busy_wait(&attempt, blocking)) 272 1.1 christos return CDS_WFCQ_WOULDBLOCK; 273 1.1 christos } 274 1.1 christos 275 1.1 christos return next; 276 1.1 christos } 277 1.1 christos 278 1.1 christos static inline struct cds_wfcq_node * 279 1.1 christos ___cds_wfcq_first(cds_wfcq_head_ptr_t u_head, 280 1.1 christos struct cds_wfcq_tail *tail, 281 1.1 christos int blocking) 282 1.1 christos { 283 1.1 christos struct __cds_wfcq_head *head = u_head._h; 284 1.1 christos struct cds_wfcq_node *node; 285 1.1 christos 286 1.1 christos if (_cds_wfcq_empty(__cds_wfcq_head_const_cast(head), tail)) 287 1.1 christos return NULL; 288 1.1 christos node = ___cds_wfcq_node_sync_next(&head->node, blocking); 289 1.1 christos 290 1.1 christos return node; 291 1.1 christos } 292 1.1 christos 293 1.1 christos /* 294 1.1 christos * __cds_wfcq_first_blocking: get first node of a queue, without dequeuing. 295 1.1 christos * 296 1.1 christos * Content written into the node before enqueue is guaranteed to be 297 1.1 christos * consistent, but no other memory ordering is ensured. 298 1.1 christos * Dequeue/splice/iteration mutual exclusion should be ensured by the 299 1.1 christos * caller. 300 1.1 christos * 301 1.1 christos * Used by for-like iteration macros in urcu/wfqueue.h: 302 1.1 christos * __cds_wfcq_for_each_blocking() 303 1.1 christos * __cds_wfcq_for_each_blocking_safe() 304 1.1 christos * 305 1.1 christos * Returns NULL if queue is empty, first node otherwise. 306 1.1 christos */ 307 1.1 christos static inline struct cds_wfcq_node * 308 1.1 christos ___cds_wfcq_first_blocking(cds_wfcq_head_ptr_t head, 309 1.1 christos struct cds_wfcq_tail *tail) 310 1.1 christos { 311 1.1 christos return ___cds_wfcq_first(head, tail, 1); 312 1.1 christos } 313 1.1 christos 314 1.1 christos 315 1.1 christos /* 316 1.1 christos * __cds_wfcq_first_nonblocking: get first node of a queue, without dequeuing. 317 1.1 christos * 318 1.1 christos * Same as __cds_wfcq_first_blocking, but returns CDS_WFCQ_WOULDBLOCK if 319 1.1 christos * it needs to block. 320 1.1 christos */ 321 1.1 christos static inline struct cds_wfcq_node * 322 1.1 christos ___cds_wfcq_first_nonblocking(cds_wfcq_head_ptr_t head, 323 1.1 christos struct cds_wfcq_tail *tail) 324 1.1 christos { 325 1.1 christos return ___cds_wfcq_first(head, tail, 0); 326 1.1 christos } 327 1.1 christos 328 1.1 christos static inline struct cds_wfcq_node * 329 1.1 christos ___cds_wfcq_next(cds_wfcq_head_ptr_t head __attribute__((unused)), 330 1.1 christos struct cds_wfcq_tail *tail, 331 1.1 christos struct cds_wfcq_node *node, 332 1.1 christos int blocking) 333 1.1 christos { 334 1.1 christos struct cds_wfcq_node *next; 335 1.1 christos 336 1.1 christos /* 337 1.1 christos * Even though the following tail->p check is sufficient to find 338 1.1 christos * out if we reached the end of the queue, we first check 339 1.1 christos * node->next as a common case to ensure that iteration on nodes 340 1.1 christos * do not frequently access enqueuer's tail->p cache line. 341 1.1 christos * 342 1.1 christos * Load node->next before loading next's content 343 1.1 christos */ 344 1.1 christos if ((next = uatomic_load(&node->next, CMM_CONSUME)) == NULL) { 345 1.1 christos if (uatomic_load(&tail->p, CMM_RELAXED) == node) 346 1.1 christos return NULL; 347 1.1 christos next = ___cds_wfcq_node_sync_next(node, blocking); 348 1.1 christos } 349 1.1 christos 350 1.1 christos return next; 351 1.1 christos } 352 1.1 christos 353 1.1 christos /* 354 1.1 christos * __cds_wfcq_next_blocking: get next node of a queue, without dequeuing. 355 1.1 christos * 356 1.1 christos * Content written into the node before enqueue is guaranteed to be 357 1.1 christos * consistent, but no other memory ordering is ensured. 358 1.1 christos * Dequeue/splice/iteration mutual exclusion should be ensured by the 359 1.1 christos * caller. 360 1.1 christos * 361 1.1 christos * Used by for-like iteration macros in urcu/wfqueue.h: 362 1.1 christos * __cds_wfcq_for_each_blocking() 363 1.1 christos * __cds_wfcq_for_each_blocking_safe() 364 1.1 christos * 365 1.1 christos * Returns NULL if reached end of queue, non-NULL next queue node 366 1.1 christos * otherwise. 367 1.1 christos */ 368 1.1 christos static inline struct cds_wfcq_node * 369 1.1 christos ___cds_wfcq_next_blocking(cds_wfcq_head_ptr_t head, 370 1.1 christos struct cds_wfcq_tail *tail, 371 1.1 christos struct cds_wfcq_node *node) 372 1.1 christos { 373 1.1 christos return ___cds_wfcq_next(head, tail, node, 1); 374 1.1 christos } 375 1.1 christos 376 1.1 christos /* 377 1.1 christos * __cds_wfcq_next_blocking: get next node of a queue, without dequeuing. 378 1.1 christos * 379 1.1 christos * Same as __cds_wfcq_next_blocking, but returns CDS_WFCQ_WOULDBLOCK if 380 1.1 christos * it needs to block. 381 1.1 christos */ 382 1.1 christos static inline struct cds_wfcq_node * 383 1.1 christos ___cds_wfcq_next_nonblocking(cds_wfcq_head_ptr_t head, 384 1.1 christos struct cds_wfcq_tail *tail, 385 1.1 christos struct cds_wfcq_node *node) 386 1.1 christos { 387 1.1 christos return ___cds_wfcq_next(head, tail, node, 0); 388 1.1 christos } 389 1.1 christos 390 1.1 christos static inline struct cds_wfcq_node * 391 1.1 christos ___cds_wfcq_dequeue_with_state(cds_wfcq_head_ptr_t u_head, 392 1.1 christos struct cds_wfcq_tail *tail, 393 1.1 christos int *state, 394 1.1 christos int blocking) 395 1.1 christos { 396 1.1 christos struct __cds_wfcq_head *head = u_head._h; 397 1.1 christos struct cds_wfcq_node *node, *next; 398 1.1 christos 399 1.1 christos if (state) 400 1.1 christos *state = 0; 401 1.1 christos 402 1.1 christos if (_cds_wfcq_empty(__cds_wfcq_head_const_cast(head), tail)) { 403 1.1 christos return NULL; 404 1.1 christos } 405 1.1 christos 406 1.1 christos node = ___cds_wfcq_node_sync_next(&head->node, blocking); 407 1.1 christos if (!blocking && node == CDS_WFCQ_WOULDBLOCK) { 408 1.1 christos return CDS_WFCQ_WOULDBLOCK; 409 1.1 christos } 410 1.1 christos 411 1.1 christos if ((next = uatomic_load(&node->next, CMM_CONSUME)) == NULL) { 412 1.1 christos /* 413 1.1 christos * @node is probably the only node in the queue. 414 1.1 christos * Try to move the tail to &q->head. 415 1.1 christos * q->head.next is set to NULL here, and stays 416 1.1 christos * NULL if the cmpxchg succeeds. Should the 417 1.1 christos * cmpxchg fail due to a concurrent enqueue, the 418 1.1 christos * q->head.next will be set to the next node. 419 1.1 christos */ 420 1.1 christos _cds_wfcq_node_init_atomic(&head->node); 421 1.1 christos if (uatomic_cmpxchg_mo(&tail->p, node, &head->node, 422 1.1 christos CMM_SEQ_CST, CMM_SEQ_CST) == node) { 423 1.1 christos if (state) 424 1.1 christos *state |= CDS_WFCQ_STATE_LAST; 425 1.1 christos cmm_emit_legacy_smp_mb(); 426 1.1 christos return node; 427 1.1 christos } 428 1.1 christos next = ___cds_wfcq_node_sync_next(node, blocking); 429 1.1 christos /* 430 1.1 christos * In nonblocking mode, if we would need to block to 431 1.1 christos * get node's next, set the head next node pointer 432 1.1 christos * (currently NULL) back to its original value. 433 1.1 christos */ 434 1.1 christos if (!blocking && next == CDS_WFCQ_WOULDBLOCK) { 435 1.1 christos uatomic_store(&head->node.next, node, CMM_RELAXED); 436 1.1 christos return CDS_WFCQ_WOULDBLOCK; 437 1.1 christos } 438 1.1 christos } 439 1.1 christos 440 1.1 christos /* 441 1.1 christos * Move queue head forward. 442 1.1 christos */ 443 1.1 christos uatomic_store(&head->node.next, next, CMM_RELAXED); 444 1.1 christos cmm_emit_legacy_smp_mb(); 445 1.1 christos 446 1.1 christos return node; 447 1.1 christos } 448 1.1 christos 449 1.1 christos /* 450 1.1 christos * __cds_wfcq_dequeue_with_state_blocking: dequeue node from queue, with state. 451 1.1 christos * 452 1.1 christos * Content written into the node before enqueue is guaranteed to be 453 1.1 christos * consistent, but no other memory ordering is ensured. 454 1.1 christos * It is valid to reuse and free a dequeued node immediately. 455 1.1 christos * Dequeue/splice/iteration mutual exclusion should be ensured by the 456 1.1 christos * caller. 457 1.1 christos */ 458 1.1 christos static inline struct cds_wfcq_node * 459 1.1 christos ___cds_wfcq_dequeue_with_state_blocking(cds_wfcq_head_ptr_t head, 460 1.1 christos struct cds_wfcq_tail *tail, int *state) 461 1.1 christos { 462 1.1 christos return ___cds_wfcq_dequeue_with_state(head, tail, state, 1); 463 1.1 christos } 464 1.1 christos 465 1.1 christos /* 466 1.1 christos * ___cds_wfcq_dequeue_blocking: dequeue node from queue. 467 1.1 christos * 468 1.1 christos * Same as __cds_wfcq_dequeue_with_state_blocking, but without saving 469 1.1 christos * state. 470 1.1 christos */ 471 1.1 christos static inline struct cds_wfcq_node * 472 1.1 christos ___cds_wfcq_dequeue_blocking(cds_wfcq_head_ptr_t head, 473 1.1 christos struct cds_wfcq_tail *tail) 474 1.1 christos { 475 1.1 christos return ___cds_wfcq_dequeue_with_state_blocking(head, tail, NULL); 476 1.1 christos } 477 1.1 christos 478 1.1 christos /* 479 1.1 christos * __cds_wfcq_dequeue_with_state_nonblocking: dequeue node, with state. 480 1.1 christos * 481 1.1 christos * Same as __cds_wfcq_dequeue_blocking, but returns CDS_WFCQ_WOULDBLOCK 482 1.1 christos * if it needs to block. 483 1.1 christos */ 484 1.1 christos static inline struct cds_wfcq_node * 485 1.1 christos ___cds_wfcq_dequeue_with_state_nonblocking(cds_wfcq_head_ptr_t head, 486 1.1 christos struct cds_wfcq_tail *tail, int *state) 487 1.1 christos { 488 1.1 christos return ___cds_wfcq_dequeue_with_state(head, tail, state, 0); 489 1.1 christos } 490 1.1 christos 491 1.1 christos /* 492 1.1 christos * ___cds_wfcq_dequeue_nonblocking: dequeue node from queue. 493 1.1 christos * 494 1.1 christos * Same as __cds_wfcq_dequeue_with_state_nonblocking, but without saving 495 1.1 christos * state. 496 1.1 christos */ 497 1.1 christos static inline struct cds_wfcq_node * 498 1.1 christos ___cds_wfcq_dequeue_nonblocking(cds_wfcq_head_ptr_t head, 499 1.1 christos struct cds_wfcq_tail *tail) 500 1.1 christos { 501 1.1 christos return ___cds_wfcq_dequeue_with_state_nonblocking(head, tail, NULL); 502 1.1 christos } 503 1.1 christos 504 1.1 christos /* 505 1.1 christos * __cds_wfcq_splice: enqueue all src_q nodes at the end of dest_q. 506 1.1 christos * 507 1.1 christos * Operations after splice are consistant with respect to enqueue. 508 1.1 christos * 509 1.1 christos * Dequeue all nodes from src_q. 510 1.1 christos * dest_q must be already initialized. 511 1.1 christos * Mutual exclusion for src_q should be ensured by the caller as 512 1.1 christos * specified in the "Synchronisation table". 513 1.1 christos * Returns enum cds_wfcq_ret which indicates the state of the src or 514 1.1 christos * dest queue. 515 1.1 christos */ 516 1.1 christos static inline enum cds_wfcq_ret 517 1.1 christos ___cds_wfcq_splice( 518 1.1 christos cds_wfcq_head_ptr_t u_dest_q_head, 519 1.1 christos struct cds_wfcq_tail *dest_q_tail, 520 1.1 christos cds_wfcq_head_ptr_t u_src_q_head, 521 1.1 christos struct cds_wfcq_tail *src_q_tail, 522 1.1 christos int blocking) 523 1.1 christos { 524 1.1 christos struct __cds_wfcq_head *dest_q_head = u_dest_q_head._h; 525 1.1 christos struct __cds_wfcq_head *src_q_head = u_src_q_head._h; 526 1.1 christos struct cds_wfcq_node *head, *tail; 527 1.1 christos int attempt = 0; 528 1.1 christos 529 1.1 christos /* 530 1.1 christos * Initial emptiness check to speed up cases where queue is 531 1.1 christos * empty: only require loads to check if queue is empty. 532 1.1 christos */ 533 1.1 christos if (_cds_wfcq_empty(__cds_wfcq_head_const_cast(src_q_head), src_q_tail)) 534 1.1 christos return CDS_WFCQ_RET_SRC_EMPTY; 535 1.1 christos 536 1.1 christos for (;;) { 537 1.1 christos /* 538 1.1 christos * Open-coded _cds_wfcq_empty() by testing result of 539 1.1 christos * uatomic_xchg, as well as tail pointer vs head node 540 1.1 christos * address. 541 1.1 christos */ 542 1.1 christos head = uatomic_xchg_mo(&src_q_head->node.next, NULL, CMM_SEQ_CST); 543 1.1 christos if (head) 544 1.1 christos break; /* non-empty */ 545 1.1 christos if (uatomic_load(&src_q_tail->p, CMM_CONSUME) == &src_q_head->node) 546 1.1 christos return CDS_WFCQ_RET_SRC_EMPTY; 547 1.1 christos if (___cds_wfcq_busy_wait(&attempt, blocking)) 548 1.1 christos return CDS_WFCQ_RET_WOULDBLOCK; 549 1.1 christos } 550 1.1 christos 551 1.1 christos /* 552 1.1 christos * Memory barrier implied before uatomic_xchg() orders store to 553 1.1 christos * src_q->head before store to src_q->tail. This is required by 554 1.1 christos * concurrent enqueue on src_q, which exchanges the tail before 555 1.1 christos * updating the previous tail's next pointer. 556 1.1 christos */ 557 1.1 christos cmm_emit_legacy_smp_mb(); 558 1.1 christos tail = uatomic_xchg_mo(&src_q_tail->p, &src_q_head->node, CMM_SEQ_CST); 559 1.1 christos 560 1.1 christos /* 561 1.1 christos * Append the spliced content of src_q into dest_q. Does not 562 1.1 christos * require mutual exclusion on dest_q (wait-free). 563 1.1 christos */ 564 1.1 christos if (___cds_wfcq_append(__cds_wfcq_head_cast(dest_q_head), dest_q_tail, 565 1.1 christos head, tail)) 566 1.1 christos return CDS_WFCQ_RET_DEST_NON_EMPTY; 567 1.1 christos else 568 1.1 christos return CDS_WFCQ_RET_DEST_EMPTY; 569 1.1 christos } 570 1.1 christos 571 1.1 christos /* 572 1.1 christos * __cds_wfcq_splice_blocking: enqueue all src_q nodes at the end of dest_q. 573 1.1 christos * 574 1.1 christos * Dequeue all nodes from src_q. 575 1.1 christos * dest_q must be already initialized. 576 1.1 christos * Mutual exclusion for src_q should be ensured by the caller as 577 1.1 christos * specified in the "Synchronisation table". 578 1.1 christos * Returns enum cds_wfcq_ret which indicates the state of the src or 579 1.1 christos * dest queue. Never returns CDS_WFCQ_RET_WOULDBLOCK. 580 1.1 christos */ 581 1.1 christos static inline enum cds_wfcq_ret 582 1.1 christos ___cds_wfcq_splice_blocking( 583 1.1 christos cds_wfcq_head_ptr_t dest_q_head, 584 1.1 christos struct cds_wfcq_tail *dest_q_tail, 585 1.1 christos cds_wfcq_head_ptr_t src_q_head, 586 1.1 christos struct cds_wfcq_tail *src_q_tail) 587 1.1 christos { 588 1.1 christos return ___cds_wfcq_splice(dest_q_head, dest_q_tail, 589 1.1 christos src_q_head, src_q_tail, 1); 590 1.1 christos } 591 1.1 christos 592 1.1 christos /* 593 1.1 christos * __cds_wfcq_splice_nonblocking: enqueue all src_q nodes at the end of dest_q. 594 1.1 christos * 595 1.1 christos * Same as __cds_wfcq_splice_blocking, but returns 596 1.1 christos * CDS_WFCQ_RET_WOULDBLOCK if it needs to block. 597 1.1 christos */ 598 1.1 christos static inline enum cds_wfcq_ret 599 1.1 christos ___cds_wfcq_splice_nonblocking( 600 1.1 christos cds_wfcq_head_ptr_t dest_q_head, 601 1.1 christos struct cds_wfcq_tail *dest_q_tail, 602 1.1 christos cds_wfcq_head_ptr_t src_q_head, 603 1.1 christos struct cds_wfcq_tail *src_q_tail) 604 1.1 christos { 605 1.1 christos return ___cds_wfcq_splice(dest_q_head, dest_q_tail, 606 1.1 christos src_q_head, src_q_tail, 0); 607 1.1 christos } 608 1.1 christos 609 1.1 christos /* 610 1.1 christos * cds_wfcq_dequeue_with_state_blocking: dequeue a node from a wait-free queue. 611 1.1 christos * 612 1.1 christos * Content written into the node before enqueue is guaranteed to be 613 1.1 christos * consistent, but no other memory ordering is ensured. 614 1.1 christos * Mutual exclusion with cds_wfcq_splice_blocking and dequeue lock is 615 1.1 christos * ensured. 616 1.1 christos * It is valid to reuse and free a dequeued node immediately. 617 1.1 christos */ 618 1.1 christos static inline struct cds_wfcq_node * 619 1.1 christos _cds_wfcq_dequeue_with_state_blocking(struct cds_wfcq_head *head, 620 1.1 christos struct cds_wfcq_tail *tail, int *state) 621 1.1 christos { 622 1.1 christos struct cds_wfcq_node *retval; 623 1.1 christos 624 1.1 christos _cds_wfcq_dequeue_lock(head, tail); 625 1.1 christos retval = ___cds_wfcq_dequeue_with_state_blocking(cds_wfcq_head_cast(head), 626 1.1 christos tail, state); 627 1.1 christos _cds_wfcq_dequeue_unlock(head, tail); 628 1.1 christos return retval; 629 1.1 christos } 630 1.1 christos 631 1.1 christos /* 632 1.1 christos * cds_wfcq_dequeue_blocking: dequeue node from queue. 633 1.1 christos * 634 1.1 christos * Same as cds_wfcq_dequeue_blocking, but without saving state. 635 1.1 christos */ 636 1.1 christos static inline struct cds_wfcq_node * 637 1.1 christos _cds_wfcq_dequeue_blocking(struct cds_wfcq_head *head, 638 1.1 christos struct cds_wfcq_tail *tail) 639 1.1 christos { 640 1.1 christos return _cds_wfcq_dequeue_with_state_blocking(head, tail, NULL); 641 1.1 christos } 642 1.1 christos 643 1.1 christos /* 644 1.1 christos * cds_wfcq_splice_blocking: enqueue all src_q nodes at the end of dest_q. 645 1.1 christos * 646 1.1 christos * Dequeue all nodes from src_q. 647 1.1 christos * dest_q must be already initialized. 648 1.1 christos * Content written into the node before enqueue is guaranteed to be 649 1.1 christos * consistent, but no other memory ordering is ensured. 650 1.1 christos * Mutual exclusion with cds_wfcq_dequeue_blocking and dequeue lock is 651 1.1 christos * ensured. 652 1.1 christos * Returns enum cds_wfcq_ret which indicates the state of the src or 653 1.1 christos * dest queue. Never returns CDS_WFCQ_RET_WOULDBLOCK. 654 1.1 christos */ 655 1.1 christos static inline enum cds_wfcq_ret 656 1.1 christos _cds_wfcq_splice_blocking( 657 1.1 christos struct cds_wfcq_head *dest_q_head, 658 1.1 christos struct cds_wfcq_tail *dest_q_tail, 659 1.1 christos struct cds_wfcq_head *src_q_head, 660 1.1 christos struct cds_wfcq_tail *src_q_tail) 661 1.1 christos { 662 1.1 christos enum cds_wfcq_ret ret; 663 1.1 christos 664 1.1 christos _cds_wfcq_dequeue_lock(src_q_head, src_q_tail); 665 1.1 christos ret = ___cds_wfcq_splice_blocking(cds_wfcq_head_cast(dest_q_head), dest_q_tail, 666 1.1 christos cds_wfcq_head_cast(src_q_head), src_q_tail); 667 1.1 christos _cds_wfcq_dequeue_unlock(src_q_head, src_q_tail); 668 1.1 christos return ret; 669 1.1 christos } 670 1.1 christos 671 1.1 christos #ifdef __cplusplus 672 1.1 christos } 673 1.1 christos #endif 674 1.1 christos 675 1.1 christos #endif /* _URCU_WFCQUEUE_STATIC_H */ 676