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