#include <unistd.h>
#include <sys/mman.h>
-#include "urcu-bp-static.h"
+#include "urcu/map/urcu-bp.h"
+
+#include "urcu/static/urcu-bp.h"
/* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */
#include "urcu-bp.h"
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#ifndef __linux__
+
+#define MREMAP_MAYMOVE 1
+#define MREMAP_FIXED 2
+
+/*
+ * mremap wrapper for non-Linux systems. Maps a RW, anonymous private mapping.
+ * This is not generic.
+*/
+void *mremap(void *old_address, size_t old_size, size_t new_size, int flags)
+{
+ void *new_address;
+
+ assert(flags & MREMAP_MAYMOVE);
+ assert(!(flags & MREMAP_FIXED));
+ new_address = mmap(old_address, new_size,
+ PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE,
+ -1, 0);
+ if (new_address == MAP_FAILED)
+ return MAP_FAILED;
+ if (old_address) {
+ memcpy(new_address, old_address, old_size);
+ munmap(old_address, old_size);
+ }
+ return new_address;
+}
+#endif
+
/* Sleep delay in us */
#define RCU_SLEEP_DELAY 1000
#define ARENA_INIT_ALLOC 16
+/*
+ * Active attempts to check for reader Q.S. before calling sleep().
+ */
+#define RCU_QS_ACTIVE_ATTEMPTS 100
+
void __attribute__((destructor)) rcu_bp_exit(void);
static pthread_mutex_t rcu_gp_lock = PTHREAD_MUTEX_INITIALIZER;
static struct registry_arena registry_arena;
+/* Saved fork signal mask, protected by rcu_gp_lock */
+static sigset_t saved_fork_signal_mask;
+
static void rcu_gc_registry(void);
static void mutex_lock(pthread_mutex_t *mutex)
if (new_arena == arena->p)
return;
- memcpy(new_arena, arena->p, arena->len);
bzero(new_arena + arena->len, len - arena->len);
arena->p = new_arena;
}
if (registry_arena.len
< registry_arena.used + sizeof(struct rcu_reader))
resize_arena(®istry_arena,
- max(registry_arena.len << 1, ARENA_INIT_ALLOC));
+ caa_max(registry_arena.len << 1, ARENA_INIT_ALLOC));
/*
* Find a free spot.
*/
{
munmap(registry_arena.p, registry_arena.len);
}
+
+/*
+ * Holding the rcu_gp_lock across fork will make sure we fork() don't race with
+ * a concurrent thread executing with this same lock held. This ensures that the
+ * registry is in a coherent state in the child.
+ */
+void rcu_bp_before_fork(void)
+{
+ sigset_t newmask, oldmask;
+ int ret;
+
+ ret = sigemptyset(&newmask);
+ assert(!ret);
+ ret = pthread_sigmask(SIG_SETMASK, &newmask, &oldmask);
+ assert(!ret);
+ mutex_lock(&rcu_gp_lock);
+ saved_fork_signal_mask = oldmask;
+}
+
+void rcu_bp_after_fork_parent(void)
+{
+ sigset_t oldmask;
+ int ret;
+
+ oldmask = saved_fork_signal_mask;
+ mutex_unlock(&rcu_gp_lock);
+ ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
+ assert(!ret);
+}
+
+void rcu_bp_after_fork_child(void)
+{
+ sigset_t oldmask;
+ int ret;
+
+ rcu_gc_registry();
+ oldmask = saved_fork_signal_mask;
+ mutex_unlock(&rcu_gp_lock);
+ ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
+ assert(!ret);
+}
+
+#include "urcu-call-rcu-impl.h"
+#include "urcu-defer-impl.h"