new list.h with {READ,WRITE}_ONCE
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "rwonce.h"
|
||||
|
||||
/************ originally in <include/linux/types.h> */
|
||||
struct list_head {
|
||||
@@ -61,7 +62,7 @@ struct hlist_node {
|
||||
*/
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
WRITE_ONCE(list->next, list);
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
@@ -78,7 +79,7 @@ static inline void __list_add(struct list_head *new,
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
WRITE_ONCE(prev->next, new);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +119,7 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
WRITE_ONCE(prev->next, next);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -284,7 +285,7 @@ static inline int list_is_last(const struct list_head *list,
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
return READ_ONCE(head->next) == head;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -510,7 +511,7 @@ static inline void list_splice_tail_init(struct list_head *list,
|
||||
*/
|
||||
#define list_first_entry_or_null(ptr, type, member) ({ \
|
||||
struct list_head *head__ = (ptr); \
|
||||
struct list_head *pos__ = head__->next; \
|
||||
struct list_head *pos__ = READ_ONCE(head__->next); \
|
||||
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
|
||||
})
|
||||
|
||||
@@ -786,7 +787,7 @@ static inline int hlist_unhashed(const struct hlist_node *h)
|
||||
*/
|
||||
static inline int hlist_unhashed_lockless(const struct hlist_node *h)
|
||||
{
|
||||
return !h->pprev;
|
||||
return !READ_ONCE(h->pprev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -795,7 +796,7 @@ static inline int hlist_unhashed_lockless(const struct hlist_node *h)
|
||||
*/
|
||||
static inline int hlist_empty(const struct hlist_head *h)
|
||||
{
|
||||
return !h->first;
|
||||
return !READ_ONCE(h->first);
|
||||
}
|
||||
|
||||
static inline void __hlist_del(struct hlist_node *n)
|
||||
@@ -803,9 +804,9 @@ static inline void __hlist_del(struct hlist_node *n)
|
||||
struct hlist_node *next = n->next;
|
||||
struct hlist_node **pprev = n->pprev;
|
||||
|
||||
*pprev = next;
|
||||
WRITE_ONCE(*pprev, next);
|
||||
if (next)
|
||||
next->pprev = pprev;
|
||||
WRITE_ONCE(next->pprev, pprev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -847,11 +848,11 @@ static inline void hlist_del_init(struct hlist_node *n)
|
||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
struct hlist_node *first = h->first;
|
||||
n->next = first;
|
||||
WRITE_ONCE(n->next, first);
|
||||
if (first)
|
||||
first->pprev = &n->next;
|
||||
h->first = n;
|
||||
n->pprev = &h->first;
|
||||
WRITE_ONCE(first->pprev, &n->next);
|
||||
WRITE_ONCE(h->first, n);
|
||||
WRITE_ONCE(n->pprev, &h->first);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -862,10 +863,10 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
static inline void hlist_add_before(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
n->pprev = next->pprev;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
*(n->pprev) = n;
|
||||
WRITE_ONCE(n->pprev, next->pprev);
|
||||
WRITE_ONCE(n->next, next);
|
||||
WRITE_ONCE(next->pprev, &n->next);
|
||||
WRITE_ONCE(*(n->pprev), n);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -876,12 +877,12 @@ static inline void hlist_add_before(struct hlist_node *n,
|
||||
static inline void hlist_add_behind(struct hlist_node *n,
|
||||
struct hlist_node *prev)
|
||||
{
|
||||
n->next = prev->next;
|
||||
prev->next = n;
|
||||
n->pprev = &prev->next;
|
||||
WRITE_ONCE(n->next, prev->next);
|
||||
WRITE_ONCE(prev->next, n);
|
||||
WRITE_ONCE(n->pprev, &prev->next);
|
||||
|
||||
if (n->next)
|
||||
n->next->pprev = &n->next;
|
||||
WRITE_ONCE(n->next->pprev, &n->next);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -993,4 +994,4 @@ static inline void hlist_move_list(struct hlist_head *old,
|
||||
pos && ({ n = pos->member.next; 1; }); \
|
||||
pos = hlist_entry_safe(n, __typeof__(*pos), member))
|
||||
|
||||
#endif
|
||||
#endif /* __BR_LIST_H */
|
||||
|
124
2021/include/rwonce.h
Normal file
124
2021/include/rwonce.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/* 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_types.h> */
|
||||
# define __compiletime_error(message) __attribute__((error(message)))
|
||||
|
||||
/************ 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 */
|
Reference in New Issue
Block a user