urcu call_rcu: Use RCU read-side protection for per-cpu call_rcu data
[urcu.git] / urcu-bp.c
index b457d2bc8f6e49fee5b55565107219aaf02d6ee9..4c0ab54a28e71b47947905d6f5f42354de0135cd 100644 (file)
--- a/urcu-bp.c
+++ b/urcu-bp.c
@@ -24,6 +24,7 @@
  */
 
 #define _GNU_SOURCE
+#define _LGPL_SOURCE
 #include <stdio.h>
 #include <pthread.h>
 #include <signal.h>
 #include <unistd.h>
 #include <sys/mman.h>
 
-#include "urcu-bp-static.h"
+#include "urcu/wfqueue.h"
+#include "urcu/map/urcu-bp.h"
+#include "urcu/static/urcu-bp.h"
+#include "urcu-pointer.h"
+
 /* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */
+#undef _LGPL_SOURCE
 #include "urcu-bp.h"
+#define _LGPL_SOURCE
+
+#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;
@@ -66,7 +111,7 @@ long rcu_gp_ctr = RCU_GP_COUNT;
  */
 struct rcu_reader __thread *rcu_reader;
 
-static LIST_HEAD(registry);
+static CDS_LIST_HEAD(registry);
 
 struct registry_arena {
        void *p;
@@ -76,6 +121,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)
@@ -95,11 +143,6 @@ static void mutex_lock(pthread_mutex_t *mutex)
                        perror("Error in pthread mutex lock");
                        exit(-1);
                }
-               if (rcu_reader.need_mb) {
-                       cmm_smp_mb();
-                       rcu_reader.need_mb = 0;
-                       cmm_smp_mb();
-               }
                poll(NULL,0,10);
        }
 #endif /* #else #ifndef DISTRUST_SIGNALS_EXTREME */
@@ -118,18 +161,18 @@ static void mutex_unlock(pthread_mutex_t *mutex)
 
 void update_counter_and_wait(void)
 {
-       LIST_HEAD(qsreaders);
+       CDS_LIST_HEAD(qsreaders);
        int wait_loops = 0;
        struct rcu_reader *index, *tmp;
 
        /* Switch parity: 0 -> 1, 1 -> 0 */
-       CAA_STORE_SHARED(rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR_PHASE);
+       CMM_STORE_SHARED(rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR_PHASE);
 
        /*
         * Must commit qparity update to memory before waiting for other parity
         * quiescent state. Failure to do so could result in the writer waiting
         * forever while new readers are always accessing data (no progress).
-        * Ensured by CAA_STORE_SHARED and CAA_LOAD_SHARED.
+        * Ensured by CMM_STORE_SHARED and CMM_LOAD_SHARED.
         */
 
        /*
@@ -144,12 +187,12 @@ void update_counter_and_wait(void)
         */
        for (;;) {
                wait_loops++;
-               list_for_each_entry_safe(index, tmp, &registry, node) {
+               cds_list_for_each_entry_safe(index, tmp, &registry, node) {
                        if (!rcu_old_gp_ongoing(&index->ctr))
-                               list_move(&index->node, &qsreaders);
+                               cds_list_move(&index->node, &qsreaders);
                }
 
-               if (list_empty(&registry)) {
+               if (cds_list_empty(&registry)) {
                        break;
                } else {
                        if (wait_loops == RCU_QS_ACTIVE_ATTEMPTS)
@@ -159,7 +202,7 @@ void update_counter_and_wait(void)
                }
        }
        /* put back the reader list in the registry */
-       list_splice(&qsreaders, &registry);
+       cds_list_splice(&qsreaders, &registry);
 }
 
 void synchronize_rcu(void)
@@ -174,7 +217,7 @@ void synchronize_rcu(void)
 
        mutex_lock(&rcu_gp_lock);
 
-       if (list_empty(&registry))
+       if (cds_list_empty(&registry))
                goto out;
 
        /* All threads should read qparity before accessing data structure
@@ -250,7 +293,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;
 }
@@ -263,7 +305,7 @@ static void add_thread(void)
        if (registry_arena.len
            < registry_arena.used + sizeof(struct rcu_reader))
                resize_arena(&registry_arena,
-               max(registry_arena.len << 1, ARENA_INIT_ALLOC));
+               caa_max(registry_arena.len << 1, ARENA_INIT_ALLOC));
        /*
         * Find a free spot.
         */
@@ -279,7 +321,7 @@ static void add_thread(void)
        /* Add to registry */
        rcu_reader_reg->tid = pthread_self();
        assert(rcu_reader_reg->ctr == 0);
-       list_add(&rcu_reader_reg->node, &registry);
+       cds_list_add(&rcu_reader_reg->node, &registry);
        rcu_reader = rcu_reader_reg;
 }
 
@@ -299,7 +341,7 @@ static void rcu_gc_registry(void)
                ret = pthread_kill(tid, 0);
                assert(ret != EINVAL);
                if (ret == ESRCH) {
-                       list_del(&rcu_reader_reg->node);
+                       cds_list_del(&rcu_reader_reg->node);
                        rcu_reader_reg->ctr = 0;
                        rcu_reader_reg->alloc = 0;
                        registry_arena.used -= sizeof(struct rcu_reader);
@@ -332,7 +374,52 @@ end:
        assert(!ret);
 }
 
-void rcu_bp_exit()
+void rcu_bp_exit(void)
 {
-       munmap(registry_arena.p, registry_arena.len);
+       if (registry_arena.p)
+               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.025695 seconds and 4 git commands to generate.