From 4d1ce26fea0296ff67791c881836393fdd020cf9 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Sep 2009 19:01:10 -0400 Subject: [PATCH 1/1] add rcu_cmpxchg_pointer Signed-off-by: Mathieu Desnoyers --- urcu-qsbr-static.h | 16 ++++++++++++++++ urcu-qsbr.c | 6 ++++++ urcu-qsbr.h | 4 ++++ urcu-static.h | 16 ++++++++++++++++ urcu.c | 6 ++++++ urcu.h | 4 ++++ 6 files changed, 52 insertions(+) diff --git a/urcu-qsbr-static.h b/urcu-qsbr-static.h index 22a93b2..c0467cd 100644 --- a/urcu-qsbr-static.h +++ b/urcu-qsbr-static.h @@ -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 diff --git a/urcu-qsbr.c b/urcu-qsbr.c index f681c05..5c6eaa0 100644 --- a/urcu-qsbr.c +++ b/urcu-qsbr.c @@ -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(); diff --git a/urcu-qsbr.h b/urcu-qsbr.h index 9a2c82f..346f906 100644 --- a/urcu-qsbr.h +++ b/urcu-qsbr.h @@ -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)) diff --git a/urcu-static.h b/urcu-static.h index 0c6891e..f819e6f 100644 --- a/urcu-static.h +++ b/urcu-static.h @@ -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 d474fc8..a8f85c6 100644 --- 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 af7d75c..5d92aa7 100644 --- 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)) -- 2.34.1