• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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