XenevaOS
Loading...
Searching...
No Matches
llist.h
Go to the documentation of this file.
1#ifndef __LINUX_LLIST_H__
2#define __LINUX_LLIST_H__
3
4/*
5 * DCL <linux/llist.h> -- the lockless singly-linked list tty_buffer.c keeps
6 * its *free* buffers on.
7 *
8 * It exists for one specific shape of traffic: a tiny buffer (<= 256 bytes)
9 * is recycled far more often than it is created, and the free list is touched
10 * both from flush_to_ldisc() and from the driver's allocation path. A singly
11 * linked list with an atomic head swap needs no per-node back pointers and no
12 * lock, which is what those two callers want.
13 *
14 * Deliberately a subset of mainline: llist_add_batch() and the _cc variants
15 * are omitted because nothing in the staged tty/serial set calls them. Adding
16 * them when something does beats carrying a surface nobody has compiled.
17 *
18 * The subtle part is llist_for_each_entry_safe(): it must not run its body
19 * when handed a NULL node (an empty list), and `container_of(NULL, type, m)`
20 * is a *computed address*, not NULL -- so the guard is the address of the
21 * member itself, which folds back to exactly 0:
22 *
23 * pos = container_of(NULL, struct tty_buffer, free); // pos != NULL
24 * &pos->member == NULL // but this is 0
25 *
26 * That is mainline's own trick (member_address_is_nonnull), and the arithmetic
27 * is done in integers so it never forms a non-canonical pointer the CPU could
28 * touch -- the body is guarded before anything is dereferenced.
29 *
30 * The integer is uintptr_t, not mainline's `unsigned long`. This target is
31 * aarch64 *Windows*, which is LLP64: unsigned long is 32 bits, so casting a
32 * pointer through it truncates. That is not a theoretical concern here -- it
33 * is what produced "cast to smaller integer type 'unsigned long' from
34 * 'struct llist_node *'" on tty_buffer.c:142, and a buffer whose address ends
35 * in 0x????????0000 would have read as 0 after truncation, silently ending
36 * the free-list walk one buffer early. uintptr_t is the type that is wide
37 * enough by definition, and it silences the warning as a side effect.
38 */
39
40#include <linux/kernel.h> /* container_of, bool, uintptr_t */
41
42struct llist_node {
44};
45
46struct llist_head {
48};
49
50#define llist_entry(ptr, type, member) container_of(ptr, type, member)
51
52/*
53 * uintptr_t, not unsigned long: see the note above this block. On this LLP64
54 * target unsigned long would truncate the address to 32 bits.
55 */
56#define member_address_is_nonnull(ptr, member) \
57 ((uintptr_t)&(ptr)->member != (uintptr_t)0)
58
59#define llist_for_each_entry_safe(pos, n, node, member) \
60 for (pos = llist_entry((node), typeof(*pos), member); \
61 member_address_is_nonnull(pos, member) && \
62 (n = llist_entry(pos->member.next, typeof(*n), member), 1); \
63 pos = n)
64
65static inline void init_llist_head(struct llist_head* head)
66{
67 head->first = 0;
68}
69
70static inline bool llist_empty(const struct llist_head* head)
71{
72 return __atomic_load_n(&head->first, __ATOMIC_ACQUIRE) == 0;
73}
74
75/*
76 * Head is a single pointer, so both directions use a CAS rather than trusting
77 * a load-then-store: tty_buffer_free() can run from the work path while the
78 * driver allocates from IRQ context on the same core.
79 */
80static inline int llist_add(struct llist_node* new, struct llist_head* head)
81{
82 struct llist_node* first;
83
84 do {
85 first = __atomic_load_n(&head->first, __ATOMIC_RELAXED);
86 __atomic_store_n(&new->next, first, __ATOMIC_RELAXED);
87 } while (!__atomic_compare_exchange_n(&head->first, &first, new, 0,
88 __ATOMIC_RELEASE, __ATOMIC_RELAXED));
89
90 return first == 0; /* mainline: true if the list was empty */
91}
92
93static inline struct llist_node* llist_del_all(struct llist_head* head)
94{
95 return __atomic_exchange_n(&head->first, 0, __ATOMIC_ACQ_REL);
96}
97
98static inline struct llist_node* llist_del_first(struct llist_head* head)
99{
100 struct llist_node* first;
101 struct llist_node* next;
102
103 do {
104 first = __atomic_load_n(&head->first, __ATOMIC_ACQUIRE);
105 if (!first)
106 return 0;
107 next = __atomic_load_n(&first->next, __ATOMIC_RELAXED);
108 } while (!__atomic_compare_exchange_n(&head->first, &first, next, 0,
109 __ATOMIC_ACQ_REL, __ATOMIC_RELAXED));
110
111 return first;
112}
113
114#endif /* __LINUX_LLIST_H__ */
int const struct list_head const struct list_head struct list_head * head
Definition list_sort.h:13
Definition llist.h:46
struct llist_node * first
Definition llist.h:47
Definition llist.h:42
struct llist_node * next
Definition llist.h:43