XenevaOS
Loading...
Searching...
No Matches
atomic.h
Go to the documentation of this file.
1#ifndef __LINUX_ATOMIC_H__
2#define __LINUX_ATOMIC_H__
3
4/*
5 * DCL <linux/atomic.h> -- refcounted counters for the tty layer.
6 *
7 * DCL had no atomic API at all: nothing in Xeneva needed one, because its own
8 * code serialises at the process level. The tty core does need it, and for a
9 * reason that is worth stating -- tty_buffer.c uses `atomic_t` as a *turn
10 * counter*, not as a lock: `buf->priority` is incremented by
11 * tty_buffer_lock_exclusive() so flush_to_ldisc() can see that the line
12 * discipline has taken the buffer over and back off mid-loop (tty_buffer.c:482).
13 * That read has to be exact or a byte gets delivered twice or dropped.
14 *
15 * The operations below are real, on clang's __atomic builtins, so aarch64
16 * emits LDXR/STXR rather than a plain load/store. That is not belt-and-braces:
17 * tty_flip_buffer_push() runs from the UART interrupt handler while
18 * flush_to_ldisc() runs from whoever called queue_work() (see
19 * <linux/workqueue.h> -- DCL runs work inline), so these two genuinely do
20 * race on one core. Making them plain stores would have been the classic
21 * "works until it doesn't" bug.
22 *
23 * Signatures follow mainline: atomic_read() takes a const pointer, atomic_add()
24 * takes the value first, *_return() hands back the post-operation value, and
25 * atomic_add_unless() is the "add unless it already equals" form
26 * serial_core.c uses for its port refcount.
27 */
28
29#include <stdbool.h>
30
31typedef struct {
33} atomic_t;
34
35#define ATOMIC_INIT(i) { (i) }
36
37/*
38 * atomic64_t -- 64-bit counter. kobject.h declares `extern atomic64_t
39 * uevent_seqnum;`, so the *type* has to exist even though nothing here
40 * increments it; laid out as long long to be 8 bytes under LLP64 (aarch64
41 * windows: long is 4). Same turn-taking rationale as atomic_t above: single
42 * owner, no lock needed, so the accessors go straight to the compiler's
43 * atomic builtins rather than to a lock.
44 */
45typedef struct {
46 long long counter;
48
49#define ATOMIC64_INIT(i) { (i) }
50
51static inline long long atomic64_read(const atomic64_t* v)
52{
53 return __atomic_load_n(&v->counter, __ATOMIC_SEQ_CST);
54}
55
56static inline void atomic64_set(atomic64_t* v, long long i)
57{
58 __atomic_store_n(&v->counter, i, __ATOMIC_SEQ_CST);
59}
60
61static inline void atomic64_inc(atomic64_t* v)
62{
63 __atomic_add_fetch(&v->counter, 1LL, __ATOMIC_SEQ_CST);
64}
65
66/* drm_vblank.c:203 -- vblank_count_inc is 1 + a jump for a missed tick. */
67static inline void atomic64_add(long long i, atomic64_t* v)
68{
69 (void)__atomic_fetch_add(&v->counter, i, __ATOMIC_SEQ_CST);
70}
71
72/*
73 * atomic64_fetch_add(i, v) -- the value *before* the add, which is what makes
74 * it a fetch: dma-fence.c:180's dma_fence_context_alloc() returns it as the
75 * new context's id, so two contexts can never share one even though the
76 * counter is shared. atomic64_add_return would hand back post-add and give
77 * the first caller id 1 where mainline gives 0.
78 */
79static inline long long atomic64_fetch_add(long long i, atomic64_t* v)
80{
81 return __atomic_fetch_add(&v->counter, i, __ATOMIC_SEQ_CST);
82}
83
84/* drm_file.c:144 -- file->client_id, assigned from the post-increment value. */
85static inline long long atomic64_inc_return(atomic64_t* v)
86{
87 return __atomic_add_fetch(&v->counter, 1LL, __ATOMIC_SEQ_CST);
88}
89
90static inline int atomic_read(const atomic_t* v)
91{
92 return __atomic_load_n(&v->counter, __ATOMIC_SEQ_CST);
93}
94
95static inline void atomic_set(atomic_t* v, int i)
96{
97 __atomic_store_n(&v->counter, i, __ATOMIC_SEQ_CST);
98}
99
100static inline int atomic_add_return(int i, atomic_t* v)
101{
102 return __atomic_add_fetch(&v->counter, i, __ATOMIC_SEQ_CST);
103}
104
105static inline int atomic_sub_return(int i, atomic_t* v)
106{
107 return __atomic_sub_fetch(&v->counter, i, __ATOMIC_SEQ_CST);
108}
109
110static inline void atomic_add(int i, atomic_t* v)
111{
112 (void)__atomic_fetch_add(&v->counter, i, __ATOMIC_SEQ_CST);
113}
114
115static inline void atomic_sub(int i, atomic_t* v)
116{
117 (void)__atomic_fetch_sub(&v->counter, i, __ATOMIC_SEQ_CST);
118}
119
120static inline void atomic_inc(atomic_t* v)
121{
122 atomic_add(1, v);
123}
124
125static inline void atomic_dec(atomic_t* v)
126{
127 atomic_sub(1, v);
128}
129
130static inline int atomic_inc_return(atomic_t* v)
131{
132 return atomic_add_return(1, v);
133}
134
135static inline int atomic_dec_return(atomic_t* v)
136{
137 return atomic_sub_return(1, v);
138}
139
140/* "was it the last reference?" -- tty_port_put()'s free path. */
141static inline bool atomic_dec_and_test(atomic_t* v)
142{
143 return atomic_dec_return(v) == 0;
144}
145
146/* drm_file.c:383 -- drm_open()'s dev->open_count, return ignored. */
147static inline int atomic_fetch_inc(atomic_t* v)
148{
149 return __atomic_fetch_add(&v->counter, 1, __ATOMIC_SEQ_CST);
150}
151
152/*
153 * atomic_read_acquire(v) -- a load the reader may not reorder with what
154 * follows. dma-fence-array.c:122 reads num_pending this way to pair with the
155 * atomic_dec_and_test() that publishes the last pending fence, and the
156 * comment at :113 says so; both sides are seq_cst here, which is strictly
157 * stronger, so the pairing holds.
158 */
159static inline int atomic_read_acquire(const atomic_t* v)
160{
161 return __atomic_load_n(&v->counter, __ATOMIC_ACQUIRE);
162}
163
164static inline int atomic_xchg(atomic_t* v, int i)
165{
166 return __atomic_exchange_n(&v->counter, i, __ATOMIC_SEQ_CST);
167}
168
169static inline int atomic_cmpxchg(atomic_t* v, int old, int new_v)
170{
171 int expected = old;
172 (void)__atomic_compare_exchange_n(&v->counter, &expected, new_v, 0,
173 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
174 return expected;
175}
176
177/* Returns the value *before* the conditional add (mainline's contract). */
178static inline int atomic_add_unless(atomic_t* v, int i, int u)
179{
180 int c = atomic_read(v);
181
182 do {
183 if (c == u)
184 break;
185 } while (!__atomic_compare_exchange_n(&v->counter, &c, c + i, 0,
186 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
187
188 return c;
189}
190
191static inline void atomic_or(int i, atomic_t* v)
192{
193 (void)__atomic_fetch_or(&v->counter, i, __ATOMIC_SEQ_CST);
194}
195
196static inline void atomic_and(int i, atomic_t* v)
197{
198 (void)__atomic_fetch_and(&v->counter, i, __ATOMIC_SEQ_CST);
199}
200
201/*
202 * atomic_long_t -- the width-augmented form. Only one structure in the tty
203 * headers uses it: struct ld_semaphore's `count` (tty_ldisc.h), which mainline
204 * keeps as a long because the reader/writer counts are packed into one word
205 * with bits to spare.
206 *
207 * The operations listed are the ones ldsem's implementation needs; adding the
208 * rest of mainline's atomic_long_* family would be a second API nobody has
209 * called yet.
210 */
211typedef struct {
214
215#define ATOMIC_LONG_INIT(i) { (i) }
216
217static inline long atomic_long_read(const atomic_long_t* v)
218{
219 return __atomic_load_n(&v->counter, __ATOMIC_SEQ_CST);
220}
221
222static inline void atomic_long_set(atomic_long_t* v, long i)
223{
224 __atomic_store_n(&v->counter, i, __ATOMIC_SEQ_CST);
225}
226
227static inline void atomic_long_add(long i, atomic_long_t* v)
228{
229 (void)__atomic_fetch_add(&v->counter, i, __ATOMIC_SEQ_CST);
230}
231
232static inline long atomic_long_add_return(long i, atomic_long_t* v)
233{
234 return __atomic_add_fetch(&v->counter, i, __ATOMIC_SEQ_CST);
235}
236
237static inline void atomic_long_inc(atomic_long_t* v)
238{
239 atomic_long_add(1, v);
240}
241
242static inline void atomic_long_dec(atomic_long_t* v)
243{
244 atomic_long_add(-1, v);
245}
246
247static inline int atomic_long_dec_and_test(atomic_long_t* v)
248{
249 return atomic_long_add_return(-1, v) == 0;
250}
251
252/*
253 * atomic_long_inc_return_relaxed -- mainline's relaxed fetch-add; the one
254 * call site in this tree is ww_acquire_init()'s lockdep stamp
255 * (linux/ww_mutex.h:203). DCL has no weak memory to be relaxed about, so
256 * the sequential form is the same operation.
257 */
258static inline long atomic_long_inc_return_relaxed(atomic_long_t* v)
259{
260 return atomic_long_add_return(1, v);
261}
262
263static inline long atomic_long_cmpxchg(atomic_long_t* v, long old, long new_v)
264{
265 long expected = old;
266 (void)__atomic_compare_exchange_n(&v->counter, &expected, new_v, 0,
267 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
268 return expected;
269}
270
271/*
272 * atomic_long_try_cmpxchg(v, old, new) -- the conditional form, and the one
273 * tty_ldsem.c actually uses (five sites: :90, :114, :170, :245, :351), every
274 * one of them `if (atomic_long_try_cmpxchg(&sem->count, &count, ...))`
275 * inside a retry loop.
276 *
277 * Difference from the function above, and the reason both exist: the expected
278 * value goes in by pointer and is *rewritten* with what the word actually
279 * held when the exchange fails. The loops depend on that -- they compute the
280 * next value from `count` on each pass, so a stale count would re-apply the
281 * same adjustment forever. Returning the old value instead (as
282 * atomic_long_cmpxchg does) would leave `count` untouched and turn every
283 * retry into a repeat.
284 *
285 * __atomic_compare_exchange_n's second argument is exactly this contract, so
286 * the body is one call with `weak = 0`: the loops have their own retry
287 * condition and do not need a spurious failure, and seq_cst on both halves
288 * matches the rest of this header.
289 */
290static inline bool atomic_long_try_cmpxchg(atomic_long_t* v, long* old,
291 long new_v)
292{
293 return __atomic_compare_exchange_n(&v->counter, old, new_v, 0,
294 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
295}
296
297/*
298 * cmpxchg(ptr, old, new) -- mainline's generic typed compare-and-swap, the
299 * name <linux/atomic.h> re-exports from the arch. DCL has no arch header
300 * for it, and the dma-buf port brought the two callers that need it:
301 *
302 * dma-fence-array.c:36, :42 cmpxchg(&array->base.error, PENDING_ERROR, error)
303 * dma-fence-chain.c:65 cmpxchg(&chain->prev, RCU_INITIALIZER(prev),
304 * RCU_INITIALIZER(replacement))
305 *
306 * Those are an `int *` and a `struct dma_fence __rcu **`, which is why this
307 * cannot be an int-shaped helper: the fence-chain result is wrapped in
308 * unrcu_pointer(), whose expansion is `typeof(*(p)) *`, and an untyped
309 * return makes that dereference an int -- which is what the first build of
310 * those two files reported ("indirection requires pointer operand ('int'
311 * invalid)"). typeof(*(ptr)) gives the macro a type it can hand back
312 * without a cast at either call site.
313 *
314 * The body is clang's builtin because its contract is mainline's exactly:
315 * the second argument is where the *actual* old value is stored back, and
316 * the call's own result says whether the swap happened -- not what the value
317 * was. So the expression's value is the local, read after the exchange, and
318 * it is the old value whether or not it matched. Objects of 4 and 8 bytes
319 * are both supported, which covers the int and the pointer in reach.
320 */
321#define cmpxchg(ptr, old, new) \
322({ \
323 typeof(*(ptr)) __old = (old); \
324 typeof(*(ptr)) __new = (new); \
325 (void)__atomic_compare_exchange_n((ptr), &__old, __new, 0, \
326 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); \
327 __old; \
328})
329
330#endif /* __LINUX_ATOMIC_H__ */
Definition atomic.h:45
long long counter
Definition atomic.h:46
Definition atomic.h:211
long counter
Definition atomic.h:212
Definition atomic.h:31
int counter
Definition atomic.h:32