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 #ifdef HAVE_WIN32_THREADS 19 #include <windows.h> 20 #else 21 #include <sched.h> 22 #endif 23 24 /* 25 * Note : 26 * 27 * (1) SuperH does not have CMPXCHG. It has only TAS for atomic 28 * operations. It does not seem a good idea to implement CMPXCHG, 29 * with TAS. So, we choose to implemnt these operations with 30 * posix mutexes. Please be sure that this might cause performance 31 * problem for Android-SH. Using LL/SC instructions supported in SH-X3, 32 * best performnace would be realized. 33 * 34 * (2) Mutex initialization problem happens, which is commented for 35 * ARM implementation, in this file above. 36 * We follow the fact that the initializer for mutex is a simple zero 37 * value. 38 * 39 * (3) These operations are NOT safe for SMP, as there is no currently 40 * no definition for a memory barrier operation. 41 */ 42 43 #include <pthread.h> 44 45 #define SWAP_LOCK_COUNT 32U 46 static pthread_mutex_t _swap_locks[SWAP_LOCK_COUNT]; 47 48 #define SWAP_LOCK(addr) \ 49 &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT] 50 51 52 int32_t android_atomic_acquire_load(volatile const int32_t* addr) 53 { 54 return *addr; 55 } 56 57 int32_t android_atomic_release_load(volatile const int32_t* addr) 58 { 59 return *addr; 60 } 61 62 void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) { 63 int32_t oldValue; 64 do { 65 oldValue = *addr; 66 } while (android_atomic_release_cas(oldValue, value, addr)); 67 } 68 69 void android_atomic_release_store(int32_t value, volatile int32_t* addr) { 70 int32_t oldValue; 71 do { 72 oldValue = *addr; 73 } while (android_atomic_release_cas(oldValue, value, addr)); 74 } 75 76 int32_t android_atomic_inc(volatile int32_t* addr) { 77 int32_t oldValue; 78 do { 79 oldValue = *addr; 80 } while (android_atomic_release_cas(oldValue, oldValue+1, addr)); 81 return oldValue; 82 } 83 84 int32_t android_atomic_dec(volatile int32_t* addr) { 85 int32_t oldValue; 86 do { 87 oldValue = *addr; 88 } while (android_atomic_release_cas(oldValue, oldValue-1, addr)); 89 return oldValue; 90 } 91 92 int32_t android_atomic_add(int32_t value, volatile int32_t* addr) { 93 int32_t oldValue; 94 do { 95 oldValue = *addr; 96 } while (android_atomic_release_cas(oldValue, oldValue+value, addr)); 97 return oldValue; 98 } 99 100 int32_t android_atomic_and(int32_t value, volatile int32_t* addr) { 101 int32_t oldValue; 102 do { 103 oldValue = *addr; 104 } while (android_atomic_release_cas(oldValue, oldValue&value, addr)); 105 return oldValue; 106 } 107 108 int32_t android_atomic_or(int32_t value, volatile int32_t* addr) { 109 int32_t oldValue; 110 do { 111 oldValue = *addr; 112 } while (android_atomic_release_cas(oldValue, oldValue|value, addr)); 113 return oldValue; 114 } 115 116 int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) { 117 return android_atomic_release_swap(value, addr); 118 } 119 120 int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) { 121 int32_t oldValue; 122 do { 123 oldValue = *addr; 124 } while (android_atomic_cmpxchg(oldValue, value, addr)); 125 return oldValue; 126 } 127 128 int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue, 129 volatile int32_t* addr) { 130 return android_atomic_release_cmpxchg(oldValue, newValue, addr); 131 } 132 133 int android_atomic_release_cmpxchg(int32_t oldvalue, int32_t newvalue, 134 volatile int32_t* addr) { 135 int result; 136 pthread_mutex_t* lock = SWAP_LOCK(addr); 137 138 pthread_mutex_lock(lock); 139 140 if (*addr == oldvalue) { 141 *addr = newvalue; 142 result = 0; 143 } else { 144 result = 1; 145 } 146 pthread_mutex_unlock(lock); 147 return result; 148 } 149 150