#ifdef RCU_MEMBARRIER
static int init_done;
-int has_sys_membarrier;
+int rcu_has_sys_membarrier;
void __attribute__((constructor)) rcu_init(void);
#endif
static pthread_mutex_t rcu_gp_lock = PTHREAD_MUTEX_INITIALIZER;
-int32_t gp_futex;
+int32_t rcu_gp_futex;
/*
* Global grace period counter.
DEFINE_URCU_TLS(struct rcu_reader, rcu_reader);
#ifdef DEBUG_YIELD
-unsigned int yield_active;
-DEFINE_URCU_TLS(unsigned int, rand_yield);
+unsigned int rcu_yield_active;
+DEFINE_URCU_TLS(unsigned int, rcu_rand_yield);
#endif
static CDS_LIST_HEAD(registry);
#ifdef RCU_MEMBARRIER
static void smp_mb_master(int group)
{
- if (caa_likely(has_sys_membarrier))
+ if (caa_likely(rcu_has_sys_membarrier))
membarrier(MEMBARRIER_EXPEDITED);
else
cmm_smp_mb();
{
/* Read reader_gp before read futex */
smp_mb_master(RCU_MB_GROUP);
- if (uatomic_read(&gp_futex) == -1)
- futex_async(&gp_futex, FUTEX_WAIT, -1,
+ if (uatomic_read(&rcu_gp_futex) == -1)
+ futex_async(&rcu_gp_futex, FUTEX_WAIT, -1,
NULL, NULL, 0);
}
-void update_counter_and_wait(void)
+static void wait_for_readers(void)
{
CDS_LIST_HEAD(qsreaders);
int wait_loops = 0;
struct rcu_reader *index, *tmp;
- /* Switch parity: 0 -> 1, 1 -> 0 */
- CMM_STORE_SHARED(rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR_PHASE);
-
- /*
- * Must commit rcu_gp_ctr update to memory before waiting for quiescent
- * state. Failure to do so could result in the writer waiting forever
- * while new readers are always accessing data (no progress). Enforce
- * compiler-order of store to rcu_gp_ctr before load rcu_reader ctr.
- */
- cmm_barrier();
-
- /*
- *
- * Adding a cmm_smp_mb() which is _not_ formally required, but makes the
- * model easier to understand. It does not have a big performance impact
- * anyway, given this is the write-side.
- */
- cmm_smp_mb();
-
/*
- * Wait for each thread URCU_TLS(rcu_reader).ctr count to become 0.
+ * Wait for each thread URCU_TLS(rcu_reader).ctr to either
+ * indicate quiescence (not nested), or observe the current
+ * rcu_gp_ctr value.
*/
for (;;) {
wait_loops++;
if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) {
- uatomic_dec(&gp_futex);
+ uatomic_dec(&rcu_gp_futex);
/* Write futex before read reader_gp */
smp_mb_master(RCU_MB_GROUP);
}
if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) {
/* Read reader_gp before write futex */
smp_mb_master(RCU_MB_GROUP);
- uatomic_set(&gp_futex, 0);
+ uatomic_set(&rcu_gp_futex, 0);
}
break;
} else {
if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS) {
/* Read reader_gp before write futex */
smp_mb_master(RCU_MB_GROUP);
- uatomic_set(&gp_futex, 0);
+ uatomic_set(&rcu_gp_futex, 0);
}
break;
} else {
smp_mb_master(RCU_MB_GROUP);
/*
- * Wait for previous parity to be empty of readers.
+ * Wait for readers to observe original parity or be quiescent.
*/
- update_counter_and_wait(); /* 0 -> 1, wait readers in parity 0 */
+ wait_for_readers();
/*
- * Must finish waiting for quiescent state for parity 0 before
+ * Must finish waiting for quiescent state for original parity before
* committing next rcu_gp_ctr update to memory. Failure to do so could
* result in the writer waiting forever while new readers are always
* accessing data (no progress). Enforce compiler-order of load
*/
cmm_smp_mb();
+ /* Switch parity: 0 -> 1, 1 -> 0 */
+ CMM_STORE_SHARED(rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR_PHASE);
+
+ /*
+ * Must commit rcu_gp_ctr update to memory before waiting for quiescent
+ * state. Failure to do so could result in the writer waiting forever
+ * while new readers are always accessing data (no progress). Enforce
+ * compiler-order of store to rcu_gp_ctr before load rcu_reader ctr.
+ */
+ cmm_barrier();
+
+ /*
+ *
+ * Adding a cmm_smp_mb() which is _not_ formally required, but makes the
+ * model easier to understand. It does not have a big performance impact
+ * anyway, given this is the write-side.
+ */
+ cmm_smp_mb();
+
/*
- * Wait for previous parity to be empty of readers.
+ * Wait for readers to observe new parity or be quiescent.
*/
- update_counter_and_wait(); /* 1 -> 0, wait readers in parity 1 */
+ wait_for_readers();
/* Finish waiting for reader threads before letting the old ptr being
* freed. Must be done within rcu_gp_lock because it iterates on reader
return;
init_done = 1;
if (!membarrier(MEMBARRIER_EXPEDITED | MEMBARRIER_QUERY))
- has_sys_membarrier = 1;
+ rcu_has_sys_membarrier = 1;
}
#endif