Shadowrun: Awakened 29 September 2011 - Build 871
Atomic.hpp
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net