/*
- * urcu.c
+ * urcu-qsbr.c
*
- * Userspace RCU library
+ * Userspace RCU QSBR library
*
* Copyright (c) 2009 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
* Copyright (c) 2009 Paul E. McKenney, IBM Corporation.
#include <errno.h>
#include <poll.h>
-#include "urcu-qsbr.h"
+#define BUILD_QSBR_LIB
+#include "urcu-qsbr-static.h"
/* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */
-//#include "urcu.h"
+#include "urcu-qsbr.h"
pthread_mutex_t urcu_mutex = PTHREAD_MUTEX_INITIALIZER;
struct reader_registry {
pthread_t tid;
long *rcu_reader_qs_gp;
- char *need_mb;
};
#ifdef DEBUG_YIELD
#endif
static struct reader_registry *registry;
-static char __thread need_mb;
static int num_readers, alloc_readers;
-void internal_urcu_lock(void)
+static void internal_urcu_lock(void)
{
int ret;
perror("Error in pthread mutex lock");
exit(-1);
}
- if (need_mb) {
- smp_mb();
- need_mb = 0;
- smp_mb();
- }
poll(NULL,0,10);
}
#endif /* #else #ifndef DISTRUST_SIGNALS_EXTREME */
}
-void internal_urcu_unlock(void)
+static void internal_urcu_unlock(void)
{
int ret;
}
#endif /* #ifdef HAS_INCOHERENT_CACHES */
-static void force_mb_all_threads(void)
-{
- smp_mb();
-}
-
-void wait_for_quiescent_state(void)
+static void wait_for_quiescent_state(void)
{
struct reader_registry *index;
*/
for (index = registry; index < registry + num_readers; index++) {
#ifndef HAS_INCOHERENT_CACHES
- while (rcu_gp_ongoing(index->rcu_reader_qs_gp) &&
- (*index->rcu_reader_qs_gp - urcu_gp_ctr < 0))
+ while (rcu_gp_ongoing(index->rcu_reader_qs_gp))
cpu_relax();
#else /* #ifndef HAS_INCOHERENT_CACHES */
int wait_loops = 0;
* BUSY-LOOP. Force the reader thread to commit its
* rcu_reader_qs_gp update to memory if we wait for too long.
*/
- while (rcu_gp_ongoing(index->rcu_reader_qs_gp) &&
- (*index->rcu_reader_qs_gp - urcu_gp_ctr < 0)) {
+ while (rcu_gp_ongoing(index->rcu_reader_qs_gp)) {
if (wait_loops++ == KICK_READER_LOOPS) {
force_mb_single_thread(index);
wait_loops = 0;
void synchronize_rcu(void)
{
+ int was_online;
+
+ was_online = rcu_reader_qs_gp & 1;
+
+ /*
+ * 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.
+ */
+ smp_mb();
+ if (was_online)
+ STORE_SHARED(rcu_reader_qs_gp, 0);
+
internal_urcu_lock();
- force_mb_all_threads();
- urcu_gp_ctr += 2;
+ STORE_SHARED(urcu_gp_ctr, urcu_gp_ctr + 2);
wait_for_quiescent_state();
- force_mb_all_threads();
internal_urcu_unlock();
+
+ if (was_online)
+ _STORE_SHARED(rcu_reader_qs_gp, LOAD_SHARED(urcu_gp_ctr) + 1);
+ smp_mb();
}
/*
return oldptr;
}
+void rcu_quiescent_state(void)
+{
+ _rcu_quiescent_state();
+}
+
+void rcu_thread_offline(void)
+{
+ _rcu_thread_offline();
+}
+
+void rcu_thread_online(void)
+{
+ _rcu_thread_online();
+}
+
static void rcu_add_reader(pthread_t id)
{
struct reader_registry *oldarray;
registry[num_readers].tid = id;
/* reference to the TLS of _this_ reader thread. */
registry[num_readers].rcu_reader_qs_gp = &rcu_reader_qs_gp;
- registry[num_readers].need_mb = &need_mb;
num_readers++;
}
internal_urcu_lock();
rcu_add_reader(pthread_self());
internal_urcu_unlock();
+ _rcu_thread_online();
}
void rcu_unregister_thread(void)
{
+ /*
+ * We have to make the thread offline otherwise we end up dealocking
+ * with a waiting writer.
+ */
+ _rcu_thread_offline();
internal_urcu_lock();
rcu_remove_reader(pthread_self());
internal_urcu_unlock();