1/* $OpenBSD: atomic.h,v 1.10 2025/01/03 21:27:41 bluhm Exp $ */
2/*
3 * Copyright (c) 2014 David Gwynne <dlg@openbsd.org>
4 * Copyright (c) 2022 Alexander Bluhm <bluhm@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#ifndef _SYS_ATOMIC_H_
20#define _SYS_ATOMIC_H_
21
22#include <machine/atomic.h>
23
24/*
25 * an arch wanting to provide its own implementations does so by defining
26 * macros.
27 */
28
29/*
30 * atomic_cas_*
31 */
32
33#ifndef atomic_cas_uint
34static inline unsigned int
35atomic_cas_uint(volatile unsigned int *p, unsigned int o, unsigned int n)
36{
37 return __sync_val_compare_and_swap(p, o, n);
38}
39#endif
40
41#ifndef atomic_cas_ulong
42static inline unsigned long
43atomic_cas_ulong(volatile unsigned long *p, unsigned long o, unsigned long n)
44{
45 return __sync_val_compare_and_swap(p, o, n);
46}
47#endif
48
49#ifndef atomic_cas_ptr
50static inline void *
51atomic_cas_ptr(volatile void *pp, void *o, void *n)
52{
53 void * volatile *p = (void * volatile *)pp;
54 return __sync_val_compare_and_swap(p, o, n);
55}
56#endif
57
58/*
59 * atomic_swap_*
60 */
61
62#ifndef atomic_swap_uint
63static inline unsigned int
64atomic_swap_uint(volatile unsigned int *p, unsigned int v)
65{
66 return __sync_lock_test_and_set(p, v);
67}
68#endif
69
70#ifndef atomic_swap_ulong
71static inline unsigned long
72atomic_swap_ulong(volatile unsigned long *p, unsigned long v)
73{
74 return __sync_lock_test_and_set(p, v);
75}
76#endif
77
78#ifndef atomic_swap_ptr
79static inline void *
80atomic_swap_ptr(volatile void *pp, void *v)
81{
82 void * volatile *p = (void * volatile *)pp;
83 return __sync_lock_test_and_set(p, v);
84}
85#endif
86
87/*
88 * atomic_add_*_nv - add and fetch
89 */
90
91#ifndef atomic_add_int_nv
92static inline unsigned int
93atomic_add_int_nv(volatile unsigned int *p, unsigned int v)
94{
95 return __sync_add_and_fetch(p, v);
96}
97#endif
98
99#ifndef atomic_add_long_nv
100static inline unsigned long
101atomic_add_long_nv(volatile unsigned long *p, unsigned long v)
102{
103 return __sync_add_and_fetch(p, v);
104}
105#endif
106
107/*
108 * atomic_add - add
109 */
110
111#ifndef atomic_add_int
112#define atomic_add_int(_p, _v) ((void)atomic_add_int_nv((_p), (_v)))
113#endif
114
115#ifndef atomic_add_long
116#define atomic_add_long(_p, _v) ((void)atomic_add_long_nv((_p), (_v)))
117#endif
118
119/*
120 * atomic_inc_*_nv - increment and fetch
121 */
122
123#ifndef atomic_inc_int_nv
124#define atomic_inc_int_nv(_p) atomic_add_int_nv((_p), 1)
125#endif
126
127#ifndef atomic_inc_long_nv
128#define atomic_inc_long_nv(_p) atomic_add_long_nv((_p), 1)
129#endif
130
131/*
132 * atomic_inc_* - increment
133 */
134
135#ifndef atomic_inc_int
136#define atomic_inc_int(_p) ((void)atomic_inc_int_nv(_p))
137#endif
138
139#ifndef atomic_inc_long
140#define atomic_inc_long(_p) ((void)atomic_inc_long_nv(_p))
141#endif
142
143/*
144 * atomic_sub_*_nv - sub and fetch
145 */
146
147#ifndef atomic_sub_int_nv
148static inline unsigned int
149atomic_sub_int_nv(volatile unsigned int *p, unsigned int v)
150{
151 return __sync_sub_and_fetch(p, v);
152}
153#endif
154
155#ifndef atomic_sub_long_nv
156static inline unsigned long
157atomic_sub_long_nv(volatile unsigned long *p, unsigned long v)
158{
159 return __sync_sub_and_fetch(p, v);
160}
161#endif
162
163/*
164 * atomic_sub_* - sub
165 */
166
167#ifndef atomic_sub_int
168#define atomic_sub_int(_p, _v) ((void)atomic_sub_int_nv((_p), (_v)))
169#endif
170
171#ifndef atomic_sub_long
172#define atomic_sub_long(_p, _v) ((void)atomic_sub_long_nv((_p), (_v)))
173#endif
174
175/*
176 * atomic_dec_*_nv - decrement and fetch
177 */
178
179#ifndef atomic_dec_int_nv
180#define atomic_dec_int_nv(_p) atomic_sub_int_nv((_p), 1)
181#endif
182
183#ifndef atomic_dec_long_nv
184#define atomic_dec_long_nv(_p) atomic_sub_long_nv((_p), 1)
185#endif
186
187/*
188 * atomic_dec_* - decrement
189 */
190
191#ifndef atomic_dec_int
192#define atomic_dec_int(_p) ((void)atomic_dec_int_nv(_p))
193#endif
194
195#ifndef atomic_dec_long
196#define atomic_dec_long(_p) ((void)atomic_dec_long_nv(_p))
197#endif
198
199#ifdef _KERNEL
200/*
201 * atomic_load_* - read from memory
202 */
203
204static inline unsigned int
205atomic_load_int(volatile const unsigned int *p)
206{
207 return *p;
208}
209
210static inline unsigned long
211atomic_load_long(volatile const unsigned long *p)
212{
213 return *p;
214}
215
216/*
217 * atomic_store_* - write to memory
218 */
219
220static inline void
221atomic_store_int(volatile unsigned int *p, unsigned int v)
222{
223 *p = v;
224}
225
226static inline void
227atomic_store_long(volatile unsigned long *p, unsigned long v)
228{
229 *p = v;
230}
231#endif /* _KERNEL */
232
233/*
234 * memory barriers
235 */
236
237#ifndef membar_enter
238#define membar_enter() __sync_synchronize()
239#endif
240
241#ifndef membar_exit
242#define membar_exit() __sync_synchronize()
243#endif
244
245#ifndef membar_producer
246#define membar_producer() __sync_synchronize()
247#endif
248
249#ifndef membar_consumer
250#define membar_consumer() __sync_synchronize()
251#endif
252
253#ifndef membar_sync
254#define membar_sync() __sync_synchronize()
255#endif
256
257#ifndef membar_enter_after_atomic
258#define membar_enter_after_atomic() membar_enter()
259#endif
260
261#ifndef membar_exit_before_atomic
262#define membar_exit_before_atomic() membar_exit()
263#endif
264
265#ifdef _KERNEL
266
267/*
268 * Force any preceding reads to happen before any subsequent reads that
269 * depend on the value returned by the preceding reads.
270 */
271static inline void
272membar_datadep_consumer(void)
273{
274#ifdef __alpha__
275 membar_consumer();
276#endif
277}
278
279#define READ_ONCE(x) ({ \
280 typeof(x) __tmp = *(volatile typeof(x) *)&(x); \
281 membar_datadep_consumer(); \
282 __tmp; \
283})
284
285#define WRITE_ONCE(x, val) ({ \
286 typeof(x) __tmp = (val); \
287 *(volatile typeof(x) *)&(x) = __tmp; \
288 __tmp; \
289})
290
291#endif /* _KERNEL */
292
293#endif /* _SYS_ATOMIC_H_ */