blob: 795afd39a4c0480c455cb7696cf146ed79abc0ac [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
Ben Cheng5206d592012-12-07 10:54:09 -080023#ifndef ANDROID_ATOMIC_INLINE
24#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
25#endif
26
27extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070028{
29 __asm__ __volatile__ ("" : : : "memory");
30}
31
32#if ANDROID_SMP == 0
Ben Cheng5206d592012-12-07 10:54:09 -080033extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070034{
Brian Carlstrom464431e2010-09-24 10:56:43 -070035 android_compiler_barrier();
36}
Ben Cheng5206d592012-12-07 10:54:09 -080037extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
Brian Carlstrom464431e2010-09-24 10:56:43 -070038{
39 android_compiler_barrier();
Carl Shapiro93b0cb42010-06-03 17:05:15 -070040}
41#elif defined(__ARM_HAVE_DMB)
Ben Cheng5206d592012-12-07 10:54:09 -080042extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070043{
44 __asm__ __volatile__ ("dmb" : : : "memory");
45}
Ben Cheng5206d592012-12-07 10:54:09 -080046extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
Brian Carlstrom464431e2010-09-24 10:56:43 -070047{
Andy McFadden2bf937e2010-10-01 11:29:48 -070048 __asm__ __volatile__ ("dmb st" : : : "memory");
Brian Carlstrom464431e2010-09-24 10:56:43 -070049}
Carl Shapiro93b0cb42010-06-03 17:05:15 -070050#elif defined(__ARM_HAVE_LDREX_STREX)
Ben Cheng5206d592012-12-07 10:54:09 -080051extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070052{
Brian Carlstrom464431e2010-09-24 10:56:43 -070053 __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory");
54}
Ben Cheng5206d592012-12-07 10:54:09 -080055extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
Brian Carlstrom464431e2010-09-24 10:56:43 -070056{
57 android_memory_barrier();
Carl Shapiro93b0cb42010-06-03 17:05:15 -070058}
59#else
Ben Cheng5206d592012-12-07 10:54:09 -080060extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070061{
62 typedef void (kuser_memory_barrier)(void);
63 (*(kuser_memory_barrier *)0xffff0fa0)();
64}
Ben Cheng5206d592012-12-07 10:54:09 -080065extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
Brian Carlstrom464431e2010-09-24 10:56:43 -070066{
67 android_memory_barrier();
68}
Carl Shapiro93b0cb42010-06-03 17:05:15 -070069#endif
70
Ben Cheng5206d592012-12-07 10:54:09 -080071extern ANDROID_ATOMIC_INLINE
72int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070073{
74 int32_t value = *ptr;
75 android_memory_barrier();
76 return value;
77}
78
Ben Cheng5206d592012-12-07 10:54:09 -080079extern ANDROID_ATOMIC_INLINE
80int32_t android_atomic_release_load(volatile const int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070081{
82 android_memory_barrier();
83 return *ptr;
84}
85
Ben Cheng5206d592012-12-07 10:54:09 -080086extern ANDROID_ATOMIC_INLINE void
87android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070088{
89 *ptr = value;
90 android_memory_barrier();
91}
92
Ben Cheng5206d592012-12-07 10:54:09 -080093extern ANDROID_ATOMIC_INLINE void
94android_atomic_release_store(int32_t value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -070095{
96 android_memory_barrier();
97 *ptr = value;
98}
99
100#if defined(__thumb__)
101extern int android_atomic_cas(int32_t old_value, int32_t new_value,
102 volatile int32_t *ptr);
103#elif defined(__ARM_HAVE_LDREX_STREX)
Ben Cheng5206d592012-12-07 10:54:09 -0800104extern ANDROID_ATOMIC_INLINE int
105android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700106{
107 int32_t prev, status;
108 do {
109 __asm__ __volatile__ ("ldrex %0, [%3]\n"
110 "mov %1, #0\n"
111 "teq %0, %4\n"
112 "strexeq %1, %5, [%3]"
113 : "=&r" (prev), "=&r" (status), "+m"(*ptr)
114 : "r" (ptr), "Ir" (old_value), "r" (new_value)
115 : "cc");
116 } while (__builtin_expect(status != 0, 0));
117 return prev != old_value;
118}
119#else
Ben Cheng5206d592012-12-07 10:54:09 -0800120extern ANDROID_ATOMIC_INLINE int
121android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700122{
123 typedef int (kuser_cmpxchg)(int32_t, int32_t, volatile int32_t *);
124 int32_t prev, status;
125 prev = *ptr;
126 do {
127 status = (*(kuser_cmpxchg *)0xffff0fc0)(old_value, new_value, ptr);
128 if (__builtin_expect(status == 0, 1))
129 return 0;
130 prev = *ptr;
131 } while (prev == old_value);
132 return 1;
133}
134#endif
135
Ben Cheng5206d592012-12-07 10:54:09 -0800136extern ANDROID_ATOMIC_INLINE int
137android_atomic_acquire_cas(int32_t old_value,
138 int32_t new_value,
139 volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700140{
141 int status = android_atomic_cas(old_value, new_value, ptr);
142 android_memory_barrier();
143 return status;
144}
145
Ben Cheng5206d592012-12-07 10:54:09 -0800146extern ANDROID_ATOMIC_INLINE int
147android_atomic_release_cas(int32_t old_value,
148 int32_t new_value,
149 volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700150{
151 android_memory_barrier();
152 return android_atomic_cas(old_value, new_value, ptr);
153}
154
155
156#if defined(__thumb__)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700157extern int32_t android_atomic_add(int32_t increment,
158 volatile int32_t *ptr);
159#elif defined(__ARM_HAVE_LDREX_STREX)
Ben Cheng5206d592012-12-07 10:54:09 -0800160extern ANDROID_ATOMIC_INLINE int32_t
161android_atomic_add(int32_t increment, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700162{
163 int32_t prev, tmp, status;
164 android_memory_barrier();
165 do {
166 __asm__ __volatile__ ("ldrex %0, [%4]\n"
167 "add %1, %0, %5\n"
168 "strex %2, %1, [%4]"
169 : "=&r" (prev), "=&r" (tmp),
170 "=&r" (status), "+m" (*ptr)
171 : "r" (ptr), "Ir" (increment)
172 : "cc");
173 } while (__builtin_expect(status != 0, 0));
174 return prev;
175}
176#else
Ben Cheng5206d592012-12-07 10:54:09 -0800177extern ANDROID_ATOMIC_INLINE int32_t
178android_atomic_add(int32_t increment, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700179{
180 int32_t prev, status;
181 android_memory_barrier();
182 do {
183 prev = *ptr;
184 status = android_atomic_cas(prev, prev + increment, ptr);
185 } while (__builtin_expect(status != 0, 0));
186 return prev;
187}
188#endif
189
Ben Cheng5206d592012-12-07 10:54:09 -0800190extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr)
Carl Shapirod55f0ad2010-09-28 13:47:03 -0700191{
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700192 return android_atomic_add(1, addr);
193}
194
Ben Cheng5206d592012-12-07 10:54:09 -0800195extern ANDROID_ATOMIC_INLINE int32_t android_atomic_dec(volatile int32_t *addr)
Carl Shapirod55f0ad2010-09-28 13:47:03 -0700196{
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700197 return android_atomic_add(-1, addr);
198}
199
200#if defined(__thumb__)
201extern int32_t android_atomic_and(int32_t value, volatile int32_t *ptr);
202#elif defined(__ARM_HAVE_LDREX_STREX)
Ben Cheng5206d592012-12-07 10:54:09 -0800203extern ANDROID_ATOMIC_INLINE int32_t
204android_atomic_and(int32_t value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700205{
206 int32_t prev, tmp, status;
207 android_memory_barrier();
208 do {
209 __asm__ __volatile__ ("ldrex %0, [%4]\n"
210 "and %1, %0, %5\n"
211 "strex %2, %1, [%4]"
212 : "=&r" (prev), "=&r" (tmp),
213 "=&r" (status), "+m" (*ptr)
214 : "r" (ptr), "Ir" (value)
215 : "cc");
216 } while (__builtin_expect(status != 0, 0));
217 return prev;
218}
219#else
Ben Cheng5206d592012-12-07 10:54:09 -0800220extern ANDROID_ATOMIC_INLINE int32_t
221android_atomic_and(int32_t value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700222{
223 int32_t prev, status;
224 android_memory_barrier();
225 do {
226 prev = *ptr;
227 status = android_atomic_cas(prev, prev & value, ptr);
228 } while (__builtin_expect(status != 0, 0));
229 return prev;
230}
231#endif
232
233#if defined(__thumb__)
234extern int32_t android_atomic_or(int32_t value, volatile int32_t *ptr);
235#elif defined(__ARM_HAVE_LDREX_STREX)
Ben Cheng5206d592012-12-07 10:54:09 -0800236extern ANDROID_ATOMIC_INLINE int32_t
237android_atomic_or(int32_t value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700238{
239 int32_t prev, tmp, status;
240 android_memory_barrier();
241 do {
242 __asm__ __volatile__ ("ldrex %0, [%4]\n"
243 "orr %1, %0, %5\n"
244 "strex %2, %1, [%4]"
245 : "=&r" (prev), "=&r" (tmp),
246 "=&r" (status), "+m" (*ptr)
247 : "r" (ptr), "Ir" (value)
248 : "cc");
249 } while (__builtin_expect(status != 0, 0));
250 return prev;
251}
252#else
Ben Cheng5206d592012-12-07 10:54:09 -0800253extern ANDROID_ATOMIC_INLINE int32_t
254android_atomic_or(int32_t value, volatile int32_t *ptr)
Carl Shapiro93b0cb42010-06-03 17:05:15 -0700255{
256 int32_t prev, status;
257 android_memory_barrier();
258 do {
259 prev = *ptr;
260 status = android_atomic_cas(prev, prev | value, ptr);
261 } while (__builtin_expect(status != 0, 0));
262 return prev;
263}
264#endif
265
266#endif /* ANDROID_CUTILS_ATOMIC_ARM_H */