+ was_online = URCU_TLS(rcu_reader).ctr;
+
+ /* All threads should read qparity before accessing data structure
+ * where new ptr points to. In the "then" case, rcu_thread_offline
+ * includes a memory barrier.
+ *
+ * Mark the writer thread offline to make sure we don't wait for
+ * our own quiescent state. This allows using synchronize_rcu()
+ * in threads registered as readers.
+ */
+ if (was_online)
+ rcu_thread_offline();
+ else
+ cmm_smp_mb();
+
+ mutex_lock(&rcu_gp_lock);
+
+ if (cds_list_empty(®istry))
+ goto out;
+
+ /*
+ * Wait for previous parity to be empty of readers.
+ */
+ update_counter_and_wait(); /* 0 -> 1, wait readers in parity 0 */
+
+ /*
+ * Must finish waiting for quiescent state for parity 0 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 URCU_TLS(rcu_reader).ctr before store to
+ * rcu_gp_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.
+ */
+ update_counter_and_wait(); /* 1 -> 0, wait readers in parity 1 */
+out:
+ mutex_unlock(&rcu_gp_lock);
+
+ /*
+ * Finish waiting for reader threads before letting the old ptr being
+ * freed.
+ */
+ if (was_online)
+ rcu_thread_online();
+ else
+ cmm_smp_mb();
+}
+#else /* !(CAA_BITS_PER_LONG < 64) */
+void synchronize_rcu(void)
+{
+ unsigned long was_online;
+
+ was_online = URCU_TLS(rcu_reader).ctr;