From bc94ca9bada25f7403e3e859caa241146ae8e338 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 9 Jun 2011 10:39:56 -0400 Subject: [PATCH] call_rcu: handle retry without wait correctly The wait scheme has an implementation problem: if the list is not empty when the !RT scheme checks for it, it will restart the loop and decrement the futex (again) without calling call_rcu_wait() (which would wait until it is set back to 0). So in this case, we can end up decrementing "futex" to values well below -1. Fix this by moving the decrement before the loop, and duplicate it after return from call_rcu_wait() + poll() delay. Also move the "set futex to 0 upon stopping" outside of the loop: this is the only way the loop can be stopped anyway. Signed-off-by: Mathieu Desnoyers --- urcu-call-rcu-impl.h | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/urcu-call-rcu-impl.h b/urcu-call-rcu-impl.h index 82fec80..6fcf8c8 100644 --- a/urcu-call-rcu-impl.h +++ b/urcu-call-rcu-impl.h @@ -211,12 +211,12 @@ static void *call_rcu_thread(void *arg) } thread_call_rcu_data = crdp; + if (!rt) { + uatomic_dec(&crdp->futex); + /* Decrement futex before reading call_rcu list */ + cmm_smp_mb(); + } for (;;) { - if (!rt) { - uatomic_dec(&crdp->futex); - /* Decrement futex before reading call_rcu list */ - cmm_smp_mb(); - } if (&crdp->cbs.head != _CMM_LOAD_SHARED(crdp->cbs.tail)) { while ((cbs = _CMM_LOAD_SHARED(crdp->cbs.head)) == NULL) poll(NULL, 0, 1); @@ -240,21 +240,30 @@ static void *call_rcu_thread(void *arg) } while (cbs != NULL); uatomic_sub(&crdp->qlen, cbcount); } - if (uatomic_read(&crdp->flags) & URCU_CALL_RCU_STOP) { - if (!rt) { + if (uatomic_read(&crdp->flags) & URCU_CALL_RCU_STOP) + break; + if (!rt) { + if (&crdp->cbs.head + == _CMM_LOAD_SHARED(crdp->cbs.tail)) { + call_rcu_wait(crdp); + poll(NULL, 0, 10); + uatomic_dec(&crdp->futex); /* - * Read call_rcu list before write futex. + * Decrement futex before reading + * call_rcu list. */ cmm_smp_mb(); - uatomic_set(&crdp->futex, 0); } - break; - } - if (!rt) { - if (&crdp->cbs.head == _CMM_LOAD_SHARED(crdp->cbs.tail)) - call_rcu_wait(crdp); + } else { + poll(NULL, 0, 10); } - poll(NULL, 0, 10); + } + if (!rt) { + /* + * Read call_rcu list before write futex. + */ + cmm_smp_mb(); + uatomic_set(&crdp->futex, 0); } uatomic_or(&crdp->flags, URCU_CALL_RCU_STOPPED); return NULL; -- 2.34.1