Merge remote branch 'origin/urcu/ht' into urcu/ht
[urcu.git] / urcu-bp.c
index db2aef0c57b8ef397095cd71d6c12ded119bb9ec..39a6cd0e9ab3ffe06f1d96eaeb889f77f692ac89 100644 (file)
--- a/urcu-bp.c
+++ b/urcu-bp.c
 #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
@@ -76,6 +111,9 @@ struct registry_arena {
 
 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)
@@ -245,7 +283,6 @@ static void resize_arena(struct registry_arena *arena, size_t len)
        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;
 }
@@ -331,3 +368,47 @@ void rcu_bp_exit()
 {
        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"
This page took 0.023934 seconds and 4 git commands to generate.