Use xchg in publish content
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Mon, 9 Feb 2009 05:54:50 +0000 (00:54 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Mon, 9 Feb 2009 05:54:50 +0000 (00:54 -0500)
Also changes the publish content parameter. Now takes the pointer itself as
first parameter rather than a pointer to the pointer.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
test_urcu.c
test_urcu_timing.c
urcu.c
urcu.h

index 39408a0bdd6d7141915b66222a9d64a7f655a7c3..b92a7d74de5c23fd55d5959e8e5f514d314ef090 100644 (file)
@@ -127,7 +127,7 @@ void *thr_writer(void *arg)
                if (old)
                        assert(old->a == 8);
                new->a = 8;
-               old = urcu_publish_content((void **)&test_rcu_pointer, new);
+               old = urcu_publish_content(&test_rcu_pointer, new);
                rcu_copy_mutex_unlock();
                /* can be done after unlock */
                if (old)
index 9903705c6c74fbcf08efed40eb72b5050f069dff..f97a5c1e3c9a15d3055c596a72a3d4d9e61d3fbc 100644 (file)
@@ -145,7 +145,7 @@ void *thr_writer(void *arg)
                        assert(old->a == 8);
                }
                new->a = 8;
-               old = urcu_publish_content((void **)&test_rcu_pointer, new);
+               old = urcu_publish_content(&test_rcu_pointer, new);
                rcu_copy_mutex_unlock();
                /* can be done after unlock */
                if (old) {
diff --git a/urcu.c b/urcu.c
index 23a985b9f9f4cdaf992c227322720e38bc139d85..9fde6238f695b06db846866a704f9ed595bd6d0c 100644 (file)
--- a/urcu.c
+++ b/urcu.c
@@ -151,42 +151,6 @@ void synchronize_rcu(void)
        debug_yield_write();
 }
 
-/*
- * Return old pointer, OK to free, no more reference exist.
- * Called under rcu_write_lock.
- */
-void *urcu_publish_content(void **ptr, void *new)
-{
-       void *oldptr;
-
-       debug_yield_write();
-       internal_urcu_lock();
-       debug_yield_write();
-       /*
-        * We can publish the new pointer before we change the current qparity.
-        * Readers seeing the new pointer while being in the previous qparity
-        * window will make us wait until the end of the quiescent state before
-        * we release the unrelated memory area. However, given we hold the
-        * urcu_mutex, we are making sure that no further garbage collection can
-        * occur until we release the mutex, therefore we guarantee that this
-        * given reader will have completed its execution using the new pointer
-        * when the next quiescent state window will be over.
-        */
-       oldptr = *ptr;
-       debug_yield_write();
-       rcu_assign_pointer(*ptr, new);
-
-       debug_yield_write();
-       switch_qparity();
-       debug_yield_write();
-       switch_qparity();
-       debug_yield_write();
-       internal_urcu_unlock();
-       debug_yield_write();
-
-       return oldptr;
-}
-
 void urcu_add_reader(pthread_t id)
 {
        struct reader_data *oldarray;
diff --git a/urcu.h b/urcu.h
index 27695d495aeeb6388b121a099183949cbbdbac06..fb8cedf3e15beab5ba5355b153d0bb999fa1c7fc 100644 (file)
--- a/urcu.h
+++ b/urcu.h
@@ -33,6 +33,45 @@ static inline void atomic_inc(int *v)
                     : "+m" (*v));
 }
 
+#define xchg(ptr, v)                                                   \
+       ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), sizeof(*(ptr))))
+
+struct __xchg_dummy {
+       unsigned long a[100];
+};
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ *       but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+                                  int size)
+{
+       switch (size) {
+       case 1:
+               asm volatile("xchgb %b0,%1"
+                            : "=q" (x)
+                            : "m" (*__xg(ptr)), "0" (x)
+                            : "memory");
+               break;
+       case 2:
+               asm volatile("xchgw %w0,%1"
+                            : "=r" (x)
+                            : "m" (*__xg(ptr)), "0" (x)
+                            : "memory");
+               break;
+       case 4:
+               asm volatile("xchgl %0,%1"
+                            : "=r" (x)
+                            : "m" (*__xg(ptr)), "0" (x)
+                            : "memory");
+               break;
+       }
+       return x;
+}
+
 /* Nop everywhere except on alpha. */
 #define smp_read_barrier_depends()
 
@@ -190,9 +229,29 @@ static inline void rcu_read_unlock(void)
                (p) = (v); \
        })
 
-extern void *urcu_publish_content(void **ptr, void *new);
+#define rcu_xchg_pointer(p, v) \
+       ({ \
+               if (!__builtin_constant_p(v) || \
+                   ((v) != NULL)) \
+                       wmb(); \
+               xchg(p, v); \
+       })
+
 extern void synchronize_rcu(void);
 
+/*
+ * Exchanges the pointer and waits for quiescent state.
+ * The pointer returned can be freed.
+ */
+#define urcu_publish_content(p, v) \
+       ({ \
+               void *oldptr; \
+               debug_yield_write(); \
+               oldptr = rcu_xchg_pointer(p, v); \
+               synchronize_rcu(); \
+               oldptr; \
+       })
+
 /*
  * Reader thread registration.
  */
This page took 0.027695 seconds and 4 git commands to generate.