![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved. 00003 00004 Redistribution and use in source and binary forms, with or without 00005 modification, are permitted provided that the following conditions are met: 00006 00007 * Redistributions of source code must retain the above copyright notice, 00008 this list of conditions and the following disclaimer. 00009 * Redistributions in binary form must reproduce the above copyright notice, 00010 this list of conditions and the following disclaimer in the documentation 00011 and/or other materials provided with the distribution. 00012 * Neither the name of LibCat nor the names of its contributors may be used 00013 to endorse or promote products derived from this software without 00014 specific prior written permission. 00015 00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00019 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00020 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00021 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00022 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00023 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00024 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00025 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00026 POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00029 #ifndef CAT_ATOMIC_HPP 00030 #define CAT_ATOMIC_HPP 00031 00032 #include <cat/Platform.hpp> 00033 00034 #if defined(CAT_OS_WINDOWS) 00035 # include <cat/port/WindowsInclude.hpp> 00036 #endif 00037 00038 namespace cat { 00039 00040 00041 namespace Atomic { 00042 00043 00044 // Compare-and-Swap 2x word size (CAS2) 00045 // On 32-bit architectures, the arguments point to 64-bit values, and must be aligned to 8 byte boundary 00046 // On 64-bit architectures, the arguments point to 128-bit values, and must be aligned to 16 byte boundary 00047 // Returns true if the old value was equal to the expected value 00048 CAT_INLINE bool CAS2(volatile void *x, const void *expected_old_value, const void *new_value); 00049 // Will define CAT_NO_ATOMIC_CAS2 if the platform/compiler does not support atomic CAS2 00050 00051 // Add y to x, returning the previous state of x 00052 CAT_INLINE u32 Add(volatile u32 *x, s32 y); 00053 // Will define CAT_NO_ATOMIC_ADD if the platform/compiler does not support atomic add 00054 00055 // Set x to new value, returning the previous state of x 00056 CAT_INLINE u32 Set(volatile u32 *x, u32 new_value); 00057 // Will define CAT_NO_ATOMIC_SET if the platform/compiler does not support atomic set 00058 00059 // Bit Test and Set (BTS) 00060 // Returns true if the bit was 1 and is still 1, otherwise false 00061 CAT_INLINE bool BTS(volatile u32 *x, int bit); 00062 // Will define CAT_NO_ATOMIC_BTS if the platform/compiler does not support atomic bts 00063 00064 // Bit Test and Reset (BTR) 00065 // Returns true if the bit was 1 and is now 0, otherwise false 00066 CAT_INLINE bool BTR(volatile u32 *x, int bit); 00067 // Will define CAT_NO_ATOMIC_BTR if the platform/compiler does not support atomic btr 00068 00069 00070 } // namespace Atomic 00071 00072 00074 00075 #if defined(CAT_WORD_64) 00076 00077 00078 bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value) 00079 { 00080 CAT_FENCE_COMPILER 00081 00082 #if defined(CAT_COMPILER_MSVC) && (_MSC_VER > 1400) // MSVC 2008+ 00083 00084 __int64 ComparandResult[2] = { ((u64*)expected_old_value)[0], 00085 ((u64*)expected_old_value)[1] }; 00086 00087 // Requires MSVC 2008 or newer 00088 bool success = 1 == _InterlockedCompareExchange128((s64*)x, ((u64*)new_value)[1], 00089 ((u64*)new_value)[0], ComparandResult); 00090 00091 CAT_FENCE_COMPILER 00092 return success; 00093 00094 #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86) 00095 00096 u128 *target = (u128*)x; 00097 u64 *replace = (u64*)new_value; 00098 u128 *expected = (u128*)expected_old_value; 00099 bool retval; 00100 00101 CAT_ASM_BEGIN 00102 "lock; CMPXCHG16B %0\n\t" 00103 "sete %%al" 00104 : "=m" (*target), "=a" (retval) 00105 : "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected) 00106 : "memory", "cc" 00107 CAT_ASM_END 00108 00109 CAT_FENCE_COMPILER 00110 return retval; 00111 00112 #else 00113 00114 #define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support CAS2 */ 00115 00116 (void) x; // avoid unused parameter warning 00117 (void) expected_old_value; 00118 (void) new_value; 00119 00120 return true; 00121 00122 #endif 00123 } 00124 00125 00126 #else // 32-bit version: 00127 00128 00129 bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value) 00130 { 00131 CAT_FENCE_COMPILER 00132 00133 #if defined(CAT_COMPILER_MSVC) 00134 00135 s64 old_value = ((s64*)expected_old_value)[0]; 00136 00137 bool success = (old_value == _InterlockedCompareExchange64((s64*)x, ((s64*)new_value)[0], old_value)); 00138 00139 CAT_FENCE_COMPILER 00140 return success; 00141 00142 #elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86) 00143 00144 CAT_ASM_BEGIN 00145 push ebx 00146 mov eax, new_value 00147 push esi 00148 mov ebx, dword ptr[eax] 00149 mov ecx, dword ptr[eax+4] 00150 mov edx, expected_old_value 00151 mov esi, x 00152 mov eax, dword ptr[edx] 00153 mov edx, dword ptr[edx+4] 00154 lock CMPXCHG8B qword ptr[esi] 00155 pop ebx 00156 mov eax, 0 00157 pop esi 00158 setz al 00159 CAT_ASM_END 00160 00161 CAT_FENCE_COMPILER 00162 00163 #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86) 00164 00165 u64 *target = (u64*)x; 00166 u32 *replace = (u32*)new_value; 00167 u64 *expected = (u64*)expected_old_value; 00168 bool retval; 00169 00170 CAT_ASM_BEGIN 00171 "lock; CMPXCHG8B %0\n\t" 00172 "sete %%al" 00173 : "=m" (*target), "=a" (retval) 00174 : "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected) 00175 : "memory", "cc" 00176 CAT_ASM_END 00177 00178 CAT_FENCE_COMPILER 00179 return retval; 00180 00181 #else 00182 00183 #define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support atomic CAS2 */ 00184 00185 (void) x; // avoid unused parameter warning 00186 (void) expected_old_value; 00187 (void) new_value; 00188 00189 return true; 00190 00191 #endif 00192 } 00193 00194 00195 #endif // defined(CAT_WORD_64) 00196 00197 00199 00200 u32 Atomic::Add(volatile u32 *x, s32 y) 00201 { 00202 CAT_FENCE_COMPILER 00203 00204 #if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64) 00205 00206 u32 result = _InterlockedAdd((volatile LONG*)x, y) - y; 00207 00208 CAT_FENCE_COMPILER 00209 return result; 00210 00211 #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86) 00212 00213 CAT_ASM_BEGIN 00214 mov edx,x 00215 mov eax,y 00216 lock XADD [edx],eax 00217 CAT_ASM_END 00218 00219 CAT_FENCE_COMPILER 00220 00221 #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86) 00222 00223 u32 retval; 00224 00225 CAT_ASM_BEGIN 00226 "lock; XADDl %%eax, %0\n\t" 00227 : "=m" (*x), "=a" (retval) 00228 : "m" (*x), "a" (y) 00229 : "memory", "cc" 00230 CAT_ASM_END 00231 00232 CAT_FENCE_COMPILER 00233 return retval; 00234 00235 #else 00236 00237 #define CAT_NO_ATOMIC_ADD /* Platform/compiler does not support atomic add */ 00238 00239 u32 old_x = *x; 00240 *x = old_x + y; 00241 00242 CAT_FENCE_COMPILER 00243 return old_x; 00244 00245 #endif 00246 } 00247 00248 00250 00251 u32 Atomic::Set(volatile u32 *x, u32 new_value) 00252 { 00253 CAT_FENCE_COMPILER 00254 00255 #if defined(CAT_COMPILER_MSVC) 00256 00257 #if (_MSC_VER <= 1400) // MSVC 2005 00258 u32 result = _InterlockedExchange((long*)x, new_value); 00259 #else // MSVC 2008+ 00260 u32 result = _InterlockedExchange((volatile LONG*)x, new_value); 00261 #endif 00262 00263 CAT_FENCE_COMPILER 00264 return result; 00265 00266 #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86) 00267 00268 CAT_ASM_BEGIN 00269 mov edx,x 00270 mov eax,new_value 00271 lock XCHG [edx],eax 00272 CAT_ASM_END 00273 00274 CAT_FENCE_COMPILER 00275 00276 #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86) 00277 00278 u32 retval; 00279 00280 CAT_ASM_BEGIN 00281 "lock; XCHGl %%eax, %0\n\t" 00282 : "=m" (*x), "=a" (retval) 00283 : "m" (*x), "a" (new_value) 00284 : "memory", "cc" 00285 CAT_ASM_END 00286 00287 CAT_FENCE_COMPILER 00288 return retval; 00289 00290 #else 00291 00292 #define CAT_NO_ATOMIC_SET /* Platform/compiler does not support atomic set */ 00293 00294 u32 old_x = *x; 00295 *x = new_value; 00296 00297 CAT_FENCE_COMPILER 00298 return old_x; 00299 00300 #endif 00301 } 00302 00303 00305 00306 bool Atomic::BTS(volatile u32 *x, int bit) 00307 { 00308 CAT_FENCE_COMPILER 00309 00310 #if defined(CAT_COMPILER_MSVC) 00311 00312 #if (_MSC_VER <= 1400) // MSVC 2005 00313 bool success = !!_interlockedbittestandset((long*)x, bit); 00314 #else // MSVC 2008+ 00315 bool success = !!_interlockedbittestandset((volatile LONG*)x, bit); 00316 #endif 00317 00318 CAT_FENCE_COMPILER 00319 return success; 00320 00321 #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86) 00322 00323 CAT_ASM_BEGIN 00324 mov edx,x 00325 mov ecx,bit 00326 lock BTS [edx],ecx 00327 mov eax,0 00328 setc al 00329 CAT_ASM_END 00330 00331 CAT_FENCE_COMPILER 00332 00333 #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86) 00334 00335 bool retval; 00336 00337 CAT_ASM_BEGIN 00338 "lock; BTSl %2, %0\n\t" 00339 "setc %%al" 00340 : "=m" (*x), "=a" (retval) 00341 : "Ir" (bit) 00342 : "memory", "cc" 00343 CAT_ASM_END 00344 00345 CAT_FENCE_COMPILER 00346 return retval; 00347 00348 #else 00349 00350 #define CAT_NO_ATOMIC_BTS /* Platform/compiler does not support atomic bts */ 00351 00352 u32 mask = 1 << bit; 00353 00354 u32 old_x = *x; 00355 *x = old_x | mask; 00356 00357 CAT_FENCE_COMPILER 00358 return (old_x & mask) ? true : false; 00359 00360 #endif 00361 } 00362 00363 00365 00366 bool Atomic::BTR(volatile u32 *x, int bit) 00367 { 00368 CAT_FENCE_COMPILER 00369 00370 #if defined(CAT_COMPILER_MSVC) 00371 00372 #if (_MSC_VER <= 1400) // MSVC 2005 00373 bool success = !!_interlockedbittestandreset((long*)x, bit); 00374 #else // MSVC 2008+ 00375 bool success = !!_interlockedbittestandreset((volatile LONG*)x, bit); 00376 #endif 00377 00378 CAT_FENCE_COMPILER 00379 return success; 00380 00381 #elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86) 00382 00383 CAT_ASM_BEGIN 00384 mov edx,x 00385 mov ecx,bit 00386 lock BTR [edx],ecx 00387 mov eax,0 00388 setc al 00389 CAT_ASM_END 00390 00391 CAT_FENCE_COMPILER 00392 00393 #elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86) 00394 00395 bool retval; 00396 00397 CAT_ASM_BEGIN 00398 "lock; BTRl %2, %0\n\t" 00399 "setc %%al" 00400 : "=m" (*x), "=a" (retval) 00401 : "Ir" (bit) 00402 : "memory", "cc" 00403 CAT_ASM_END 00404 00405 CAT_FENCE_COMPILER 00406 return retval; 00407 00408 #else 00409 00410 #define CAT_NO_ATOMIC_BTR /* Platform/compiler does not support atomic btr */ 00411 00412 u32 mask = 1 << bit; 00413 00414 u32 old_x = *x; 00415 *x = old_x & ~mask; 00416 00417 CAT_FENCE_COMPILER 00418 return (old_x & mask) ? true : false; 00419 00420 #endif 00421 } 00422 00423 00424 00425 } // namespace cat 00426 00427 #endif // CAT_ATOMIC_HPP
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.