blob: 0dd629d86d9b1abbf6e16b7e3c37cc267da477a9 [file] [log] [blame]
Carl Shapiro93b0cb42010-06-03 17:05:15 -07001/*
2 * Copyright (C) 2010 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#ifndef ANDROID_CUTILS_ATOMIC_ARM_H
18#define ANDROID_CUTILS_ATOMIC_ARM_H
19
20#include <stdint.h>
21#include <machine/cpu-features.h>
22
23extern inline void android_compiler_barrier(void)
24{
25 __asm__ __volatile__ ("" : : : "memory");
26}
27
28#if ANDROID_SMP == 0
29extern inline void android_memory_barrier(void)
30{
31 android_compiler_barrier();
32}
33#elif defined(__ARM_HAVE_DMB)
34extern inline void android_memory_barrier(void)
35{
36 __asm__ __volatile__ ("dmb" : : : "memory");
37}
38#elif defined(__ARM_HAVE_LDREX_STREX)
39extern inline void android_memory_barrier(void)
40{
41 __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5"
42 : : "r" (0) : "memory");
43}
44#else
45extern inline void android_memory_barrier(void)
46{
47 typedef void (kuser_memory_barrier)(void);
48 (*(kuser_memory_barrier *)0xffff0fa0)();
49}
50#endif
51
52extern inline int32_t android_atomic_acquire_load(volatile int32_t *ptr)
53{
54 int32_t value = *ptr;
55 android_memory_barrier();
56 return value;
57}
58
59extern inline int32_t android_atomic_release_load(volatile int32_t *ptr)
60{
61 android_memory_barrier();
62 return *ptr;
63}
64
65extern inline void android_atomic_acquire_store(int32_t value,
66 volatile int32_t *ptr)
67{
68 *ptr = value;
69 android_memory_barrier();
70}
71
72extern inline void android_atomic_release_store(int32_t value,
73 volatile int32_t *ptr)
74{
75 android_memory_barrier();
76 *ptr = value;
77}
78
79#if defined(__thumb__)
80extern int android_atomic_cas(int32_t old_value, int32_t new_value,
81 volatile int32_t *ptr);
82#elif defined(__ARM_HAVE_LDREX_STREX)
83extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
84 volatile int32_t *ptr)
85{
86 int32_t prev, status;
87 do {
88 __asm__ __volatile__ ("ldrex %0, [%3]\n"
89 "mov %1, #0\n"
90 "teq %0, %4\n"
91 "strexeq %1, %5, [%3]"
92 : "=&r" (prev), "=&r" (status), "+m"(*ptr)
93 : "r" (ptr), "Ir" (old_value), "r" (new_value)
94 : "cc");
95 } while (__builtin_expect(status != 0, 0));
96 return prev != old_value;
97}
98#else
99extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
100 volatile int32_t *ptr)
101{
102 typedef int (kuser_cmpxchg)(int32_t, int32_t, volatile int32_t *);
103 int32_t prev, status;
104 prev = *ptr;
105 do {
106 status = (*(kuser_cmpxchg *)0xffff0fc0)(old_value, new_value, ptr);
107 if (__builtin_expect(status == 0, 1))
108 return 0;
109 prev = *ptr;
110 } while (prev == old_value);
111 return 1;
112}
113#endif
114
115extern inline int android_atomic_acquire_cas(int32_t old_value,
116 int32_t new_value,
117 volatile int32_t *ptr)
118{
119 int status = android_atomic_cas(old_value, new_value, ptr);
120 android_memory_barrier();
121 return status;
122}
123
124extern inline int android_atomic_release_cas(int32_t old_value,
125 int32_t new_value,
126 volatile int32_t *ptr)
127{
128 android_memory_barrier();
129 return android_atomic_cas(old_value, new_value, ptr);
130}
131
132
133#if defined(__thumb__)
134extern int32_t android_atomic_swap(int32_t new_value,
135 volatile int32_t *ptr);
136#elif defined(__ARM_HAVE_LDREX_STREX)
137extern inline int32_t android_atomic_swap(int32_t new_value,
138 volatile int32_t *ptr)
139{
140 int32_t prev, status;
141 do {
142 __asm__ __volatile__ ("ldrex %0, [%3]\n"
143 "strex %1, %4, [%3]"
144 : "=&r" (prev), "=&r" (status), "+m" (*ptr)
145 : "r" (ptr), "r" (new_value)
146 : "cc");
147 } while (__builtin_expect(status != 0, 0));
148 android_memory_barrier();
149 return prev;
150}
151#else
152extern inline int32_t android_atomic_swap(int32_t new_value,
153 volatile int32_t *ptr)
154{
155 int32_t prev;
156 __asm__ __volatile__ ("swp %0, %2, [%3]"
157 : "=&r" (prev), "+m" (*ptr)
158 : "r" (new_value), "r" (ptr)
159 : "cc");
160 android_memory_barrier();
161 return prev;
162}
163#endif
164
165#if defined(__thumb__)
166extern int32_t android_atomic_add(int32_t increment,
167 volatile int32_t *ptr);
168#elif defined(__ARM_HAVE_LDREX_STREX)
169extern inline int32_t android_atomic_add(int32_t increment,
170 volatile int32_t *ptr)
171{
172 int32_t prev, tmp, status;
173 android_memory_barrier();
174 do {
175 __asm__ __volatile__ ("ldrex %0, [%4]\n"
176 "add %1, %0, %5\n"
177 "strex %2, %1, [%4]"
178 : "=&r" (prev), "=&r" (tmp),
179 "=&r" (status), "+m" (*ptr)
180 : "r" (ptr), "Ir" (increment)
181 : "cc");
182 } while (__builtin_expect(status != 0, 0));
183 return prev;
184}
185#else
186extern inline int32_t android_atomic_add(int32_t increment,
187 volatile int32_t *ptr)
188{
189 int32_t prev, status;
190 android_memory_barrier();
191 do {
192 prev = *ptr;
193 status = android_atomic_cas(prev, prev + increment, ptr);
194 } while (__builtin_expect(status != 0, 0));
195 return prev;
196}
197#endif
198
199extern inline int32_t android_atomic_inc(volatile int32_t *addr) {
200 return android_atomic_add(1, addr);
201}
202
203extern inline int32_t android_atomic_dec(volatile int32_t *addr) {
204 return android_atomic_add(-1, addr);
205}
206
207#if defined(__thumb__)
208extern int32_t android_atomic_and(int32_t value, volatile int32_t *ptr);
209#elif defined(__ARM_HAVE_LDREX_STREX)
210extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
211{
212 int32_t prev, tmp, status;
213 android_memory_barrier();
214 do {
215 __asm__ __volatile__ ("ldrex %0, [%4]\n"
216 "and %1, %0, %5\n"
217 "strex %2, %1, [%4]"
218 : "=&r" (prev), "=&r" (tmp),
219 "=&r" (status), "+m" (*ptr)
220 : "r" (ptr), "Ir" (value)
221 : "cc");
222 } while (__builtin_expect(status != 0, 0));
223 return prev;
224}
225#else
226extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
227{
228 int32_t prev, status;
229 android_memory_barrier();
230 do {
231 prev = *ptr;
232 status = android_atomic_cas(prev, prev & value, ptr);
233 } while (__builtin_expect(status != 0, 0));
234 return prev;
235}
236#endif
237
238#if defined(__thumb__)
239extern int32_t android_atomic_or(int32_t value, volatile int32_t *ptr);
240#elif defined(__ARM_HAVE_LDREX_STREX)
241extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
242{
243 int32_t prev, tmp, status;
244 android_memory_barrier();
245 do {
246 __asm__ __volatile__ ("ldrex %0, [%4]\n"
247 "orr %1, %0, %5\n"
248 "strex %2, %1, [%4]"
249 : "=&r" (prev), "=&r" (tmp),
250 "=&r" (status), "+m" (*ptr)
251 : "r" (ptr), "Ir" (value)
252 : "cc");
253 } while (__builtin_expect(status != 0, 0));
254 return prev;
255}
256#else
257extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
258{
259 int32_t prev, status;
260 android_memory_barrier();
261 do {
262 prev = *ptr;
263 status = android_atomic_cas(prev, prev | value, ptr);
264 } while (__builtin_expect(status != 0, 0));
265 return prev;
266}
267#endif
268
269#endif /* ANDROID_CUTILS_ATOMIC_ARM_H */