+ force_mb_all_readers();
+}
+#endif /* #ifdef RCU_SIGNAL */
+
+/*
+ * synchronize_rcu() waiting. Single thread.
+ * Always called with rcu_registry lock held. Releases this lock and
+ * grabs it again. Holds the lock when it returns.
+ */
+static void wait_gp(void)
+{
+ /*
+ * Read reader_gp before read futex. smp_mb_master() needs to
+ * be called with the rcu registry lock held in RCU_SIGNAL
+ * flavor.
+ */
+ smp_mb_master();
+ /* Temporarily unlock the registry lock. */
+ mutex_unlock(&rcu_registry_lock);
+ if (uatomic_read(&rcu_gp.futex) != -1)
+ goto end;
+ while (futex_async(&rcu_gp.futex, FUTEX_WAIT, -1,
+ NULL, NULL, 0)) {
+ switch (errno) {
+ case EWOULDBLOCK:
+ /* Value already changed. */
+ goto end;
+ case EINTR:
+ /* Retry if interrupted by signal. */
+ break; /* Get out of switch. */
+ default:
+ /* Unexpected error. */
+ urcu_die(errno);
+ }
+ }
+end:
+ /*
+ * Re-lock the registry lock before the next loop.
+ */
+ mutex_lock(&rcu_registry_lock);
+}
+
+/*
+ * Always called with rcu_registry lock held. Releases this lock between
+ * iterations and grabs it again. Holds the lock when it returns.
+ */
+static void wait_for_readers(struct cds_list_head *input_readers,
+ struct cds_list_head *cur_snap_readers,
+ struct cds_list_head *qsreaders)
+{
+ unsigned int wait_loops = 0;
+ struct rcu_reader *index, *tmp;
+#ifdef HAS_INCOHERENT_CACHES
+ unsigned int wait_gp_loops = 0;
+#endif /* HAS_INCOHERENT_CACHES */