+ CDS_LIST_HEAD(cur_snap_readers);
+ CDS_LIST_HEAD(qsreaders);
+ unsigned long was_online;
+ DEFINE_URCU_WAIT_NODE(wait, URCU_WAIT_WAITING);
+ struct urcu_waiters waiters;
+
+ was_online = rcu_read_ongoing();
+
+ /* 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();
+
+ /*
+ * Add ourself to gp_waiters queue of threads awaiting to wait
+ * for a grace period. Proceed to perform the grace period only
+ * if we are the first thread added into the queue.
+ */
+ if (urcu_wait_add(&gp_waiters, &wait) != 0) {
+ /* Not first in queue: will be awakened by another thread. */
+ urcu_adaptative_busy_wait(&wait);
+ goto gp_end;
+ }
+ /* We won't need to wake ourself up */
+ urcu_wait_set_state(&wait, URCU_WAIT_RUNNING);
+
+ mutex_lock(&rcu_gp_lock);
+
+ /*
+ * Move all waiters into our local queue.
+ */
+ urcu_move_waiters(&waiters, &gp_waiters);
+
+ if (cds_list_empty(®istry))
+ goto out;
+
+ /*
+ * Wait for readers to observe original parity or be quiescent.
+ */
+ wait_for_readers(®istry, &cur_snap_readers, &qsreaders);
+
+ /*
+ * 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();