Init
This commit is contained in:
435
DependentExtensions/cat/threads/Atomic.hpp
Normal file
435
DependentExtensions/cat/threads/Atomic.hpp
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of LibCat nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschr<68>nkt)
|
||||
*
|
||||
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
||||
* license found in the license.txt file in the root directory of this source tree.
|
||||
* Alternatively you are permitted to license the modifications under the Modified BSD License.
|
||||
*/
|
||||
|
||||
#ifndef CAT_ATOMIC_HPP
|
||||
#define CAT_ATOMIC_HPP
|
||||
|
||||
#include <cat/Platform.hpp>
|
||||
|
||||
#if defined(CAT_OS_WINDOWS)
|
||||
# include <cat/port/WindowsInclude.hpp>
|
||||
#endif
|
||||
|
||||
namespace cat {
|
||||
|
||||
|
||||
namespace Atomic {
|
||||
|
||||
|
||||
// Compare-and-Swap 2x word size (CAS2)
|
||||
// On 32-bit architectures, the arguments point to 64-bit values, and must be aligned to 8 byte boundary
|
||||
// On 64-bit architectures, the arguments point to 128-bit values, and must be aligned to 16 byte boundary
|
||||
// Returns true if the old value was equal to the expected value
|
||||
CAT_INLINE bool CAS2(volatile void *x, const void *expected_old_value, const void *new_value);
|
||||
// Will define CAT_NO_ATOMIC_CAS2 if the platform/compiler does not support atomic CAS2
|
||||
|
||||
// Add y to x, returning the previous state of x
|
||||
CAT_INLINE u32 Add(volatile u32 *x, s32 y);
|
||||
// Will define CAT_NO_ATOMIC_ADD if the platform/compiler does not support atomic add
|
||||
|
||||
// Set x to new value, returning the previous state of x
|
||||
CAT_INLINE u32 Set(volatile u32 *x, u32 new_value);
|
||||
// Will define CAT_NO_ATOMIC_SET if the platform/compiler does not support atomic set
|
||||
|
||||
// Bit Test and Set (BTS)
|
||||
// Returns true if the bit was 1 and is still 1, otherwise false
|
||||
CAT_INLINE bool BTS(volatile u32 *x, int bit);
|
||||
// Will define CAT_NO_ATOMIC_BTS if the platform/compiler does not support atomic bts
|
||||
|
||||
// Bit Test and Reset (BTR)
|
||||
// Returns true if the bit was 1 and is now 0, otherwise false
|
||||
CAT_INLINE bool BTR(volatile u32 *x, int bit);
|
||||
// Will define CAT_NO_ATOMIC_BTR if the platform/compiler does not support atomic btr
|
||||
|
||||
|
||||
} // namespace Atomic
|
||||
|
||||
|
||||
//// Compare-and-Swap
|
||||
|
||||
#if defined(CAT_WORD_64)
|
||||
|
||||
|
||||
bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value)
|
||||
{
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#if defined(CAT_COMPILER_MSVC) && (_MSC_VER > 1400) // MSVC 2008+
|
||||
|
||||
__int64 ComparandResult[2] = { ((u64*)expected_old_value)[0],
|
||||
((u64*)expected_old_value)[1] };
|
||||
|
||||
// Requires MSVC 2008 or newer
|
||||
bool success = 1 == _InterlockedCompareExchange128((s64*)x, ((u64*)new_value)[1],
|
||||
((u64*)new_value)[0], ComparandResult);
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return success;
|
||||
|
||||
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
||||
|
||||
u128 *target = (u128*)x;
|
||||
u64 *replace = (u64*)new_value;
|
||||
u128 *expected = (u128*)expected_old_value;
|
||||
bool retval;
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
"lock; CMPXCHG16B %0\n\t"
|
||||
"sete %%al"
|
||||
: "=m" (*target), "=a" (retval)
|
||||
: "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected)
|
||||
: "memory", "cc"
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return retval;
|
||||
|
||||
#else
|
||||
|
||||
#define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support CAS2 */
|
||||
|
||||
(void) x; // avoid unused parameter warning
|
||||
(void) expected_old_value;
|
||||
(void) new_value;
|
||||
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#else // 32-bit version:
|
||||
|
||||
|
||||
bool Atomic::CAS2(volatile void *x, const void *expected_old_value, const void *new_value)
|
||||
{
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#if defined(CAT_COMPILER_MSVC)
|
||||
|
||||
s64 old_value = ((s64*)expected_old_value)[0];
|
||||
|
||||
bool success = (old_value == _InterlockedCompareExchange64((s64*)x, ((s64*)new_value)[0], old_value));
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return success;
|
||||
|
||||
#elif defined(CAT_ASM_INTEL) && defined(CAT_ISA_X86)
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
push ebx
|
||||
mov eax, new_value
|
||||
push esi
|
||||
mov ebx, dword ptr[eax]
|
||||
mov ecx, dword ptr[eax+4]
|
||||
mov edx, expected_old_value
|
||||
mov esi, x
|
||||
mov eax, dword ptr[edx]
|
||||
mov edx, dword ptr[edx+4]
|
||||
lock CMPXCHG8B qword ptr[esi]
|
||||
pop ebx
|
||||
mov eax, 0
|
||||
pop esi
|
||||
setz al
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
||||
|
||||
u64 *target = (u64*)x;
|
||||
u32 *replace = (u32*)new_value;
|
||||
u64 *expected = (u64*)expected_old_value;
|
||||
bool retval;
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
"lock; CMPXCHG8B %0\n\t"
|
||||
"sete %%al"
|
||||
: "=m" (*target), "=a" (retval)
|
||||
: "m" (*target), "b" (replace[0]), "c" (replace[1]), "A" (*expected)
|
||||
: "memory", "cc"
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return retval;
|
||||
|
||||
#else
|
||||
|
||||
#define CAT_NO_ATOMIC_CAS2 /* Platform/compiler does not support atomic CAS2 */
|
||||
|
||||
(void) x; // avoid unused parameter warning
|
||||
(void) expected_old_value;
|
||||
(void) new_value;
|
||||
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif // defined(CAT_WORD_64)
|
||||
|
||||
|
||||
//// Add y to x, returning the previous state of x
|
||||
|
||||
u32 Atomic::Add(volatile u32 *x, s32 y)
|
||||
{
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#if defined(CAT_COMPILER_MSVC) && defined(CAT_WORD_64)
|
||||
|
||||
u32 result = InterlockedAdd((volatile LONG*)x, y) - y;
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return result;
|
||||
|
||||
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
mov edx,x
|
||||
mov eax,y
|
||||
lock XADD [edx],eax
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
||||
|
||||
u32 retval;
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
"lock; XADDl %%eax, %0\n\t"
|
||||
: "=m" (*x), "=a" (retval)
|
||||
: "m" (*x), "a" (y)
|
||||
: "memory", "cc"
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return retval;
|
||||
|
||||
#else
|
||||
|
||||
#define CAT_NO_ATOMIC_ADD /* Platform/compiler does not support atomic add */
|
||||
|
||||
u32 old_x = *x;
|
||||
*x = old_x + y;
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return old_x;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//// Set x to new value, returning the previous state of x
|
||||
|
||||
u32 Atomic::Set(volatile u32 *x, u32 new_value)
|
||||
{
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#if defined(CAT_COMPILER_MSVC)
|
||||
|
||||
#if (_MSC_VER <= 1400) // MSVC 2005
|
||||
u32 result = _InterlockedExchange((long*)x, new_value);
|
||||
#else // MSVC 2008+
|
||||
u32 result = _InterlockedExchange((volatile LONG*)x, new_value);
|
||||
#endif
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return result;
|
||||
|
||||
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
mov edx,x
|
||||
mov eax,new_value
|
||||
lock XCHG [edx],eax
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
||||
|
||||
u32 retval;
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
"lock; XCHGl %%eax, %0\n\t"
|
||||
: "=m" (*x), "=a" (retval)
|
||||
: "m" (*x), "a" (new_value)
|
||||
: "memory", "cc"
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return retval;
|
||||
|
||||
#else
|
||||
|
||||
#define CAT_NO_ATOMIC_SET /* Platform/compiler does not support atomic set */
|
||||
|
||||
u32 old_x = *x;
|
||||
*x = new_value;
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return old_x;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//// Bit Test and Set (BTS)
|
||||
|
||||
bool Atomic::BTS(volatile u32 *x, int bit)
|
||||
{
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#if defined(CAT_COMPILER_MSVC)
|
||||
|
||||
#if (_MSC_VER <= 1400) // MSVC 2005
|
||||
bool success = !!_interlockedbittestandset((long*)x, bit);
|
||||
#else // MSVC 2008+
|
||||
bool success = !!_interlockedbittestandset((volatile LONG*)x, bit);
|
||||
#endif
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return success;
|
||||
|
||||
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
mov edx,x
|
||||
mov ecx,bit
|
||||
lock BTS [edx],ecx
|
||||
mov eax,0
|
||||
setc al
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
||||
|
||||
bool retval;
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
"lock; BTSl %2, %0\n\t"
|
||||
"setc %%al"
|
||||
: "=m" (*x), "=a" (retval)
|
||||
: "Ir" (bit)
|
||||
: "memory", "cc"
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return retval;
|
||||
|
||||
#else
|
||||
|
||||
#define CAT_NO_ATOMIC_BTS /* Platform/compiler does not support atomic bts */
|
||||
|
||||
u32 mask = 1 << bit;
|
||||
|
||||
u32 old_x = *x;
|
||||
*x = old_x | mask;
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return (old_x & mask) ? true : false;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//// Bit Test and Reset (BTR)
|
||||
|
||||
bool Atomic::BTR(volatile u32 *x, int bit)
|
||||
{
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#if defined(CAT_COMPILER_MSVC)
|
||||
|
||||
#if (_MSC_VER <= 1400) // MSVC 2005
|
||||
bool success = !!_interlockedbittestandreset((long*)x, bit);
|
||||
#else // MSVC 2008+
|
||||
bool success = !!_interlockedbittestandreset((volatile LONG*)x, bit);
|
||||
#endif
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return success;
|
||||
|
||||
#elif defined(CAT_ASM_INTEL) && defined(CAT_WORD_32) && defined(CAT_ISA_X86)
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
mov edx,x
|
||||
mov ecx,bit
|
||||
lock BTR [edx],ecx
|
||||
mov eax,0
|
||||
setc al
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
|
||||
#elif defined(CAT_ASM_ATT) && defined(CAT_ISA_X86)
|
||||
|
||||
bool retval;
|
||||
|
||||
CAT_ASM_BEGIN
|
||||
"lock; BTRl %2, %0\n\t"
|
||||
"setc %%al"
|
||||
: "=m" (*x), "=a" (retval)
|
||||
: "Ir" (bit)
|
||||
: "memory", "cc"
|
||||
CAT_ASM_END
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return retval;
|
||||
|
||||
#else
|
||||
|
||||
#define CAT_NO_ATOMIC_BTR /* Platform/compiler does not support atomic btr */
|
||||
|
||||
u32 mask = 1 << bit;
|
||||
|
||||
u32 old_x = *x;
|
||||
*x = old_x & ~mask;
|
||||
|
||||
CAT_FENCE_COMPILER
|
||||
return (old_x & mask) ? true : false;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace cat
|
||||
|
||||
#endif // CAT_ATOMIC_HPP
|
||||
Reference in New Issue
Block a user