129 lines
5.6 KiB
C
129 lines
5.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/* adaptation of kernel's <asm-generic/rwonce.h>
|
|
* See https://www.kernel.org/doc/Documentation/memory-barriers.txt
|
|
*/
|
|
/*
|
|
* Prevent the compiler from merging or refetching reads or writes. The
|
|
* compiler is also forbidden from reordering successive instances of
|
|
* READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some
|
|
* particular ordering. One way to make the compiler aware of ordering is to
|
|
* put the two invocations of READ_ONCE or WRITE_ONCE in different C
|
|
* statements.
|
|
*
|
|
* These two macros will also work on aggregate data types like structs or
|
|
* unions.
|
|
*
|
|
* Their two major use cases are: (1) Mediating communication between
|
|
* process-level code and irq/NMI handlers, all running on the same CPU,
|
|
* and (2) Ensuring that the compiler does not fold, spindle, or otherwise
|
|
* mutilate accesses that either do not require ordering or that interact
|
|
* with an explicit memory barrier or atomic instruction that provides the
|
|
* required ordering.
|
|
*/
|
|
#ifndef __BR_RWONCE_H
|
|
#define __BR_RWONCE_H
|
|
|
|
/************ originally in <include/linux/compiler_attributes.h> */
|
|
#if __has_attribute(__error__)
|
|
# define __compiletime_error(msg) __attribute__((__error__(msg)))
|
|
#else
|
|
# define __compiletime_error(msg)
|
|
#endif
|
|
|
|
/************ originally in <include/linux/compiler_types.h> */
|
|
/*
|
|
* __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving
|
|
* non-scalar types unchanged.
|
|
*/
|
|
/*
|
|
* Prefer C11 _Generic for better compile-times and simpler code. Note: 'char'
|
|
* is not type-compatible with 'signed char', and we define a separate case.
|
|
*/
|
|
#define __scalar_type_to_expr_cases(type) \
|
|
unsigned type: (unsigned type)0, \
|
|
signed type: (signed type)0
|
|
|
|
#define __unqual_scalar_typeof(x) \
|
|
typeof(_Generic((x), \
|
|
char: (char)0, \
|
|
__scalar_type_to_expr_cases(char), \
|
|
__scalar_type_to_expr_cases(short), \
|
|
__scalar_type_to_expr_cases(int), \
|
|
__scalar_type_to_expr_cases(long), \
|
|
__scalar_type_to_expr_cases(long long), \
|
|
default: (x)))
|
|
|
|
/* Is this type a native word size -- useful for atomic operations */
|
|
#define __native_word(t) \
|
|
(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \
|
|
sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
|
|
|
|
#ifdef __OPTIMIZE__
|
|
# define __compiletime_assert(condition, msg, prefix, suffix) \
|
|
do { \
|
|
extern void prefix ## suffix(void) __compiletime_error(msg); \
|
|
if (!(condition)) \
|
|
prefix ## suffix(); \
|
|
} while (0)
|
|
#else
|
|
# define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0)
|
|
#endif
|
|
|
|
#define _compiletime_assert(condition, msg, prefix, suffix) \
|
|
__compiletime_assert(condition, msg, prefix, suffix)
|
|
|
|
/**
|
|
* compiletime_assert - break build and emit msg if condition is false
|
|
* @condition: a compile-time constant condition to check
|
|
* @msg: a message to emit if condition is false
|
|
*
|
|
* In tradition of POSIX assert, this macro will break the build if the
|
|
* supplied condition is *false*, emitting the supplied error message if the
|
|
* compiler has support to do so.
|
|
*/
|
|
#define compiletime_assert(condition, msg) \
|
|
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
|
|
|
|
#define compiletime_assert_atomic_type(t) \
|
|
compiletime_assert(__native_word(t), \
|
|
"Need native word sized stores/loads for atomicity.")
|
|
|
|
/************ originally in <asm-generic/rwonce.h> */
|
|
/*
|
|
* Yes, this permits 64-bit accesses on 32-bit architectures. These will
|
|
* actually be atomic in some cases (namely Armv7 + LPAE), but for others we
|
|
* rely on the access being split into 2x32-bit accesses for a 32-bit quantity
|
|
* (e.g. a virtual address) and a strong prevailing wind.
|
|
*/
|
|
#define compiletime_assert_rwonce_type(t) \
|
|
compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
|
|
"Unsupported access size for {READ,WRITE}_ONCE().")
|
|
|
|
/*
|
|
* Use __READ_ONCE() instead of READ_ONCE() if you do not require any
|
|
* atomicity. Note that this may result in tears!
|
|
*/
|
|
#ifndef __READ_ONCE
|
|
#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
|
|
#endif
|
|
|
|
#define READ_ONCE(x) \
|
|
({ \
|
|
compiletime_assert_rwonce_type(x); \
|
|
__READ_ONCE(x); \
|
|
})
|
|
|
|
#define __WRITE_ONCE(x, val) \
|
|
do { \
|
|
*(volatile typeof(x) *)&(x) = (val); \
|
|
} while (0)
|
|
|
|
#define WRITE_ONCE(x, val) \
|
|
do { \
|
|
compiletime_assert_rwonce_type(x); \
|
|
__WRITE_ONCE(x, val); \
|
|
} while (0)
|
|
|
|
#endif /* __BR_RWONCE_H */
|