blob: 6b031b678623ac6ee929cc506749e846663ef9e5 [file] [log] [blame]
Hans Boehm2789faa2014-10-04 00:49:06 +00001/*
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
22#ifndef ANDROID_ATOMIC_INLINE
23#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
24#endif
25
26extern ANDROID_ATOMIC_INLINE void android_compiler_barrier()
27{
28 __asm__ __volatile__ ("" : : : "memory");
29}
30
31extern ANDROID_ATOMIC_INLINE void android_memory_barrier()
32{
33#if ANDROID_SMP == 0
34 android_compiler_barrier();
35#else
36 __asm__ __volatile__ ("dmb" : : : "memory");
37#endif
38}
39
40extern ANDROID_ATOMIC_INLINE
41int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
42{
43 int32_t value = *ptr;
44 android_memory_barrier();
45 return value;
46}
47
48extern ANDROID_ATOMIC_INLINE
49int32_t android_atomic_release_load(volatile const int32_t *ptr)
50{
51 android_memory_barrier();
52 return *ptr;
53}
54
55extern ANDROID_ATOMIC_INLINE
56void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
57{
58 *ptr = value;
59 android_memory_barrier();
60}
61
62extern ANDROID_ATOMIC_INLINE
63void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
64{
65 android_memory_barrier();
66 *ptr = value;
67}
68
69extern ANDROID_ATOMIC_INLINE
70int android_atomic_cas(int32_t old_value, int32_t new_value,
71 volatile int32_t *ptr)
72{
73 int32_t prev, status;
74 do {
75 __asm__ __volatile__ ("ldrex %0, [%3]\n"
76 "mov %1, #0\n"
77 "teq %0, %4\n"
78#ifdef __thumb2__
79 "it eq\n"
80#endif
81 "strexeq %1, %5, [%3]"
82 : "=&r" (prev), "=&r" (status), "+m"(*ptr)
83 : "r" (ptr), "Ir" (old_value), "r" (new_value)
84 : "cc");
85 } while (__builtin_expect(status != 0, 0));
86 return prev != old_value;
87}
88
89extern ANDROID_ATOMIC_INLINE
90int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
91 volatile int32_t *ptr)
92{
93 int status = android_atomic_cas(old_value, new_value, ptr);
94 android_memory_barrier();
95 return status;
96}
97
98extern ANDROID_ATOMIC_INLINE
99int android_atomic_release_cas(int32_t old_value, int32_t new_value,
100 volatile int32_t *ptr)
101{
102 android_memory_barrier();
103 return android_atomic_cas(old_value, new_value, ptr);
104}
105
106extern ANDROID_ATOMIC_INLINE
107int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
108{
109 int32_t prev, tmp, status;
110 android_memory_barrier();
111 do {
112 __asm__ __volatile__ ("ldrex %0, [%4]\n"
113 "add %1, %0, %5\n"
114 "strex %2, %1, [%4]"
115 : "=&r" (prev), "=&r" (tmp),
116 "=&r" (status), "+m" (*ptr)
117 : "r" (ptr), "Ir" (increment)
118 : "cc");
119 } while (__builtin_expect(status != 0, 0));
120 return prev;
121}
122
123extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr)
124{
125 return android_atomic_add(1, addr);
126}
127
128extern ANDROID_ATOMIC_INLINE int32_t android_atomic_dec(volatile int32_t *addr)
129{
130 return android_atomic_add(-1, addr);
131}
132
133extern ANDROID_ATOMIC_INLINE
134int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
135{
136 int32_t prev, tmp, status;
137 android_memory_barrier();
138 do {
139 __asm__ __volatile__ ("ldrex %0, [%4]\n"
140 "and %1, %0, %5\n"
141 "strex %2, %1, [%4]"
142 : "=&r" (prev), "=&r" (tmp),
143 "=&r" (status), "+m" (*ptr)
144 : "r" (ptr), "Ir" (value)
145 : "cc");
146 } while (__builtin_expect(status != 0, 0));
147 return prev;
148}
149
150extern ANDROID_ATOMIC_INLINE
151int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
152{
153 int32_t prev, tmp, status;
154 android_memory_barrier();
155 do {
156 __asm__ __volatile__ ("ldrex %0, [%4]\n"
157 "orr %1, %0, %5\n"
158 "strex %2, %1, [%4]"
159 : "=&r" (prev), "=&r" (tmp),
160 "=&r" (status), "+m" (*ptr)
161 : "r" (ptr), "Ir" (value)
162 : "cc");
163 } while (__builtin_expect(status != 0, 0));
164 return prev;
165}
166
167#endif /* ANDROID_CUTILS_ATOMIC_ARM_H */