-/*
- * It is valid to reuse and free a dequeued node immediately.
- *
- * No need to go on a waitqueue here, as there is no possible state in which the
- * list could cause dequeue to busy-loop needlessly while waiting for another
- * thread to be scheduled. The queue appears empty until tail->next is set by
- * enqueue.
- */
-struct wfq_node *
-__wfq_dequeue_blocking(struct wfq_queue *q)
-{
- struct wfq_node *node, *next;
- int attempt = 0;
-
- /*
- * Queue is empty if it only contains the dummy node.
- */
- if (q->head == &q->dummy && LOAD_SHARED(q->tail) == &q->dummy.next)
- return NULL;
- node = q->head;
-
- /*
- * Adaptative busy-looping waiting for enqueuer to complete enqueue.
- */
- while ((next = LOAD_SHARED(node->next)) == NULL) {
- if (++attempt >= WFQ_ADAPT_ATTEMPTS) {
- poll(NULL, 0, WFQ_WAIT); /* Wait for 10ms */
- attempt = 0;
- } else
- cpu_relax();
- }
- /*
- * Move queue head forward.
- */
- q->head = next;
- /*
- * Requeue dummy node if we just dequeued it.
- */
- if (node == &q->dummy) {
- wfq_node_init(node);
- wfq_enqueue(q, node);
- return __wfq_dequeue_blocking(q);
- }
- return node;
-}
-
-struct wfq_node *
-wfq_dequeue_blocking(struct wfq_queue *q)
-{
- struct wfq_node *retnode;
- int ret;
-
- ret = pthread_mutex_lock(&q->lock);
- assert(!ret);
- retnode = __wfq_dequeue_blocking(q);
- ret = pthread_mutex_unlock(&q->lock);
- assert(!ret);
- return retnode;
-}