blob: 4cefa6b93bfcd2463824173b8f160cc78a578574 [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <cutils/atomic.h>
Andy McFaddenac322da2010-05-19 22:33:28 -070018#include <cutils/atomic-inline.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070019#ifdef HAVE_WIN32_THREADS
20#include <windows.h>
21#else
22#include <sched.h>
23#endif
24
25/*****************************************************************************/
26#if defined(HAVE_MACOSX_IPC)
27
28#include <libkern/OSAtomic.h>
29
Andy McFadden8dfa47d2010-05-27 10:10:18 -070030int32_t android_atomic_acquire_load(volatile int32_t* addr) {
31 int32_t value = *addr;
32 OSMemoryBarrier();
33 return value;
34}
35
36int32_t android_atomic_release_load(volatile int32_t* addr) {
37 OSMemoryBarrier();
38 return *addr;
39}
40
41void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) {
42 *addr = value;
43 OSMemoryBarrier();
44}
45
46void android_atomic_release_store(int32_t value, volatile int32_t* addr) {
47 OSMemoryBarrier();
48 *addr = value;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070049}
50
51int32_t android_atomic_inc(volatile int32_t* addr) {
52 return OSAtomicIncrement32Barrier((int32_t*)addr)-1;
53}
54
55int32_t android_atomic_dec(volatile int32_t* addr) {
56 return OSAtomicDecrement32Barrier((int32_t*)addr)+1;
57}
58
59int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
60 return OSAtomicAdd32Barrier(value, (int32_t*)addr)-value;
61}
62
63int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
Andy McFadden8dfa47d2010-05-27 10:10:18 -070064 return OSAtomicAnd32OrigBarrier(value, (int32_t*)addr);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070065}
66
67int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
Andy McFadden8dfa47d2010-05-27 10:10:18 -070068 return OSAtomicOr32OrigBarrier(value, (int32_t*)addr);
69}
70
71int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070072 int32_t oldValue;
73 do {
74 oldValue = *addr;
Andy McFadden8dfa47d2010-05-27 10:10:18 -070075 } while (android_atomic_acquire_cas(oldValue, value, addr));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070076 return oldValue;
77}
78
Andy McFadden8dfa47d2010-05-27 10:10:18 -070079int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070080 int32_t oldValue;
81 do {
82 oldValue = *addr;
Andy McFadden8dfa47d2010-05-27 10:10:18 -070083 } while (android_atomic_release_cas(oldValue, value, addr));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070084 return oldValue;
85}
86
Andy McFadden8dfa47d2010-05-27 10:10:18 -070087int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
Andy McFaddenac322da2010-05-19 22:33:28 -070088 /* OS X CAS returns zero on failure; invert to return zero on success */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070089 return OSAtomicCompareAndSwap32Barrier(oldvalue, newvalue, (int32_t*)addr) == 0;
90}
91
Andy McFadden8dfa47d2010-05-27 10:10:18 -070092int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
Andy McFaddenac322da2010-05-19 22:33:28 -070093 volatile int32_t* addr) {
94 int result = (OSAtomicCompareAndSwap32(oldvalue, newvalue, (int32_t*)addr) == 0);
Andy McFadden8dfa47d2010-05-27 10:10:18 -070095 if (result == 0) {
Andy McFaddenac322da2010-05-19 22:33:28 -070096 /* success, perform barrier */
97 OSMemoryBarrier();
98 }
Andy McFadden8dfa47d2010-05-27 10:10:18 -070099 return result;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700100}
101
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700102/*****************************************************************************/
103#elif defined(__i386__) || defined(__x86_64__)
104
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700105int32_t android_atomic_acquire_load(volatile int32_t* addr) {
106 int32_t value = *addr;
107 ANDROID_MEMBAR_FULL();
108 return value;
109}
110
111int32_t android_atomic_release_load(volatile int32_t* addr) {
112 ANDROID_MEMBAR_FULL();
113 return *addr;
114}
115
116void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) {
117 *addr = value;
118 ANDROID_MEMBAR_FULL();
119}
120
121void android_atomic_release_store(int32_t value, volatile int32_t* addr) {
122 ANDROID_MEMBAR_FULL();
123 *addr = value;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700124}
125
126int32_t android_atomic_inc(volatile int32_t* addr) {
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700127 return android_atomic_add(1, addr);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700128}
129
130int32_t android_atomic_dec(volatile int32_t* addr) {
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700131 return android_atomic_add(-1, addr);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700132}
133
134int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
135 int32_t oldValue;
136 do {
137 oldValue = *addr;
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700138 } while (android_atomic_release_cas(oldValue, oldValue+value, addr));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700139 return oldValue;
140}
141
142int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
143 int32_t oldValue;
144 do {
145 oldValue = *addr;
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700146 } while (android_atomic_release_cas(oldValue, oldValue&value, addr));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700147 return oldValue;
148}
149
150int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
151 int32_t oldValue;
152 do {
153 oldValue = *addr;
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700154 } while (android_atomic_release_cas(oldValue, oldValue|value, addr));
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700155 return oldValue;
156}
157
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700158/* returns 0 on successful swap */
159static inline int cas(int32_t oldvalue, int32_t newvalue,
160 volatile int32_t* addr) {
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700161 int xchg;
162 asm volatile
163 (
164 " lock; cmpxchg %%ecx, (%%edx);"
165 " setne %%al;"
166 " andl $1, %%eax"
167 : "=a" (xchg)
168 : "a" (oldvalue), "c" (newvalue), "d" (addr)
169 );
170 return xchg;
171}
172
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700173int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
174 int32_t oldValue;
175 do {
176 oldValue = *addr;
177 } while (cas(oldValue, value, addr));
178 ANDROID_MEMBAR_FULL();
179 return oldValue;
180}
181
182int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) {
183 ANDROID_MEMBAR_FULL();
184 int32_t oldValue;
185 do {
186 oldValue = *addr;
187 } while (cas(oldValue, value, addr));
188 return oldValue;
189}
190
191int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
Andy McFaddenac322da2010-05-19 22:33:28 -0700192 volatile int32_t* addr) {
Andy McFadden8dfa47d2010-05-27 10:10:18 -0700193 int xchg = cas(oldvalue, newvalue, addr);
194 if (xchg == 0)
195 ANDROID_MEMBAR_FULL();
196 return xchg;
197}
198
199int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
200 volatile int32_t* addr) {
201 ANDROID_MEMBAR_FULL();
202 int xchg = cas(oldvalue, newvalue, addr);
Andy McFaddenac322da2010-05-19 22:33:28 -0700203 return xchg;
204}
205
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700206
207/*****************************************************************************/
208#elif __arm__
Andy McFaddenac322da2010-05-19 22:33:28 -0700209// implementation for ARM is in atomic-android-arm.s.
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700210
Shin-ichiro KAWASAKIc6af9112009-08-04 19:14:22 +0900211/*****************************************************************************/
212#elif __sh__
213// implementation for SuperH is in atomic-android-sh.c.
214
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700215#else
216
217#error "Unsupported atomic operations for this platform"
218
219#endif
220