#include <errno.h>
#include <poll.h>
+#include "urcu/arch.h"
#include "urcu/wfcqueue.h"
#include "urcu/map/urcu.h"
#include "urcu/static/urcu.h"
*/
#define RCU_QS_ACTIVE_ATTEMPTS 100
-/*
- * RCU_MEMBARRIER is only possibly available on Linux.
- */
-#if defined(RCU_MEMBARRIER) && defined(__linux__)
-#include <urcu/syscall-compat.h>
-#endif
-
-/* If the headers do not support SYS_membarrier, fall back on RCU_MB */
-#ifdef SYS_membarrier
-# define membarrier(...) syscall(SYS_membarrier, __VA_ARGS__)
+/* If the headers do not support membarrier system call, fall back on RCU_MB */
+#ifdef __NR_membarrier
+# define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__)
#else
# define membarrier(...) -ENOSYS
#endif
/*
* 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 */
+ /*
+ * 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)
- return;
+ goto end;
while (futex_async(&rcu_gp.futex, FUTEX_WAIT, -1,
NULL, NULL, 0)) {
switch (errno) {
case EWOULDBLOCK:
/* Value already changed. */
- return;
+ goto end;
case EINTR:
/* Retry if interrupted by signal. */
break; /* Get out of switch. */
urcu_die(errno);
}
}
+end:
+ /*
+ * Re-lock the registry lock before the next loop.
+ */
+ mutex_lock(&rcu_registry_lock);
}
/*
}
break;
} else {
- /* Temporarily unlock the registry lock. */
- mutex_unlock(&rcu_registry_lock);
- if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS)
+ if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) {
+ /* wait_gp unlocks/locks registry lock. */
wait_gp();
- else
+ } else {
+ /* Temporarily unlock the registry lock. */
+ mutex_unlock(&rcu_registry_lock);
caa_cpu_relax();
- /* Re-lock the registry lock before the next loop. */
- mutex_lock(&rcu_registry_lock);
+ /*
+ * Re-lock the registry lock before the
+ * next loop.
+ */
+ mutex_lock(&rcu_registry_lock);
+ }
}
#else /* #ifndef HAS_INCOHERENT_CACHES */
/*
smp_mb_master();
wait_gp_loops = 0;
}
- /* Temporarily unlock the registry lock. */
- mutex_unlock(&rcu_registry_lock);
if (wait_loops >= RCU_QS_ACTIVE_ATTEMPTS) {
+ /* wait_gp unlocks/locks registry lock. */
wait_gp();
wait_gp_loops++;
} else {
+ /* Temporarily unlock the registry lock. */
+ mutex_unlock(&rcu_registry_lock);
caa_cpu_relax();
+ /*
+ * Re-lock the registry lock before the
+ * next loop.
+ */
+ mutex_lock(&rcu_registry_lock);
}
- /* Re-lock the registry lock before the next loop. */
- mutex_lock(&rcu_registry_lock);
}
#endif /* #else #ifndef HAS_INCOHERENT_CACHES */
}