blob: d81890614fb6e8cff1b5838175f2a6d24d5df175 [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
30void android_atomic_write(int32_t value, volatile int32_t* addr) {
31 int32_t oldValue;
32 do {
33 oldValue = *addr;
34 } while (OSAtomicCompareAndSwap32Barrier(oldValue, value, (int32_t*)addr) == 0);
35}
36
37int32_t android_atomic_inc(volatile int32_t* addr) {
38 return OSAtomicIncrement32Barrier((int32_t*)addr)-1;
39}
40
41int32_t android_atomic_dec(volatile int32_t* addr) {
42 return OSAtomicDecrement32Barrier((int32_t*)addr)+1;
43}
44
45int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
46 return OSAtomicAdd32Barrier(value, (int32_t*)addr)-value;
47}
48
49int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
50 int32_t oldValue;
51 do {
52 oldValue = *addr;
53 } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue&value, (int32_t*)addr) == 0);
54 return oldValue;
55}
56
57int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
58 int32_t oldValue;
59 do {
60 oldValue = *addr;
61 } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue|value, (int32_t*)addr) == 0);
62 return oldValue;
63}
64
65int32_t android_atomic_swap(int32_t value, volatile int32_t* addr) {
66 int32_t oldValue;
67 do {
68 oldValue = *addr;
69 } while (android_atomic_cmpxchg(oldValue, value, addr));
70 return oldValue;
71}
72
73int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
Andy McFaddenac322da2010-05-19 22:33:28 -070074 /* OS X CAS returns zero on failure; invert to return zero on success */
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070075 return OSAtomicCompareAndSwap32Barrier(oldvalue, newvalue, (int32_t*)addr) == 0;
76}
77
Andy McFaddenac322da2010-05-19 22:33:28 -070078int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
79 volatile int32_t* addr) {
80 int result = (OSAtomicCompareAndSwap32(oldvalue, newvalue, (int32_t*)addr) == 0);
81 if (!result) {
82 /* success, perform barrier */
83 OSMemoryBarrier();
84 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070085}
86
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070087/*****************************************************************************/
88#elif defined(__i386__) || defined(__x86_64__)
89
90void android_atomic_write(int32_t value, volatile int32_t* addr) {
91 int32_t oldValue;
92 do {
93 oldValue = *addr;
94 } while (android_atomic_cmpxchg(oldValue, value, addr));
95}
96
97int32_t android_atomic_inc(volatile int32_t* addr) {
98 int32_t oldValue;
99 do {
100 oldValue = *addr;
101 } while (android_atomic_cmpxchg(oldValue, oldValue+1, addr));
102 return oldValue;
103}
104
105int32_t android_atomic_dec(volatile int32_t* addr) {
106 int32_t oldValue;
107 do {
108 oldValue = *addr;
109 } while (android_atomic_cmpxchg(oldValue, oldValue-1, addr));
110 return oldValue;
111}
112
113int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
114 int32_t oldValue;
115 do {
116 oldValue = *addr;
117 } while (android_atomic_cmpxchg(oldValue, oldValue+value, addr));
118 return oldValue;
119}
120
121int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
122 int32_t oldValue;
123 do {
124 oldValue = *addr;
125 } while (android_atomic_cmpxchg(oldValue, oldValue&value, addr));
126 return oldValue;
127}
128
129int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
130 int32_t oldValue;
131 do {
132 oldValue = *addr;
133 } while (android_atomic_cmpxchg(oldValue, oldValue|value, addr));
134 return oldValue;
135}
136
137int32_t android_atomic_swap(int32_t value, volatile int32_t* addr) {
138 int32_t oldValue;
139 do {
140 oldValue = *addr;
141 } while (android_atomic_cmpxchg(oldValue, value, addr));
142 return oldValue;
143}
144
145int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
Andy McFaddenac322da2010-05-19 22:33:28 -0700146 android_membar_full();
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700147 int xchg;
148 asm volatile
149 (
150 " lock; cmpxchg %%ecx, (%%edx);"
151 " setne %%al;"
152 " andl $1, %%eax"
153 : "=a" (xchg)
154 : "a" (oldvalue), "c" (newvalue), "d" (addr)
155 );
156 return xchg;
157}
158
Andy McFaddenac322da2010-05-19 22:33:28 -0700159int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
160 volatile int32_t* addr) {
161 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 android_membar_full();
171 return xchg;
172}
173
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700174
175/*****************************************************************************/
176#elif __arm__
Andy McFaddenac322da2010-05-19 22:33:28 -0700177// implementation for ARM is in atomic-android-arm.s.
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700178
Shin-ichiro KAWASAKIc6af9112009-08-04 19:14:22 +0900179/*****************************************************************************/
180#elif __sh__
181// implementation for SuperH is in atomic-android-sh.c.
182
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700183#else
184
185#error "Unsupported atomic operations for this platform"
186
187#endif
188