diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-11-11 09:59:34 -0800 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-12-12 12:24:23 -0800 |
commit | 462225ae47d7175f886281d8a91708550cd5178c (patch) | |
tree | 46048d886502e6a177a485a965f5f3371f545d43 | |
parent | 9d162cd06349dfee6b4f254b3abf1355cf0aee43 (diff) | |
download | kernel-common-462225ae47d7175f886281d8a91708550cd5178c.tar.gz kernel-common-462225ae47d7175f886281d8a91708550cd5178c.tar.bz2 kernel-common-462225ae47d7175f886281d8a91708550cd5178c.zip |
rcu: Add an RCU_INITIALIZER for global RCU-protected pointers
There is currently no way to initialize a global RCU-protected pointer
without either putting up with sparse complaints or open-coding an
obscure cast. This commit therefore creates RCU_INITIALIZER(), which
is intended to be used as follows:
struct foo __rcu *p = RCU_INITIALIZER(&my_rcu_structure);
This commit also applies RCU_INITIALIZER() to eliminate repeated
open-coded obscure casts in __rcu_assign_pointer(), RCU_INIT_POINTER(),
and RCU_POINTER_INITIALIZER(). This commit also inlines
__rcu_assign_pointer() into its only caller, rcu_assign_pointer().
Suggested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
-rw-r--r-- | include/linux/rcupdate.h | 80 |
1 files changed, 42 insertions, 38 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 97853cd2d7b4..ea3816cf1a13 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -548,10 +548,48 @@ static inline void rcu_preempt_sleep_check(void) smp_read_barrier_depends(); \ (_________p1); \ }) -#define __rcu_assign_pointer(p, v, space) \ + +/** + * RCU_INITIALIZER() - statically initialize an RCU-protected global variable + * @v: The value to statically initialize with. + */ +#define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) + +/** + * rcu_assign_pointer() - assign to RCU-protected pointer + * @p: pointer to assign to + * @v: value to assign (publish) + * + * Assigns the specified value to the specified RCU-protected + * pointer, ensuring that any concurrent RCU readers will see + * any prior initialization. + * + * Inserts memory barriers on architectures that require them + * (which is most of them), and also prevents the compiler from + * reordering the code that initializes the structure after the pointer + * assignment. More importantly, this call documents which pointers + * will be dereferenced by RCU read-side code. + * + * In some special cases, you may use RCU_INIT_POINTER() instead + * of rcu_assign_pointer(). RCU_INIT_POINTER() is a bit faster due + * to the fact that it does not constrain either the CPU or the compiler. + * That said, using RCU_INIT_POINTER() when you should have used + * rcu_assign_pointer() is a very bad thing that results in + * impossible-to-diagnose memory corruption. So please be careful. + * See the RCU_INIT_POINTER() comment header for details. + * + * Note that rcu_assign_pointer() evaluates each of its arguments only + * once, appearances notwithstanding. One of the "extra" evaluations + * is in typeof() and the other visible only to sparse (__CHECKER__), + * neither of which actually execute the argument. As with most cpp + * macros, this execute-arguments-only-once property is important, so + * please be careful when making changes to rcu_assign_pointer() and the + * other macros that it invokes. + */ +#define rcu_assign_pointer(p, v) \ do { \ smp_wmb(); \ - ACCESS_ONCE(p) = (typeof(*(v)) __force space *)(v); \ + ACCESS_ONCE(p) = RCU_INITIALIZER(v); \ } while (0) @@ -890,40 +928,6 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) } /** - * rcu_assign_pointer() - assign to RCU-protected pointer - * @p: pointer to assign to - * @v: value to assign (publish) - * - * Assigns the specified value to the specified RCU-protected - * pointer, ensuring that any concurrent RCU readers will see - * any prior initialization. - * - * Inserts memory barriers on architectures that require them - * (which is most of them), and also prevents the compiler from - * reordering the code that initializes the structure after the pointer - * assignment. More importantly, this call documents which pointers - * will be dereferenced by RCU read-side code. - * - * In some special cases, you may use RCU_INIT_POINTER() instead - * of rcu_assign_pointer(). RCU_INIT_POINTER() is a bit faster due - * to the fact that it does not constrain either the CPU or the compiler. - * That said, using RCU_INIT_POINTER() when you should have used - * rcu_assign_pointer() is a very bad thing that results in - * impossible-to-diagnose memory corruption. So please be careful. - * See the RCU_INIT_POINTER() comment header for details. - * - * Note that rcu_assign_pointer() evaluates each of its arguments only - * once, appearances notwithstanding. One of the "extra" evaluations - * is in typeof() and the other visible only to sparse (__CHECKER__), - * neither of which actually execute the argument. As with most cpp - * macros, this execute-arguments-only-once property is important, so - * please be careful when making changes to rcu_assign_pointer() and the - * other macros that it invokes. - */ -#define rcu_assign_pointer(p, v) \ - __rcu_assign_pointer((p), (v), __rcu) - -/** * RCU_INIT_POINTER() - initialize an RCU protected pointer * * Initialize an RCU-protected pointer in special cases where readers @@ -957,7 +961,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) */ #define RCU_INIT_POINTER(p, v) \ do { \ - p = (typeof(*v) __force __rcu *)(v); \ + p = RCU_INITIALIZER(v); \ } while (0) /** @@ -966,7 +970,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) * GCC-style initialization for an RCU-protected pointer in a structure field. */ #define RCU_POINTER_INITIALIZER(p, v) \ - .p = (typeof(*v) __force __rcu *)(v) + .p = RCU_INITIALIZER(v) /* * Does the specified offset indicate that the corresponding rcu_head |