void ___urcu_steal_work(struct urcu_worker *worker,
struct urcu_worker *sibling)
{
+ /*
+ * Don't bother grabbing the sibling queue lock if it is empty.
+ */
+ if (cds_wfcq_empty(&sibling->head, &sibling->tail))
+ return;
cds_wfcq_dequeue_lock(&sibling->head, &sibling->tail);
(void) __cds_wfcq_splice_blocking(&worker->head,
&worker->tail,
}
static inline
-void ___urcu_wakeup_sibling(struct urcu_worker *sibling)
+bool ___urcu_wakeup_sibling(struct urcu_worker *sibling)
{
- urcu_adaptative_wake_up(&sibling->wait_node);
+ return urcu_adaptative_wake_up(&sibling->wait_node);
}
static inline
-void __urcu_wakeup_siblings(struct urcu_workqueue *queue,
+bool __urcu_wakeup_siblings(struct urcu_workqueue *queue,
struct urcu_worker *worker)
{
struct urcu_worker *sibling_prev, *sibling_next;
struct cds_list_head *sibling_node;
+ bool wakeup_performed = 0;
if (!(worker->flags & URCU_WORKER_STEAL))
return;
sibling_next = caa_container_of(sibling_node, struct urcu_worker,
sibling_node);
if (sibling_next != worker)
- ___urcu_wakeup_sibling(sibling_next);
+ wakeup_performed = ___urcu_wakeup_sibling(sibling_next);
+ if (wakeup_performed)
+ goto end;
sibling_node = rcu_dereference(worker->sibling_node.prev);
if (sibling_node == &queue->sibling_head)
sibling_prev = caa_container_of(sibling_node, struct urcu_worker,
sibling_node);
if (sibling_prev != worker && sibling_prev != sibling_next)
- ___urcu_wakeup_sibling(sibling_prev);
-
+ wakeup_performed = ___urcu_wakeup_sibling(sibling_prev);
+end:
rcu_read_unlock();
+
+ return wakeup_performed;
}
static inline
* We will be busy handling the work batch, awaken siblings so
* they can steal from us.
*/
- __urcu_wakeup_siblings(queue, worker);
+ (void) __urcu_wakeup_siblings(queue, worker);
}
static inline
* If we are registered for work stealing, we need to dequeue
* safely against siblings.
*/
- if (worker->flags & URCU_WORKER_STEAL)
+ if (worker->flags & URCU_WORKER_STEAL) {
+ /*
+ * Don't bother grabbing the worker queue lock if it is
+ * empty.
+ */
+ if (cds_wfcq_empty(&worker->head, &worker->tail))
+ return NULL;
node = cds_wfcq_dequeue_blocking(&worker->head,
&worker->tail);
- else
+ } else {
node = ___cds_wfcq_dequeue_with_state(&worker->head,
&worker->tail, NULL, 1, 0);
+ }
if (!node)
return NULL;
return caa_container_of(node, struct urcu_work, node);