]>
Commit | Line | Data |
---|---|---|
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 | |
33 | enum { | |
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 |
59 | Boolean |
60 | OSCompareAndSwap8(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 |
66 | Boolean |
67 | OSCompareAndSwap16(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 |
73 | Boolean |
74 | OSCompareAndSwap(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 |
81 | Boolean |
82 | OSCompareAndSwap64(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 |
96 | Boolean |
97 | OSCompareAndSwapPtr(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 |
102 | SInt8 |
103 | OSAddAtomic8(SInt32 amount, volatile SInt8 *address) | |
3e170ce0 | 104 | { |
cb323159 | 105 | return os_atomic_add_orig(address, amount, relaxed); |
3e170ce0 A |
106 | } |
107 | ||
0a7de745 A |
108 | SInt16 |
109 | OSAddAtomic16(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 |
115 | SInt32 |
116 | OSAddAtomic(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 |
123 | SInt64 |
124 | OSAddAtomic64(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 | |
133 | long | |
134 | OSAddAtomicLong(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 |
140 | SInt32 |
141 | OSIncrementAtomic(volatile SInt32 * value) | |
91447636 | 142 | { |
cb323159 | 143 | return os_atomic_inc_orig(value, relaxed); |
91447636 A |
144 | } |
145 | ||
b0d623f7 | 146 | #undef OSDecrementAtomic |
0a7de745 A |
147 | SInt32 |
148 | OSDecrementAtomic(volatile SInt32 * value) | |
91447636 | 149 | { |
cb323159 | 150 | return os_atomic_dec_orig(value, relaxed); |
91447636 | 151 | } |
1c79356b | 152 | |
b0d623f7 | 153 | #undef OSBitAndAtomic |
0a7de745 A |
154 | UInt32 |
155 | OSBitAndAtomic(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 |
161 | UInt32 |
162 | OSBitOrAtomic(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 |
168 | UInt32 |
169 | OSBitXorAtomic(UInt32 mask, volatile UInt32 * value) | |
1c79356b | 170 | { |
cb323159 | 171 | return os_atomic_xor_orig(value, mask, relaxed); |
1c79356b A |
172 | } |
173 | ||
0a7de745 A |
174 | static Boolean |
175 | OSTestAndSetClear(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 |
194 | Boolean |
195 | OSTestAndSet(UInt32 bit, volatile UInt8 * startAddress) | |
1c79356b A |
196 | { |
197 | return OSTestAndSetClear(bit, true, startAddress); | |
198 | } | |
199 | ||
0a7de745 A |
200 | Boolean |
201 | OSTestAndClear(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 |
210 | SInt8 |
211 | OSIncrementAtomic8(volatile SInt8 * value) | |
1c79356b | 212 | { |
cb323159 | 213 | return os_atomic_inc_orig(value, relaxed); |
1c79356b A |
214 | } |
215 | ||
0a7de745 A |
216 | SInt8 |
217 | OSDecrementAtomic8(volatile SInt8 * value) | |
1c79356b | 218 | { |
cb323159 | 219 | return os_atomic_dec_orig(value, relaxed); |
1c79356b A |
220 | } |
221 | ||
0a7de745 A |
222 | UInt8 |
223 | OSBitAndAtomic8(UInt32 mask, volatile UInt8 * value) | |
1c79356b | 224 | { |
cb323159 | 225 | return os_atomic_and_orig(value, mask, relaxed); |
1c79356b A |
226 | } |
227 | ||
0a7de745 A |
228 | UInt8 |
229 | OSBitOrAtomic8(UInt32 mask, volatile UInt8 * value) | |
1c79356b | 230 | { |
cb323159 | 231 | return os_atomic_or_orig(value, mask, relaxed); |
1c79356b A |
232 | } |
233 | ||
0a7de745 A |
234 | UInt8 |
235 | OSBitXorAtomic8(UInt32 mask, volatile UInt8 * value) | |
1c79356b | 236 | { |
cb323159 | 237 | return os_atomic_xor_orig(value, mask, relaxed); |
1c79356b A |
238 | } |
239 | ||
0a7de745 A |
240 | SInt16 |
241 | OSIncrementAtomic16(volatile SInt16 * value) | |
1c79356b A |
242 | { |
243 | return OSAddAtomic16(1, value); | |
244 | } | |
245 | ||
0a7de745 A |
246 | SInt16 |
247 | OSDecrementAtomic16(volatile SInt16 * value) | |
1c79356b A |
248 | { |
249 | return OSAddAtomic16(-1, value); | |
250 | } | |
251 | ||
0a7de745 A |
252 | UInt16 |
253 | OSBitAndAtomic16(UInt32 mask, volatile UInt16 * value) | |
1c79356b | 254 | { |
cb323159 | 255 | return os_atomic_and_orig(value, mask, relaxed); |
1c79356b A |
256 | } |
257 | ||
0a7de745 A |
258 | UInt16 |
259 | OSBitOrAtomic16(UInt32 mask, volatile UInt16 * value) | |
1c79356b | 260 | { |
cb323159 | 261 | return os_atomic_or_orig(value, mask, relaxed); |
1c79356b A |
262 | } |
263 | ||
0a7de745 A |
264 | UInt16 |
265 | OSBitXorAtomic16(UInt32 mask, volatile UInt16 * value) | |
1c79356b | 266 | { |
cb323159 | 267 | return os_atomic_xor_orig(value, mask, relaxed); |
1c79356b | 268 | } |