xref: /freebsd/share/man/man9/atomic.9 (revision 17d6c636720d00f77e5d098daf4c278f89d84f7b)
1.\" Copyright (c) 2000-2001 John H. Baldwin <jhb@FreeBSD.org>
2.\" All rights reserved.
3.\"
4.\" Redistribution and use in source and binary forms, with or without
5.\" modification, are permitted provided that the following conditions
6.\" are met:
7.\" 1. Redistributions of source code must retain the above copyright
8.\"    notice, this list of conditions and the following disclaimer.
9.\" 2. Redistributions in binary form must reproduce the above copyright
10.\"    notice, this list of conditions and the following disclaimer in the
11.\"    documentation and/or other materials provided with the distribution.
12.\"
13.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
14.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
17.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23.\"
24.\" $FreeBSD$
25.\"
26.Dd October 27, 2000
27.Os
28.Dt ATOMIC 9
29.Sh NAME
30.Nm atomic_add ,
31.Nm atomic_clear ,
32.Nm atomic_cmpset ,
33.Nm atomic_load ,
34.Nm atomic_readandclear ,
35.Nm atomic_set ,
36.Nm atomic_subtract ,
37.Nm atomic_store
38.Nd atomic operations
39.Sh SYNOPSIS
40.In sys/types.h
41.In machine/atomic.h
42.\" XXX
43.ds LB \f[R]\(lB\f[P]
44.ds RB \f[R]\(rB\f[P]
45.ds La \f[R]\(la\f[P]
46.ds Ra \f[R]\(ra\f[P]
47.Ft void
48.Fn atomic_add_\*[LB]acq_\*[Ba]rel_\*[RB]\*[La]type\*[Ra] "volatile \*[La]type\*[Ra] *p" "\*[La]type\*[Ra] v"
49.Ft void
50.Fn atomic_clear_\*[LB]acq_\*[Ba]rel_\*[RB]\*[La]type\*[Ra] "volatile \*[La]type\*[Ra] *p" "\*[La]type\*[Ra] v"
51.Ft int
52.Fo atomic_cmpset_\*[LB]acq_\*[Ba]rel_\*[RB]\*[La]type\*[Ra]
53.Fa "volatile \*[La]type\*[Ra] *dst"
54.Fa "\*[La]type\*[Ra] old"
55.Fa "\*[La]type\*[Ra] new"
56.Fc
57.Ft \*[La]type\*[Ra]
58.Fn atomic_load_acq_\*[La]type\*[Ra] "volatile \*[La]type\*[Ra] *p"
59.Ft \*[La]type\*[Ra]
60.Fn atomic_readandclear_\*[La]type\*[Ra] "volatile \*[La]type\*[Ra] *p"
61.Ft void
62.Fn atomic_set_\*[LB]acq_\*[Ba]rel_\*[RB]\*[La]type\*[Ra] "volatile \*[La]type\*[Ra] *p" "\*[La]type\*[Ra] v"
63.Ft void
64.Fn atomic_subtract_\*[LB]acq_\*[Ba]rel_\*[RB]\*[La]type\*[Ra] "volatile \*[La]type\*[Ra] *p" "\*[La]type\*[Ra] v"
65.Ft void
66.Fn atomic_store_rel_\*[La]type\*[Ra] "volatile \*[La]type\*[Ra] *p" "\*[La]type\*[Ra] v"
67.rm LB RB La Ra
68.Sh DESCRIPTION
69Each of the atomic operations is guaranteed to be atomic in the presence of
70interrupts.
71They can be used to implement reference counts or as building blocks for more
72advanced synchronization primitives such as mutexes.
73.Ss Types
74Each atomic operation operates on a specific
75.Ar type .
76The type to use is indicated in the function name.
77The available types that can be used are:
78.Pp
79.Bl -tag -offset indent -width short -compact
80.It Li int
81unsigned integer
82.It Li long
83unsigned long integer
84.It Li ptr
85unsigned integer the size of a pointer
86.It Li 32
87unsigned 32-bit integer
88.It Li 64
89unsigned 64-bit integer
90.El
91.Pp
92For example, the function to atomically add two integers is called
93.Fn atomic_add_int .
94.Pp
95Certain architectures also provide operations for types smaller than
96.Dq Li int .
97.Pp
98.Bl -tag -offset indent -width short -compact
99.It Li char
100unsigned character
101.It Li short
102unsigned short integer
103.It Li 8
104unsigned 8-bit integer
105.It Li 16
106unsigned 16-bit integer
107.El
108.Pp
109These must not be used in MI code because the instructions to implement them
110efficiently may not be available.
111.Ss Memory Barriers
112Memory barriers are used to guarantee the order of data accesses in
113two ways.
114First, they specify hints to the compiler to not re-order or optimize the
115operations.
116Second, on architectures that do not guarantee ordered data accesses,
117special instructions or special variants of instructions are used to indicate
118to the processor that data accesses need to occur in a certain order.
119As a result, most of the atomic operations have three variants in order to
120include optional memory barriers.
121The first form just performs the operation without any explicit barriers.
122The second form uses a read memory barrier, and the third variant uses a write
123memory barrier.
124.Pp
125The second variant of each operation includes a read memory barrier.
126This barrier ensures that the effects of this operation are completed before the
127effects of any later data accesses.
128As a result, the operation is said to have acquire semantics as it acquires a
129pseudo-lock requiring further operations to wait until it has completed.
130To denote this, the suffix
131.Dq Li _acq
132is inserted into the function name immediately prior to the
133.Dq Li _ Ns Aq Ar type
134suffix.
135For example, to subtract two integers ensuring that any later writes will
136happen after the subtraction is performed, use
137.Fn atomic_subtract_acq_int .
138.Pp
139The third variant of each operation includes a write memory barrier.
140This ensures that all effects of all previous data accesses are completed
141before this operation takes place.
142As a result, the operation is said to have release semantics as it releases
143any pending data accesses to be completed before its operation is performed.
144To denote this, the suffix
145.Dq Li _rel
146is inserted into the function name immediately prior to the
147.Dq Li _ Ns Aq Ar type
148suffix.
149For example, to add two long integers ensuring that all previous
150writes will happen first, use
151.Fn atomic_add_rel_long .
152.Pp
153A practical example of using memory barriers is to ensure that data accesses
154that are protected by a lock are all performed while the lock is held.
155To achieve this, one would use a read barrier when acquiring the lock to
156guarantee that the lock is held before any protected operations are performed.
157Finally, one would use a write barrier when releasing the lock to ensure that
158all of the protected operations are completed before the lock is released.
159.Ss Multiple Processors
160The current set of atomic operations do not necessarily guarantee atomicity
161across multiple processors.
162To guarantee atomicity across processors, not only does the individual
163operation need to be atomic on the processor performing the operation, but
164the result of the operation needs to be pushed out to stable storage and the
165caches of all other processors on the system need to invalidate any cache
166lines that include the affected memory region.
167On the
168.Tn i386
169architecture, the cache coherency model requires that the hardware perform
170this task, thus the atomic operations are atomic across multiple processors.
171On the
172.Tn ia64
173architecture, coherency is only guaranteed for pages that are configured to
174using a caching policy of either uncached or write back.
175.Ss Semantics
176This section describes the semantics of each operation using a C like notation.
177.Bl -hang
178.It Fn atomic_add p v
179.Bd -literal -compact
180*p += v;
181.Ed
182.It Fn atomic_clear p v
183.Bd -literal -compact
184*p &= ~v;
185.Ed
186.It Fn atomic_cmpset dst old new
187.Bd -literal -compact
188if (*dst == old) {
189	*dst = new;
190	return 1;
191} else
192	return 0;
193.Ed
194.El
195.Pp
196The
197.Fn atomic_cmpset
198functions are not implemented for the types
199.Dq Li char ,
200.Dq Li short ,
201.Dq Li 8 ,
202and
203.Dq Li 16 .
204.Bl -hang
205.It Fn atomic_load addr
206.Bd -literal -compact
207return (*addr)
208.Ed
209.El
210.Pp
211The
212.Fn atomic_load
213functions always have acquire semantics.
214.Bl -hang
215.It Fn atomic_readandclear addr
216.Bd -literal -compact
217temp = *addr;
218*addr = 0;
219return (temp);
220.Ed
221.El
222.Pp
223The
224.Fn atomic_readandclear
225functions are not implemented for the types
226.Dq Li char ,
227.Dq Li short ,
228.Dq Li ptr ,
229.Dq Li 8 ,
230and
231.Dq Li 16
232and do
233not have any variants with memory barriers at this time.
234.Bl -hang
235.It Fn atomic_set p v
236.Bd -literal -compact
237*p |= v;
238.Ed
239.It Fn atomic_subtract p v
240.Bd -literal -compact
241*p -= v;
242.Ed
243.It Fn atomic_store p v
244.Bd -literal -compact
245*p = v;
246.Ed
247.El
248.Pp
249The
250.Fn atomic_store
251functions always have release semantics.
252.Pp
253The type
254.Dq Li 64
255is currently not implemented for any of the atomic operations on the
256.Tn i386
257architecture.
258.Sh RETURN VALUES
259The
260.Fn atomic_cmpset
261function
262returns the result of the compare operation.
263The
264.Fn atomic_load
265and
266.Fn atomic_readandclear
267functions
268return the value at the specified address.
269.Sh EXAMPLES
270This example uses the
271.Fn atomic_cmpset_acq_ptr
272and
273.Fn atomic_set_ptr
274functions to obtain a sleep mutex and handle recursion.
275Since the
276.Va mtx_lock
277member of a
278.Vt "struct mtx"
279is a pointer, the
280.Dq Li ptr
281type is used.
282.Bd -literal
283#define _obtain_lock(mp, tid)						\\
284	atomic_cmpset_acq_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED, (tid))
285
286/* Get a sleep lock, deal with recursion inline. */
287#define	_getlock_sleep(mp, tid, type) do {				\\
288	if (!_obtain_lock(mp, tid)) {					\\
289		if (((mp)->mtx_lock & MTX_FLAGMASK) != ((uintptr_t)(tid)))\\
290			mtx_enter_hard(mp, (type) & MTX_HARDOPTS, 0);	\\
291		else {							\\
292			atomic_set_ptr(&(mp)->mtx_lock, MTX_RECURSE);	\\
293			(mp)->mtx_recurse++;				\\
294		}							\\
295	}								\\
296} while (0)
297.Ed
298.Sh HISTORY
299The
300.Fn atomic_add ,
301.Fn atomic_clear ,
302.Fn atomic_set ,
303and
304.Fn atomic_subtract
305operations were first introduced in
306.Fx 3.0 .
307This first set only supported the types
308.Dq Li char ,
309.Dq Li short ,
310.Dq Li int ,
311and
312.Dq Li long .
313The
314.Fn atomic_cmpset ,
315.Fn atomic_load ,
316.Fn atomic_readandclear ,
317and
318.Fn atomic_store
319operations were added in
320.Fx 5.0 .
321The types
322.Dq Li 8 ,
323.Dq Li 16 ,
324.Dq Li 32 ,
325.Dq Li 64 ,
326and
327.Dq Li ptr ,
328and all of the acquire and release variants
329were added in
330.Fx 5.0
331as well.
332