63 lines
2.4 KiB
C
63 lines
2.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
#ifndef __LINUX_RCU_ASSIGN_POINTER_H__
|
|
#define __LINUX_RCU_ASSIGN_POINTER_H__
|
|
#include <linux/compiler.h>
|
|
#include <asm/barrier.h>
|
|
|
|
#ifdef __CHECKER__
|
|
#define rcu_check_sparse(p, space) \
|
|
((void)(((typeof(*p) space *)p) == p))
|
|
#else /* #ifdef __CHECKER__ */
|
|
#define rcu_check_sparse(p, space)
|
|
#endif /* #else #ifdef __CHECKER__ */
|
|
|
|
/**
|
|
* 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 { \
|
|
uintptr_t _r_a_p__v = (uintptr_t)(v); \
|
|
rcu_check_sparse(p, __rcu); \
|
|
\
|
|
if (__builtin_constant_p(v) && (_r_a_p__v) == (uintptr_t)NULL) \
|
|
WRITE_ONCE((p), (typeof(p))(_r_a_p__v)); \
|
|
else \
|
|
smp_store_release(&p, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \
|
|
} while (0)
|
|
|
|
#endif
|