]> git.saurik.com Git - apple/xnu.git/blame - libkern/gen/OSAtomicOperations.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / libkern / gen / OSAtomicOperations.c
CommitLineData
1c79356b 1/*
3e170ce0 2 * Copyright (c) 2000-2015 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28
29#include <libkern/OSAtomic.h>
3e170ce0
A
30#include <kern/debug.h>
31#include <machine/atomic.h>
1c79356b
A
32
33enum {
0a7de745
A
34 false = 0,
35 true = 1
1c79356b 36};
2d21ac55
A
37
38#ifndef NULL
39#define NULL ((void *)0)
40#endif
1c79356b 41
3e170ce0
A
42#define ATOMIC_DEBUG DEBUG
43
44#if ATOMIC_DEBUG
0a7de745 45#define ALIGN_TEST(p, t) do{if((uintptr_t)p&(sizeof(t)-1)) panic("Unaligned atomic pointer %p\n",p);}while(0)
3e170ce0 46#else
0a7de745 47#define ALIGN_TEST(p, t) do{}while(0)
3e170ce0
A
48#endif
49
1c79356b
A
50/*
51 * atomic operations
3e170ce0
A
52 * These are _the_ atomic operations, now implemented via compiler built-ins.
53 * It is expected that this C implementation is a candidate for Link-Time-
54 * Optimization inlining, whereas the assembler implementations they replace
55 * were not.
1c79356b
A
56 */
57
3e170ce0 58#undef OSCompareAndSwap8
0a7de745
A
59Boolean
60OSCompareAndSwap8(UInt8 oldValue, UInt8 newValue, volatile UInt8 *address)
3e170ce0 61{
cb323159 62 return os_atomic_cmpxchg(address, oldValue, newValue, acq_rel);
3e170ce0
A
63}
64
65#undef OSCompareAndSwap16
0a7de745
A
66Boolean
67OSCompareAndSwap16(UInt16 oldValue, UInt16 newValue, volatile UInt16 *address)
3e170ce0 68{
cb323159 69 return os_atomic_cmpxchg(address, oldValue, newValue, acq_rel);
3e170ce0
A
70}
71
72#undef OSCompareAndSwap
0a7de745
A
73Boolean
74OSCompareAndSwap(UInt32 oldValue, UInt32 newValue, volatile UInt32 *address)
3e170ce0
A
75{
76 ALIGN_TEST(address, UInt32);
cb323159 77 return os_atomic_cmpxchg(address, oldValue, newValue, acq_rel);
3e170ce0
A
78}
79
80#undef OSCompareAndSwap64
0a7de745
A
81Boolean
82OSCompareAndSwap64(UInt64 oldValue, UInt64 newValue, volatile UInt64 *address)
3e170ce0
A
83{
84 /*
85 * _Atomic uint64 requires 8-byte alignment on all architectures.
86 * This silences the compiler cast warning. ALIGN_TEST() verifies
87 * that the cast was legal, if defined.
88 */
89 _Atomic UInt64 *aligned_addr = (_Atomic UInt64 *)(uintptr_t)address;
90
91 ALIGN_TEST(address, UInt64);
cb323159 92 return os_atomic_cmpxchg(aligned_addr, oldValue, newValue, acq_rel);
3e170ce0
A
93}
94
95#undef OSCompareAndSwapPtr
0a7de745
A
96Boolean
97OSCompareAndSwapPtr(void *oldValue, void *newValue, void * volatile *address)
3e170ce0 98{
cb323159 99 return os_atomic_cmpxchg(address, oldValue, newValue, acq_rel);
3e170ce0
A
100}
101
0a7de745
A
102SInt8
103OSAddAtomic8(SInt32 amount, volatile SInt8 *address)
3e170ce0 104{
cb323159 105 return os_atomic_add_orig(address, amount, relaxed);
3e170ce0
A
106}
107
0a7de745
A
108SInt16
109OSAddAtomic16(SInt32 amount, volatile SInt16 *address)
3e170ce0 110{
cb323159 111 return os_atomic_add_orig(address, amount, relaxed);
3e170ce0
A
112}
113
114#undef OSAddAtomic
0a7de745
A
115SInt32
116OSAddAtomic(SInt32 amount, volatile SInt32 *address)
3e170ce0
A
117{
118 ALIGN_TEST(address, UInt32);
cb323159 119 return os_atomic_add_orig(address, amount, relaxed);
3e170ce0
A
120}
121
122#undef OSAddAtomic64
0a7de745
A
123SInt64
124OSAddAtomic64(SInt64 amount, volatile SInt64 *address)
3e170ce0 125{
0a7de745 126 _Atomic SInt64* aligned_address = (_Atomic SInt64*)(uintptr_t)address;
3e170ce0
A
127
128 ALIGN_TEST(address, SInt64);
cb323159 129 return os_atomic_add_orig(aligned_address, amount, relaxed);
3e170ce0
A
130}
131
132#undef OSAddAtomicLong
133long
134OSAddAtomicLong(long theAmount, volatile long *address)
135{
cb323159 136 return os_atomic_add_orig(address, theAmount, relaxed);
3e170ce0 137}
b0d623f7 138
b0d623f7 139#undef OSIncrementAtomic
0a7de745
A
140SInt32
141OSIncrementAtomic(volatile SInt32 * value)
91447636 142{
cb323159 143 return os_atomic_inc_orig(value, relaxed);
91447636
A
144}
145
b0d623f7 146#undef OSDecrementAtomic
0a7de745
A
147SInt32
148OSDecrementAtomic(volatile SInt32 * value)
91447636 149{
cb323159 150 return os_atomic_dec_orig(value, relaxed);
91447636 151}
1c79356b 152
b0d623f7 153#undef OSBitAndAtomic
0a7de745
A
154UInt32
155OSBitAndAtomic(UInt32 mask, volatile UInt32 * value)
1c79356b 156{
cb323159 157 return os_atomic_and_orig(value, mask, relaxed);
1c79356b
A
158}
159
b0d623f7 160#undef OSBitOrAtomic
0a7de745
A
161UInt32
162OSBitOrAtomic(UInt32 mask, volatile UInt32 * value)
1c79356b 163{
cb323159 164 return os_atomic_or_orig(value, mask, relaxed);
1c79356b
A
165}
166
b0d623f7 167#undef OSBitXorAtomic
0a7de745
A
168UInt32
169OSBitXorAtomic(UInt32 mask, volatile UInt32 * value)
1c79356b 170{
cb323159 171 return os_atomic_xor_orig(value, mask, relaxed);
1c79356b
A
172}
173
0a7de745
A
174static Boolean
175OSTestAndSetClear(UInt32 bit, Boolean wantSet, volatile UInt8 * startAddress)
1c79356b 176{
0a7de745 177 UInt8 mask = 1;
cb323159 178 UInt8 oldValue, newValue;
0a7de745 179 UInt8 wantValue;
cb323159 180 UInt8 *address;
0a7de745 181
cb323159 182 address = (UInt8 *)(uintptr_t)(startAddress + (bit / 8));
1c79356b
A
183 mask <<= (7 - (bit % 8));
184 wantValue = wantSet ? mask : 0;
0a7de745 185
cb323159 186 return !os_atomic_rmw_loop(address, oldValue, newValue, relaxed, {
1c79356b 187 if ((oldValue & mask) == wantValue) {
cb323159 188 os_atomic_rmw_loop_give_up(break);
1c79356b 189 }
cb323159
A
190 newValue = (oldValue & ~mask) | wantValue;
191 });
1c79356b
A
192}
193
0a7de745
A
194Boolean
195OSTestAndSet(UInt32 bit, volatile UInt8 * startAddress)
1c79356b
A
196{
197 return OSTestAndSetClear(bit, true, startAddress);
198}
199
0a7de745
A
200Boolean
201OSTestAndClear(UInt32 bit, volatile UInt8 * startAddress)
1c79356b
A
202{
203 return OSTestAndSetClear(bit, false, startAddress);
204}
205
1c79356b
A
206/*
207 * silly unaligned versions
208 */
209
0a7de745
A
210SInt8
211OSIncrementAtomic8(volatile SInt8 * value)
1c79356b 212{
cb323159 213 return os_atomic_inc_orig(value, relaxed);
1c79356b
A
214}
215
0a7de745
A
216SInt8
217OSDecrementAtomic8(volatile SInt8 * value)
1c79356b 218{
cb323159 219 return os_atomic_dec_orig(value, relaxed);
1c79356b
A
220}
221
0a7de745
A
222UInt8
223OSBitAndAtomic8(UInt32 mask, volatile UInt8 * value)
1c79356b 224{
cb323159 225 return os_atomic_and_orig(value, mask, relaxed);
1c79356b
A
226}
227
0a7de745
A
228UInt8
229OSBitOrAtomic8(UInt32 mask, volatile UInt8 * value)
1c79356b 230{
cb323159 231 return os_atomic_or_orig(value, mask, relaxed);
1c79356b
A
232}
233
0a7de745
A
234UInt8
235OSBitXorAtomic8(UInt32 mask, volatile UInt8 * value)
1c79356b 236{
cb323159 237 return os_atomic_xor_orig(value, mask, relaxed);
1c79356b
A
238}
239
0a7de745
A
240SInt16
241OSIncrementAtomic16(volatile SInt16 * value)
1c79356b
A
242{
243 return OSAddAtomic16(1, value);
244}
245
0a7de745
A
246SInt16
247OSDecrementAtomic16(volatile SInt16 * value)
1c79356b
A
248{
249 return OSAddAtomic16(-1, value);
250}
251
0a7de745
A
252UInt16
253OSBitAndAtomic16(UInt32 mask, volatile UInt16 * value)
1c79356b 254{
cb323159 255 return os_atomic_and_orig(value, mask, relaxed);
1c79356b
A
256}
257
0a7de745
A
258UInt16
259OSBitOrAtomic16(UInt32 mask, volatile UInt16 * value)
1c79356b 260{
cb323159 261 return os_atomic_or_orig(value, mask, relaxed);
1c79356b
A
262}
263
0a7de745
A
264UInt16
265OSBitXorAtomic16(UInt32 mask, volatile UInt16 * value)
1c79356b 266{
cb323159 267 return os_atomic_xor_orig(value, mask, relaxed);
1c79356b 268}