atomic.c revision ac322da69ee48aa792baf5c48cfb719ce077f67e
1/*
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>
18#include <cutils/atomic-inline.h>
19#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) {
74    /* OS X CAS returns zero on failure; invert to return zero on success */
75    return OSAtomicCompareAndSwap32Barrier(oldvalue, newvalue, (int32_t*)addr) == 0;
76}
77
78int 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    }
85}
86
87/*****************************************************************************/
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) {
146    android_membar_full();
147    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
159int 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
174
175/*****************************************************************************/
176#elif __arm__
177// implementation for ARM is in atomic-android-arm.s.
178
179/*****************************************************************************/
180#elif __sh__
181// implementation for SuperH is in atomic-android-sh.c.
182
183#else
184
185#error "Unsupported atomic operations for this platform"
186
187#endif
188
189