runs
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Fri, 6 Feb 2009 01:04:03 +0000 (20:04 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Fri, 6 Feb 2009 01:04:03 +0000 (20:04 -0500)
test_urcu.c
urcu.c
urcu.h

index f9b0e86c375ccdad4c71752e494810627908ba90..8212dfc241748684e4bba7d287ffcb72afe6c406 100644 (file)
@@ -1,27 +1,50 @@
 #include <stdio.h>
 #include <pthread.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <assert.h>
 #include "urcu.h"
 
-#define NR_READ 10
-#define NR_WRITE 4
+struct test_array {
+       int a;
+       int b;
+       char c[200];
+};
+
+static struct test_array *test_rcu_pointer;
+
+#define NR_READ 1000
+#define NR_WRITE 50
 
 
 void *thr_reader(void *arg)
 {
+       int qparity, i;
+       struct test_array *local_ptr;
+
        printf("thread %s, thread id : %lu, pid %lu\n",
                        "reader", pthread_self(), getpid());
        sleep(2);
 
        urcu_register_thread();
 
-
+       for (i = 0; i < 1000; i++) {
+               qparity = rcu_read_lock();
+               local_ptr = rcu_dereference(test_rcu_pointer);
+               if (local_ptr) {
+                       assert(local_ptr->a == 8);
+                       assert(local_ptr->b == 12);
+                       assert(local_ptr->c[55] == 2);
+               }
+               rcu_read_unlock(qparity);
+       }
 
        urcu_unregister_thread();
+
        return ((void*)1);
 
 }
@@ -29,12 +52,28 @@ void *thr_reader(void *arg)
 void *thr_writer(void *arg)
 {
        int i;
+       struct test_array *new, *old;
 
        printf("thread %s, thread id : %lu, pid %lu\n",
                        "writer", pthread_self(), getpid());
        sleep(2);
 
        for (i = 0; i < 1000; i++) {
+               rcu_write_lock();
+               new = malloc(sizeof(struct test_array));
+               old = test_rcu_pointer;
+               if (old) {
+                       assert(old->a == 8);
+                       assert(old->b == 12);
+                       assert(old->c[55] == 2);
+               }
+               assert(new->a = 8);
+               assert(new->b = 12);
+               assert(new->c[55] = 2);
+               old = urcu_publish_content(&test_rcu_pointer, new);
+               rcu_write_unlock();
+               /* can be done after unlock */
+               free(old);
        }
 
        return ((void*)2);
diff --git a/urcu.c b/urcu.c
index c55a5a2be9395ad691876e8e1b58d787729207d4..7e79207be6a88eaaf6d2b74c0b16b4543368a6fd 100644 (file)
--- a/urcu.c
+++ b/urcu.c
@@ -26,6 +26,27 @@ static struct reader_data *reader_data;
 static int num_readers, alloc_readers;
 static int sig_done;
 
+void rcu_write_lock(void)
+{
+       int ret;
+       ret = pthread_mutex_lock(&urcu_mutex);
+       if (ret) {
+               perror("Error in pthread mutex lock");
+               exit(-1);
+       }
+}
+
+void rcu_write_unlock(void)
+{
+       int ret;
+
+       ret = pthread_mutex_unlock(&urcu_mutex);
+       if (ret) {
+               perror("Error in pthread mutex unlock");
+               exit(-1);
+       }
+}
+
 /*
  * called with urcu_mutex held.
  */
@@ -84,18 +105,13 @@ void wait_for_quiescent_state(int parity)
 
 /*
  * Return old pointer, OK to free, no more reference exist.
+ * Called under rcu_write_lock.
  */
 void *urcu_publish_content(void **ptr, void *new)
 {
        int ret, prev_parity;
        void *oldptr;
 
-       ret = pthread_mutex_lock(&urcu_mutex);
-       if (ret) {
-               perror("Error in pthread mutex lock");
-               exit(-1);
-       }
-
        /*
         * We can publish the new pointer before we change the current qparity.
         * Readers seeing the new pointer while being in the previous qparity
@@ -121,11 +137,6 @@ void *urcu_publish_content(void **ptr, void *new)
         * Deleting old data is ok !
         */
        
-       ret = pthread_mutex_unlock(&urcu_mutex);
-       if (ret) {
-               perror("Error in pthread mutex lock");
-               exit(-1);
-       }
        return oldptr;
 }
 
@@ -179,44 +190,17 @@ void urcu_remove_reader(pthread_t id)
 
 void urcu_register_thread(void)
 {
-       pthread_t self = pthread_self();
-       int ret;
-
-       ret = pthread_mutex_lock(&urcu_mutex);
-       if (ret) {
-               perror("Error in pthread mutex lock");
-               exit(-1);
-       }
-
-       urcu_add_reader(self);
-
-
-       ret = pthread_mutex_unlock(&urcu_mutex);
-       if (ret) {
-               perror("Error in pthread mutex unlock");
-               exit(-1);
-       }
+       rcu_write_lock();
+       urcu_add_reader(pthread_self());
+       rcu_write_unlock();
 }
 
 void urcu_unregister_thread(void)
 {
        pthread_t self = pthread_self();
-       int ret;
-
-       ret = pthread_mutex_lock(&urcu_mutex);
-       if (ret) {
-               perror("Error in pthread mutex lock");
-               exit(-1);
-       }
-
-       urcu_remove_reader(self);
-
-       ret = pthread_mutex_unlock(&urcu_mutex);
-       if (ret) {
-               perror("Error in pthread mutex unlock");
-               exit(-1);
-       }
-
+       rcu_write_lock();
+       urcu_remove_reader(pthread_self());
+       rcu_write_unlock();
 }
 
 void sigurcu_handler(int signo, siginfo_t *siginfo, void *context)
diff --git a/urcu.h b/urcu.h
index 363021d7832927e288705e42f7c31f4d36486d72..bee7715270794c3e83cede4acb1741a98d361ac6 100644 (file)
--- a/urcu.h
+++ b/urcu.h
@@ -21,6 +21,36 @@ static inline void atomic_inc(int *v)
 /* Nop everywhere except on alpha. */
 #define smp_read_barrier_depends()
 
+/*
+ * Prevent the compiler from merging or refetching accesses.  The compiler
+ * is also forbidden from reordering successive instances of ACCESS_ONCE(),
+ * but only when the compiler is aware of some particular ordering.  One way
+ * to make the compiler aware of ordering is to put the two invocations of
+ * ACCESS_ONCE() in different C statements.
+ *
+ * This macro does absolutely -nothing- to prevent the CPU from reordering,
+ * merging, or refetching absolutely anything at any time.  Its main intended
+ * use is to mediate communication between process-level code and irq/NMI
+ * handlers, all running on the same CPU.
+ */
+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+
+/**
+ * rcu_dereference - fetch an RCU-protected pointer in an
+ * RCU read-side critical section.  This pointer may later
+ * be safely dereferenced.
+ *
+ * Inserts memory barriers on architectures that require them
+ * (currently only the Alpha), and, more importantly, documents
+ * exactly which pointers are protected by RCU.
+ */
+
+#define rcu_dereference(p)     ({ \
+                               typeof(p) _________p1 = ACCESS_ONCE(p); \
+                               smp_read_barrier_depends(); \
+                               (_________p1); \
+                               })
+
 #define SIGURCU SIGUSR1
 
 /* Global quiescent period parity */
@@ -58,6 +88,9 @@ static inline void rcu_read_unlock(int urcu_parity)
        urcu_active_readers[urcu_parity]--;
 }
 
+extern void rcu_write_lock(void);
+extern void rcu_write_unlock(void);
+
 extern void *urcu_publish_content(void **ptr, void *new);
 
 /*
This page took 0.03829 seconds and 4 git commands to generate.