xref: /freebsd/share/man/man9/atomic.9 (revision 9207b4cff7b8d483f4dd3c62266c2b58819eb7f9)
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.Ft void
43.Fn atomic_add_{acq_,rel_,}<type> "volatile <type> *p" "<type> v"
44.Ft void
45.Fn atomic_clear_{acq_,rel_,}<type> "volatile <type> *p" "<type> v"
46.Ft int
47.Fo atomic_cmpset_{acq_,rel_,}<type>
48.Fa "volatile <type> *dst"
49.Fa "<type> old"
50.Fa "<type> new"
51.Fc
52.Ft <type>
53.Fn atomic_load_acq_<type> "volatile <type> *p"
54.Ft <type>
55.Fn atomic_readandclear_<type> "volatile <type> *p"
56.Ft void
57.Fn atomic_set_{acq_,rel_,}<type> "volatile <type> *p" "<type> v"
58.Ft void
59.Fn atomic_subtract_{acq_,rel_,}<type> "volatile <type> *p" "<type> v"
60.Ft void
61.Fn atomic_store_rel_<type> "volatile <type> *p" "<type> v"
62.Sh DESCRIPTION
63Each of the atomic operations is guaranteed to be atomic in the presence of
64interrupts.
65They can be used to implement reference counts or as building blocks for more
66advanced synchronization primitives such as mutexes.
67.Ss Types
68Each atomic operation operates on a specific type.
69The type to use is indicated in the function name.
70The available types that can be used are:
71.Bl -tag -offset indent -width short
72.It int
73unsigned integer
74.It long
75unsigned long integer
76.It ptr
77unsigned integer the size of a pointer
78.It 32
79unsigned 32-bit integer
80.It 64
81unsigned 64-bit integer
82.El
83.Pp
84For example, the function to atomically add two integers is called
85.Fn atomic_add_int .
86.Pp
87Certain architectures also provide operations for types smaller than int.
88.Bl -tag -offset indent -width short
89.It char
90unsigned character
91.It short
92unsigned short integer
93.It 8
94unsigned 8-bit integer
95.It 16
96unsigned 16-bit integer
97.El
98.Pp
99These must not be used in MI code because the instructions to implement them
100efficiently may not be available.
101.Ss Memory Barriers
102Memory barriers are used to guarantee the order the order of data accesses in
103two ways.
104First, they specify hints to the compiler to not re-order or optimize the
105operations.
106Secondly, on architectures that do not guarantee ordered data accesses,
107special instructions or special variants of instructions are used to indicate
108to the processor that data accesses need to occur in a certain order.
109As a result, most of the atomic operations have three variants in order to
110include optional memory barriers.
111The first form just performs the operation without any explicit barriers.
112The second form uses a read memory barrier, and the final variant uses a write
113memory barrier.
114.Pp
115The second variant of each operation includes a read memory barrier.
116This barrier ensures that the effects of this operation are completed before the
117effects of any later data accesses.
118As a result, the operation is said to have acquire semantics as it acquires a
119pseudo-lock requiring further operations to wait until it has completed.
120To denote this, the suffix
121.Dq _acq
122is inserted into the function name immediately prior to the
123.Em _type
124suffix.
125For example, to subtract two integers ensuring that any later writes will
126happen after the subtraction is performed, use
127.Fn atomic_subtract_acq_int .
128.Pp
129The third variant of each operation includes a write memory barrier.
130This ensures that all effects of all previous data accesses are completed
131before this operation takes place.
132As a result, the operation is said to have release semantics as it releases
133any pending data accesses to be completed before its operation is performed.
134To denote this, the suffix
135.Dq _rel
136is inserted into the function name immediately prior to the
137.Em _type
138suffix.
139For example, to add two long integers ensuring that all previous
140writes will happen first, use
141.Fn atomic_add_rel_long .
142.Pp
143A practical example of using memory barriers is to ensure that data accesses
144that are protected by a lock are all performed while the lock is held.
145To achieve this, one would use a read barrier when acquiring the lock to
146guarantee that the lock is held before any protected operations are performed.
147Finally, one would use a write barrier when releasing the lock to ensure that
148all of the protected operations are completed before the lock is released.
149.Pp
150.Ss Multiple Processors
151The current set of atomic operations do not necessarily guarantee atomicity
152across multiple processors.
153To guarantee atomicity across processors, not only does the individual
154operation need to be atomic on the processor performing the operation, but
155the result of the operation needs to be pushed out to stable storage and the
156caches of all other processors on the system need to invalidate any cache
157lines that include the affected memory region.
158On the
159.Tn i386
160architecture, the cache coherency model requires that the hardware perform
161this task, thus the atomic operations are atomic across multiple processors.
162On the
163.Tn ia64
164architecture, coherency is only guaranteed for pages that are configured to
165using a caching policy of either uncached or write back.
166.Ss Semantics
167This section describes the semantics of each operation using a C like notation.
168.Bl -hang
169.It Fn atomic_add "p" "v"
170.Bd -literal
171*p += v;
172.Ed
173.It Fn atomic_clear "p" "v"
174.Bd -literal
175*p &= ~v;
176.Ed
177.It Fn atomic_cmpset "dst" "old" "new"
178.Bd -literal
179if (*dst == old) {
180	*dst = new;
181	return 1;
182} else
183	return 0;
184.Ed
185.El
186.Pp
187The
188.Fn atomic_cmpset
189functions are not implemented for the types char, short, 8, and 16.
190.Bl -hang
191.It Fn atomic_load "addr"
192.Bd -literal
193return (*addr)
194.Ed
195.El
196.Pp
197The
198.Fn atomic_load
199functions always have acquire semantics.
200.Bl -hang
201.It Fn atomic_readandclear "addr"
202.Bd -literal
203temp = *addr;
204*addr = 0;
205return (temp);
206.Ed
207.El
208.Pp
209The
210.Fn atomic_readandclear
211functions are not implemented for the types char, short, ptr, 8, and 16 and do
212not have any variants with memory barriers at this time.
213.Bl -hang
214.It Fn atomic_set "p" "v"
215.Bd -literal
216*p |= v;
217.Ed
218.It Fn atomic_subtract "p" "v"
219.Bd -literal
220*p -= v;
221.Ed
222.It Fn atomic_store "p" "v"
223.Bd -literal
224*p = v;
225.Ed
226.El
227.Pp
228The
229.Fn atomic_store
230functions always have release semantics.
231.Pp
232The type
233.Dq 64
234is currently not implemented for any of the atomic operations on the
235.Tn i386
236architecture.
237.Sh RETURN VALUES
238.Fn atomic_cmpset
239returns the result of the compare operation.
240.Fn atomic_load
241and
242.Fn atomic_readandclear
243return the value at the specified address.
244.Sh EXAMPLES
245This example uses the
246.Fn atomic_cmpset_acq_ptr
247and
248.Fn atomic_set_ptr
249functions to obtain a sleep mutex and handle recursion.
250Since the
251.Va mtx_lock
252member of a
253.Li struct mtx
254is a pointer, the
255.Dq ptr
256type is used.
257.Bd -literal
258#define _obtain_lock(mp, tid)						\\
259	atomic_cmpset_acq_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED, (tid))
260
261/* Get a sleep lock, deal with recursion inline. */
262#define	_getlock_sleep(mp, tid, type) do {				\\
263	if (!_obtain_lock(mp, tid)) {					\\
264		if (((mp)->mtx_lock & MTX_FLAGMASK) != ((uintptr_t)(tid)))\\
265			mtx_enter_hard(mp, (type) & MTX_HARDOPTS, 0);	\\
266		else {							\\
267			atomic_set_ptr(&(mp)->mtx_lock, MTX_RECURSE);	\\
268			(mp)->mtx_recurse++;				\\
269		}							\\
270	}								\\
271} while (0)
272.Ed
273.Sh HISTORY
274The
275.Fn atomic_add ,
276.Fn atomic_clear ,
277.Fn atomic_set ,
278and
279.Fn atomic_subtract
280operations were first introduced in
281.Fx 3.0 .
282This first set only suppored the types char, short, int, and long.
283The
284.Fn atomic_cmpset ,
285.Fn atomic_load ,
286.Fn atomic_readandclear ,
287and
288.Fn atomic_store
289operations were added in
290.Fx 5.0 .
291The types 8, 16, 32, 64, and ptr and all of the acquire and release variants
292were added in
293.Fx 5.0
294as well.
295