1 #ifndef _DEATOMIC_H 2 #define _DEATOMIC_H 3 /*------------------------------------------------------------------------- 4 * drawElements Thread Library 5 * --------------------------- 6 * 7 * Copyright 2014 The Android Open Source Project 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Atomic operations. 24 *//*--------------------------------------------------------------------*/ 25 26 #include "deDefs.h" 27 28 #if (DE_COMPILER == DE_COMPILER_MSC) 29 # include <intrin.h> 30 #endif 31 32 DE_BEGIN_EXTERN_C 33 34 /*--------------------------------------------------------------------*//*! 35 * \brief Atomic increment and fetch 32-bit signed integer. 36 * \param dstAddr Destination address. 37 * \return Incremented value. 38 *//*--------------------------------------------------------------------*/ 39 DE_INLINE deInt32 deAtomicIncrementInt32 (volatile deInt32* dstAddr) 40 { 41 #if (DE_COMPILER == DE_COMPILER_MSC) 42 return _InterlockedIncrement((long volatile*)dstAddr); 43 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 44 return __sync_add_and_fetch(dstAddr, 1); 45 #else 46 # error "Implement deAtomicIncrementInt32()" 47 #endif 48 } 49 50 /*--------------------------------------------------------------------*//*! 51 * \brief Atomic increment and fetch 32-bit unsigned integer. 52 * \param dstAddr Destination address. 53 * \return Incremented value. 54 *//*--------------------------------------------------------------------*/ 55 DE_INLINE deUint32 deAtomicIncrementUint32 (volatile deUint32* dstAddr) 56 { 57 return deAtomicIncrementInt32((deInt32 volatile*)dstAddr); 58 } 59 60 /*--------------------------------------------------------------------*//*! 61 * \brief Atomic decrement and fetch 32-bit signed integer. 62 * \param dstAddr Destination address. 63 * \return Decremented value. 64 *//*--------------------------------------------------------------------*/ 65 DE_INLINE deInt32 deAtomicDecrementInt32 (volatile deInt32* dstAddr) 66 { 67 #if (DE_COMPILER == DE_COMPILER_MSC) 68 return _InterlockedDecrement((volatile long*)dstAddr); 69 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 70 return __sync_sub_and_fetch(dstAddr, 1); 71 #else 72 # error "Implement deAtomicDecrementInt32()" 73 #endif 74 } 75 76 /*--------------------------------------------------------------------*//*! 77 * \brief Atomic decrement and fetch 32-bit unsigned integer. 78 * \param dstAddr Destination address. 79 * \return Decremented value. 80 *//*--------------------------------------------------------------------*/ 81 DE_INLINE deUint32 deAtomicDecrementUint32 (volatile deUint32* dstAddr) 82 { 83 return deAtomicDecrementInt32((volatile deInt32*)dstAddr); 84 } 85 86 /*--------------------------------------------------------------------*//*! 87 * \brief Atomic compare and exchange (CAS) 32-bit value. 88 * \param dstAddr Destination address. 89 * \param compare Old value. 90 * \param exchange New value. 91 * \return compare value if CAS passes, *dstAddr value otherwise 92 * 93 * Performs standard Compare-And-Swap with 32b data. Dst value is compared 94 * to compare value and if that comparison passes, value is replaced with 95 * exchange value. 96 * 97 * If CAS succeeds, compare value is returned. Otherwise value stored in 98 * dstAddr is returned. 99 *//*--------------------------------------------------------------------*/ 100 DE_INLINE deUint32 deAtomicCompareExchangeUint32 (volatile deUint32* dstAddr, deUint32 compare, deUint32 exchange) 101 { 102 #if (DE_COMPILER == DE_COMPILER_MSC) 103 return _InterlockedCompareExchange((volatile long*)dstAddr, exchange, compare); 104 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 105 return __sync_val_compare_and_swap(dstAddr, compare, exchange); 106 #else 107 # error "Implement deAtomicCompareExchange32()" 108 #endif 109 } 110 111 /* Deprecated names */ 112 #define deAtomicIncrement32 deAtomicIncrementInt32 113 #define deAtomicDecrement32 deAtomicDecrementInt32 114 #define deAtomicCompareExchange32 deAtomicCompareExchangeUint32 115 116 #if (DE_PTR_SIZE == 8) 117 118 /*--------------------------------------------------------------------*//*! 119 * \brief Atomic increment and fetch 64-bit signed integer. 120 * \param dstAddr Destination address. 121 * \return Incremented value. 122 *//*--------------------------------------------------------------------*/ 123 DE_INLINE deInt64 deAtomicIncrementInt64 (volatile deInt64* dstAddr) 124 { 125 #if (DE_COMPILER == DE_COMPILER_MSC) 126 return _InterlockedIncrement64((volatile long long*)dstAddr); 127 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 128 return __sync_add_and_fetch(dstAddr, 1); 129 #else 130 # error "Implement deAtomicIncrementInt64()" 131 #endif 132 } 133 134 /*--------------------------------------------------------------------*//*! 135 * \brief Atomic increment and fetch 64-bit unsigned integer. 136 * \param dstAddr Destination address. 137 * \return Incremented value. 138 *//*--------------------------------------------------------------------*/ 139 DE_INLINE deUint64 deAtomicIncrementUint64 (volatile deUint64* dstAddr) 140 { 141 return deAtomicIncrementInt64((volatile deInt64*)dstAddr); 142 } 143 144 /*--------------------------------------------------------------------*//*! 145 * \brief Atomic decrement and fetch. 146 * \param dstAddr Destination address. 147 * \return Decremented value. 148 *//*--------------------------------------------------------------------*/ 149 DE_INLINE deInt64 deAtomicDecrementInt64 (volatile deInt64* dstAddr) 150 { 151 #if (DE_COMPILER == DE_COMPILER_MSC) 152 return _InterlockedDecrement64((volatile long long*)dstAddr); 153 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 154 return __sync_sub_and_fetch(dstAddr, 1); 155 #else 156 # error "Implement deAtomicDecrementInt64()" 157 #endif 158 } 159 160 /*--------------------------------------------------------------------*//*! 161 * \brief Atomic increment and fetch 64-bit unsigned integer. 162 * \param dstAddr Destination address. 163 * \return Incremented value. 164 *//*--------------------------------------------------------------------*/ 165 DE_INLINE deUint64 deAtomicDecrementUint64 (volatile deUint64* dstAddr) 166 { 167 return deAtomicDecrementInt64((volatile deInt64*)dstAddr); 168 } 169 170 /*--------------------------------------------------------------------*//*! 171 * \brief Atomic compare and exchange (CAS) 64-bit value. 172 * \param dstAddr Destination address. 173 * \param compare Old value. 174 * \param exchange New value. 175 * \return compare value if CAS passes, *dstAddr value otherwise 176 * 177 * Performs standard Compare-And-Swap with 64b data. Dst value is compared 178 * to compare value and if that comparison passes, value is replaced with 179 * exchange value. 180 * 181 * If CAS succeeds, compare value is returned. Otherwise value stored in 182 * dstAddr is returned. 183 *//*--------------------------------------------------------------------*/ 184 DE_INLINE deUint64 deAtomicCompareExchangeUint64 (volatile deUint64* dstAddr, deUint64 compare, deUint64 exchange) 185 { 186 #if (DE_COMPILER == DE_COMPILER_MSC) 187 return _InterlockedCompareExchange64((volatile long long*)dstAddr, exchange, compare); 188 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 189 return __sync_val_compare_and_swap(dstAddr, compare, exchange); 190 #else 191 # error "Implement deAtomicCompareExchangeUint64()" 192 #endif 193 } 194 195 #endif /* (DE_PTR_SIZE == 8) */ 196 197 /*--------------------------------------------------------------------*//*! 198 * \brief Atomic increment and fetch size_t. 199 * \param dstAddr Destination address. 200 * \return Incremented value. 201 *//*--------------------------------------------------------------------*/ 202 DE_INLINE size_t deAtomicIncrementUSize (volatile size_t* size) 203 { 204 #if (DE_PTR_SIZE == 8) 205 return deAtomicIncrementUint64((volatile deUint64*)size); 206 #elif (DE_PTR_SIZE == 4) 207 return deAtomicIncrementUint32((volatile deUint32*)size); 208 #else 209 # error "Invalid DE_PTR_SIZE value" 210 #endif 211 } 212 213 /*--------------------------------------------------------------------*//*! 214 * \brief Atomic increment and fetch size_t. 215 * \param dstAddr Destination address. 216 * \return Incremented value. 217 *//*--------------------------------------------------------------------*/ 218 DE_INLINE size_t deAtomicDecrementUSize (volatile size_t* size) 219 { 220 #if (DE_PTR_SIZE == 8) 221 return deAtomicDecrementUint64((volatile deUint64*)size); 222 #elif (DE_PTR_SIZE == 4) 223 return deAtomicDecrementUint32((volatile deUint32*)size); 224 #else 225 # error "Invalid DE_PTR_SIZE value" 226 #endif 227 } 228 229 /*--------------------------------------------------------------------*//*! 230 * \brief Atomic compare and exchange (CAS) pointer. 231 * \param dstAddr Destination address. 232 * \param compare Old value. 233 * \param exchange New value. 234 * \return compare value if CAS passes, *dstAddr value otherwise 235 * 236 * Performs standard Compare-And-Swap with pointer value. Dst value is compared 237 * to compare value and if that comparison passes, value is replaced with 238 * exchange value. 239 * 240 * If CAS succeeds, compare value is returned. Otherwise value stored in 241 * dstAddr is returned. 242 *//*--------------------------------------------------------------------*/ 243 DE_INLINE void* deAtomicCompareExchangePtr (void* volatile* dstAddr, void* compare, void* exchange) 244 { 245 #if (DE_PTR_SIZE == 8) 246 return (void*)deAtomicCompareExchangeUint64((volatile deUint64*)dstAddr, (deUint64)compare, (deUint64)exchange); 247 #elif (DE_PTR_SIZE == 4) 248 return (void*)deAtomicCompareExchangeUint32((volatile deUint32*)dstAddr, (deUint32)compare, (deUint32)exchange); 249 #else 250 # error "Invalid DE_PTR_SIZE value" 251 #endif 252 } 253 254 /*--------------------------------------------------------------------*//*! 255 * \brief Issue hardware memory read-write fence. 256 *//*--------------------------------------------------------------------*/ 257 #if (DE_COMPILER == DE_COMPILER_MSC) 258 void deMemoryReadWriteFence (void); 259 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 260 DE_INLINE void deMemoryReadWriteFence (void) 261 { 262 __sync_synchronize(); 263 } 264 #else 265 # error "Implement deMemoryReadWriteFence()" 266 #endif 267 268 DE_END_EXTERN_C 269 270 #endif /* _DEATOMIC_H */ 271