+ /*
+ * 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 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();
+
+ /* Switch parity: 0 -> 1, 1 -> 0 */
+ CMM_STORE_SHARED(rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR);
+
+ /*
+ * 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 URCU_TLS(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 readers to observe new parity or be quiescent.
+ */
+ wait_for_readers(&cur_snap_readers, NULL, &qsreaders);
+
+ /*
+ * Put quiescent reader list back into registry.
+ */
+ cds_list_splice(&qsreaders, ®istry);
+out:
+ mutex_unlock(&rcu_gp_lock);
+ urcu_wake_all_waiters(&waiters);
+gp_end:
+ /*
+ * 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)
+{
+ CDS_LIST_HEAD(qsreaders);
+ unsigned long was_online;
+ DEFINE_URCU_WAIT_NODE(wait, URCU_WAIT_WAITING);
+ struct urcu_waiters waiters;
+
+ was_online = URCU_TLS(rcu_reader).ctr;