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
android_atomic_acquire_load(volatile const int32_t * addr)52 int32_t android_atomic_acquire_load(volatile const int32_t* addr)
53 {
54 return *addr;
55 }
56
android_atomic_release_load(volatile const int32_t * addr)57 int32_t android_atomic_release_load(volatile const int32_t* addr)
58 {
59 return *addr;
60 }
61
android_atomic_acquire_store(int32_t value,volatile int32_t * addr)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
android_atomic_release_store(int32_t value,volatile int32_t * addr)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
android_atomic_inc(volatile int32_t * addr)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
android_atomic_dec(volatile int32_t * addr)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
android_atomic_add(int32_t value,volatile int32_t * addr)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
android_atomic_and(int32_t value,volatile int32_t * addr)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
android_atomic_or(int32_t value,volatile int32_t * addr)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
android_atomic_acquire_swap(int32_t value,volatile int32_t * addr)116 int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
117 return android_atomic_release_swap(value, addr);
118 }
119
android_atomic_release_swap(int32_t value,volatile int32_t * addr)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
android_atomic_acquire_cmpxchg(int32_t oldvalue,int32_t newvalue,volatile int32_t * addr)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
android_atomic_release_cmpxchg(int32_t oldvalue,int32_t newvalue,volatile int32_t * addr)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