add rcu_cmpxchg_pointer
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Tue, 22 Sep 2009 23:01:10 +0000 (19:01 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Tue, 22 Sep 2009 23:01:10 +0000 (19:01 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
urcu-qsbr-static.h
urcu-qsbr.c
urcu-qsbr.h
urcu-static.h
urcu.c
urcu.h

index 22a93b2fd7a823d21c76cbbd1ad5c6bf3b0495e4..c0467cd0e1606c87a522e56d2299716cf6402b3e 100644 (file)
@@ -244,6 +244,22 @@ static inline void _rcu_thread_online(void)
                STORE_SHARED(p, v);                     \
        })
 
+/**
+ * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer
+ * is as expected by "old". If succeeds, returns the previous pointer to the
+ * data structure, which can be safely freed after waiting for a quiescent state
+ * using synchronize_rcu(). If fails (unexpected value), returns old (which
+ * should not be freed !).
+ */
+
+#define _rcu_cmpxchg_pointer(p, old, _new)             \
+       ({                                              \
+               if (!__builtin_constant_p(_new) ||      \
+                   ((_new) != NULL))                   \
+                       wmb();                          \
+               cmpxchg(p, old, _new);                  \
+       })
+
 /**
  * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous
  * pointer to the data structure, which can be safely freed after waiting for a
index f681c05bf0c05d96860e06cbb8771b11c9e3e829..5c6eaa014721267da7de5f85fff22835d41a80b2 100644 (file)
@@ -255,6 +255,12 @@ void *rcu_assign_pointer_sym(void **p, void *v)
        return STORE_SHARED(p, v);
 }
 
+void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new)
+{
+       wmb();
+       return cmpxchg(p, old, _new);
+}
+
 void *rcu_xchg_pointer_sym(void **p, void *v)
 {
        wmb();
index 9a2c82f4b1e503155de664a545c8c5e5697c5608..346f906202aa60edc8f5c77628e18af5f130361a 100644 (file)
@@ -103,6 +103,10 @@ extern void *rcu_assign_pointer_sym(void **p, void *v);
 #define rcu_assign_pointer(p, v)                       \
        rcu_assign_pointer_sym((void **)(p), (v))
 
+extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new);
+#define rcu_cmpxchg_pointer(p, old, _new)              \
+       rcu_cmpxchg_pointer_sym((void **)(p), (old), (_new))
+
 extern void *rcu_xchg_pointer_sym(void **p, void *v);
 #define rcu_xchg_pointer(p, v)                         \
        rcu_xchg_pointer_sym((void **)(p), (v))
index 0c6891e77ca0871f85cd1461333c0facd95bcf13..f819e6fc9aa07e9f4e58329661bf5a494936bb25 100644 (file)
@@ -276,6 +276,22 @@ static inline void _rcu_read_unlock(void)
                STORE_SHARED(p, v);                     \
        })
 
+/**
+ * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer
+ * is as expected by "old". If succeeds, returns the previous pointer to the
+ * data structure, which can be safely freed after waiting for a quiescent state
+ * using synchronize_rcu(). If fails (unexpected value), returns old (which
+ * should not be freed !).
+ */
+
+#define _rcu_cmpxchg_pointer(p, old, _new)             \
+       ({                                              \
+               if (!__builtin_constant_p(_new) ||      \
+                   ((_new) != NULL))                   \
+                       wmb();                          \
+               cmpxchg(p, old, _new);                  \
+       })
+
 /**
  * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous
  * pointer to the data structure, which can be safely freed after waiting for a
diff --git a/urcu.c b/urcu.c
index d474fc8a3e8311c036f151698afdeaab7bde192a..a8f85c6f02199d4ecdfb20b1a0098cef213c138c 100644 (file)
--- a/urcu.c
+++ b/urcu.c
@@ -347,6 +347,12 @@ void *rcu_xchg_pointer_sym(void **p, void *v)
        return xchg(p, v);
 }
 
+void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new)
+{
+       wmb();
+       return cmpxchg(p, old, _new);
+}
+
 void *rcu_publish_content_sym(void **p, void *v)
 {
        void *oldptr;
diff --git a/urcu.h b/urcu.h
index af7d75cb7bc9e389ba9896a9207695d4feea9540..5d92aa7232d4d0b53d262115fefc470d14286af0 100644 (file)
--- a/urcu.h
+++ b/urcu.h
@@ -75,6 +75,10 @@ extern void *rcu_assign_pointer_sym(void **p, void *v);
 #define rcu_assign_pointer(p, v)                       \
        rcu_assign_pointer_sym((void **)(p), (v))
 
+extern void *rcu_cmpxchg_pointer_sym(void **p, void *old, void *_new);
+#define rcu_cmpxchg_pointer(p, old, _new)              \
+       rcu_cmpxchg_pointer_sym((void **)(p), (old), (_new))
+
 extern void *rcu_xchg_pointer_sym(void **p, void *v);
 #define rcu_xchg_pointer(p, v)                         \
        rcu_xchg_pointer_sym((void **)(p), (v))
This page took 0.027955 seconds and 4 git commands to generate.