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