This commit is contained in:
jeanlemotan
2024-07-02 18:10:39 +02:00
commit 48ab06b1d9
733 changed files with 321088 additions and 0 deletions
@@ -0,0 +1,29 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EATHREAD_INTERNAL_ATOMIC_H
#define EATHREAD_INTERNAL_ATOMIC_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
namespace EA
{
namespace Thread
{
typedef int64_t(*AtomicAdd64Function)(volatile int64_t *ptr, int64_t value);
typedef int64_t(*AtomicGetValue64Function)(volatile int64_t *ptr);
typedef int64_t(*AtomicSetValue64Function)(volatile int64_t *ptr, int64_t value);
typedef bool(*AtomicSetValueConditional64Function)(volatile int64_t *ptr, int64_t value, int64_t condition);
extern AtomicAdd64Function AtomicAdd64;
extern AtomicGetValue64Function AtomicGetValue64;
extern AtomicSetValue64Function AtomicSetValue64;
extern AtomicSetValueConditional64Function AtomicSetValueConditional64;
}
}
#endif
@@ -0,0 +1,638 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EATHREAD_INTERNAL_CONFIG_H
#define EATHREAD_INTERNAL_CONFIG_H
#include <EABase/eabase.h>
EA_DISABLE_VC_WARNING(4574)
#include <stddef.h>
EA_RESTORE_VC_WARNING()
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_VERSION
//
// We more or less follow the conventional EA packaging approach to versioning
// here. A primary distinction here is that minor versions are defined as two
// digit entities (e.g. .03") instead of minimal digit entities ".3"). The logic
// here is that the value is a counter and not a floating point fraction.
// Note that the major version doesn't have leading zeros.
//
// Example version strings:
// "0.91.00" // Major version 0, minor version 91, patch version 0.
// "1.00.00" // Major version 1, minor and patch version 0.
// "3.10.02" // Major version 3, minor version 10, patch version 02.
// "12.03.01" // Major version 12, minor version 03, patch version
//
// Example usage:
// printf("EATHREAD_VERSION version: %s", EATHREAD_VERSION);
// printf("EATHREAD_VERSION version: %d.%d.%d", EATHREAD_VERSION_N / 10000 % 100, EATHREAD_VERSION_N / 100 % 100, EATHREAD_VERSION_N % 100);
//
#ifndef EATHREAD_VERSION
#define EATHREAD_VERSION "1.32.09"
#define EATHREAD_VERSION_N 13209
// Older style version info
#define EATHREAD_VERSION_MAJOR (EATHREAD_VERSION_N / 100 / 100 % 100)
#define EATHREAD_VERSION_MINOR (EATHREAD_VERSION_N / 100 % 100)
#define EATHREAD_VERSION_PATCH (EATHREAD_VERSION_N % 100)
#endif
///////////////////////////////////////////////////////////////////////////////
// _GNU_SOURCE
//
// Defined or not defined.
// If this is defined then GlibC extension functionality is enabled during
// calls to glibc header files.
//
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_TLS_COUNT
//
// Defined as compile-time constant integer > 0.
//
#if !defined(EATHREAD_TLS_COUNT)
#define EATHREAD_TLS_COUNT 16
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_THREADS_AVAILABLE
//
// Defined as 0 or 1
// Defines if threading is supported on the given platform.
// If 0 then the EAThread implementation is not capable of creating threads,
// but other facilities (e.g. mutex) work in a non-thread-aware way.
//
#ifndef EA_THREADS_AVAILABLE
#define EA_THREADS_AVAILABLE 1
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_USE_CPP11_CONCURRENCY
//
// Defined as 0 or 1
//
#ifndef EA_USE_CPP11_CONCURRENCY
#if defined(EA_PLATFORM_WINDOWS) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
#define EA_USE_CPP11_CONCURRENCY 1
#else
#define EA_USE_CPP11_CONCURRENCY 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_USE_COMMON_ATOMICINT_IMPLEMENTATION
//
// Use the common EAThread AtomicInt implementation on all platforms.
//
// Defined as 0 or 1
//
#ifndef EA_USE_COMMON_ATOMICINT_IMPLEMENTATION
#define EA_USE_COMMON_ATOMICINT_IMPLEMENTATION 1
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_POSIX_THREADS_AVAILABLE
//
// Defined as 0 or 1
//
#ifndef EA_POSIX_THREADS_AVAILABLE
#if defined(__unix__) || defined(__linux__) || defined(__APPLE__)
#define EA_POSIX_THREADS_AVAILABLE 1
#elif defined(EA_PLATFORM_SONY)
#define EA_POSIX_THREADS_AVAILABLE 0 // POSIX threading API is present but use is discouraged by Sony. They want shipping code to use their scePthreads* API.
#else
#define EA_POSIX_THREADS_AVAILABLE 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EAT_ASSERT_ENABLED
//
// Defined as 0 or 1, default is 1 if EA_DEBUG or _DEBUG is defined.
// If defined as 1, then assertion failures are reported via EA::Thread::AssertionFailure().
//
#ifndef EAT_ASSERT_ENABLED
#if defined(EA_DEBUG) || defined(_DEBUG)
#define EAT_ASSERT_ENABLED 1
#else
#define EAT_ASSERT_ENABLED 0
#endif
#endif
#if EAT_ASSERT_ENABLED
#define EAT_ASSERT(expression) \
EA_DISABLE_VC_WARNING(4127) \
do { \
EA_ANALYSIS_ASSUME(expression); \
if (!(expression) ) \
EA::Thread::AssertionFailure(__FILE__ "(" EA_STRINGIFY(__LINE__) "): " #expression); \
} while(0) \
EA_RESTORE_VC_WARNING()
#else
#define EAT_ASSERT(expression)
#endif
#if EAT_ASSERT_ENABLED
#define EAT_ASSERT_MSG(expression, msg) \
EA_DISABLE_VC_WARNING(4127) \
do { \
EA_ANALYSIS_ASSUME(expression); \
if (!(expression) ) \
EA::Thread::AssertionFailure(msg); \
} while(0) \
EA_RESTORE_VC_WARNING()
#else
#define EAT_ASSERT_MSG(expression, msg)
#endif
#if EAT_ASSERT_ENABLED
#define EAT_ASSERT_FORMATTED(expression, pFormat, ...) \
EA_DISABLE_VC_WARNING(4127) \
do { \
EA_ANALYSIS_ASSUME(expression); \
if (!(expression) ) \
EA::Thread::AssertionFailureV(pFormat, __VA_ARGS__); \
} while(0) \
EA_RESTORE_VC_WARNING()
#else
#define EAT_ASSERT_FORMATTED(expression, pFormat, ...)
#endif
#if EAT_ASSERT_ENABLED
#define EAT_FAIL_MSG(msg) (EA::Thread::AssertionFailure(msg))
#else
#define EAT_FAIL_MSG(msg)
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// EAT_COMPILETIME_ASSERT
//
// Compile-time assertion for this module.
// C-like declaration:
// void EAT_COMPILETIME_ASSERT(bool bExpression);
//
#if !defined(EAT_COMPILETIME_ASSERT)
#define EAT_COMPILETIME_ASSERT(expression) static_assert(expression, EA_STRINGIFY(expression))
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_TLSALLOC_DTOR_ENABLED
//
// Defined as 0 or 1. Default is 1.
// Defines if the TLSAlloc class destructor frees the TLS thread handle.
// This won't make a difference unless you were using EAThread in a DLL and
// you were repeatedly loading and unloading DLLs.
// See eathread_pc.cpp for usage of this and more info about the situation.
//
#ifndef EATHREAD_TLSALLOC_DTOR_ENABLED
#define EATHREAD_TLSALLOC_DTOR_ENABLED 1
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_LIKELY / EATHREAD_UNLIKELY
//
// Defined as a macro which gives a hint to the compiler for branch
// prediction. GCC gives you the ability to manually give a hint to
// the compiler about the result of a comparison, though it's often
// best to compile shipping code with profiling feedback under both
// GCC (-fprofile-arcs) and VC++ (/LTCG:PGO, etc.). However, there
// are times when you feel very sure that a boolean expression will
// usually evaluate to either true or false and can help the compiler
// by using an explicity directive...
//
// Example usage:
// if(EATHREAD_LIKELY(a == 0)) // Tell the compiler that a will usually equal 0.
// { ... }
//
// Example usage:
// if(EATHREAD_UNLIKELY(a == 0)) // Tell the compiler that a will usually not equal 0.
// { ... }
//
#ifndef EATHREAD_LIKELY
#define EATHREAD_LIKELY(x) EA_LIKELY(x)
#define EATHREAD_UNLIKELY(x) EA_UNLIKELY(x)
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_NAMING
//
// Defined as 0, 1 (enabled), or 2 (enabled only when debugger is present).
//
#define EATHREAD_NAMING_DISABLED 0
#define EATHREAD_NAMING_ENABLED 1
#define EATHREAD_NAMING_OPTIONAL 2
#ifndef EATHREAD_NAMING
#if defined(EA_SHIP) || defined(EA_FINAL) // These are two de-facto standard EA defines for identifying a shipping build.
#define EATHREAD_NAMING 0
#else
#define EATHREAD_NAMING EATHREAD_NAMING_ENABLED // or EATHREAD_NAMING_OPTIONAL?
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_NAME_SIZE
//
// Specifies the max size to support for naming threads.
// This value can be changed as desired.
//
#ifndef EATHREAD_NAME_SIZE
#if defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_UNIX)
#define EATHREAD_NAME_SIZE 64
#else
#define EATHREAD_NAME_SIZE 32
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EA_XBDM_ENABLED
//
// Defined as 0 or 1, with 1 being the default for debug builds.
// This controls whether xbdm library usage is enabled on XBox 360. This library
// allows for runtime debug functionality. But shipping applications are not
// allowed to use xbdm.
//
#if !defined(EA_XBDM_ENABLED)
#if defined(EA_DEBUG)
#define EA_XBDM_ENABLED 1
#else
#define EA_XBDM_ENABLED 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_DLL
//
// Defined as 0 or 1. The default is dependent on the definition of EA_DLL.
// If EA_DLL is defined, then EATHREAD_DLL is 1, else EATHREAD_DLL is 0.
// EA_DLL is a define that controls DLL builds within the EAConfig build system.
// EATHREAD_DLL controls whether EATHREAD_VERSION is built and used as a DLL.
// Normally you wouldn't do such a thing, but there are use cases for such
// a thing, particularly in the case of embedding C++ into C# applications.
//
#ifndef EATHREAD_DLL
#if defined(EA_DLL)
#define EATHREAD_DLL 1
#else
#define EATHREAD_DLL 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREADLIB_API
//
// This is used to label functions as DLL exports under Microsoft platforms.
// If EA_DLL is defined, then the user is building EAThread as a DLL and EAThread's
// non-templated functions will be exported. EAThread template functions are not
// labelled as EATHREADLIB_API (and are thus not exported in a DLL build). This is
// because it's not possible (or at least unsafe) to implement inline templated
// functions in a DLL.
//
// Example usage of EATHREADLIB_API:
// EATHREADLIB_API int someVariable = 10; // Export someVariable in a DLL build.
//
// struct EATHREADLIB_API SomeClass{ // Export SomeClass and its member functions in a DLL build.
// EATHREADLIB_LOCAL void PrivateMethod(); // Not exported.
// };
//
// EATHREADLIB_API void SomeFunction(); // Export SomeFunction in a DLL build.
//
// For GCC, see http://gcc.gnu.org/wiki/Visibility
//
#ifndef EATHREADLIB_API // If the build file hasn't already defined this to be dllexport...
#if EATHREAD_DLL
#if defined(_MSC_VER)
#define EATHREADLIB_API __declspec(dllimport)
#define EATHREADLIB_LOCAL
#elif defined(__CYGWIN__)
#define EATHREADLIB_API __attribute__((dllimport))
#define EATHREADLIB_LOCAL
#elif (defined(__GNUC__) && (__GNUC__ >= 4))
#define EATHREADLIB_API __attribute__ ((visibility("default")))
#define EATHREADLIB_LOCAL __attribute__ ((visibility("hidden")))
#else
#define EATHREADLIB_API
#define EATHREADLIB_LOCAL
#endif
#else
#define EATHREADLIB_API
#define EATHREADLIB_LOCAL
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_ALLOC_PREFIX
//
// Defined as a string literal. Defaults to this package's name.
// Can be overridden by the user by predefining it or by editing this file.
// This define is used as the default name used by this package for naming
// memory allocations and memory allocators.
//
// All allocations names follow the same naming pattern:
// <package>/<module>[/<specific usage>]
//
// Example usage:
// void* p = pCoreAllocator->Alloc(37, EATHREAD_ALLOC_PREFIX, 0);
//
// Example usage:
// gMessageServer.GetMessageQueue().get_allocator().set_name(EATHREAD_ALLOC_PREFIX "MessageSystem/Queue");
//
#ifndef EATHREAD_ALLOC_PREFIX
#define EATHREAD_ALLOC_PREFIX "EAThread/"
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_USE_STANDARD_NEW
//
// Defines whether we use the basic standard operator new or the named
// extended version of operator new, as per the EASTL package.
//
#ifndef EATHREAD_USE_STANDARD_NEW
#if EATHREAD_DLL // A DLL must provide its own implementation of new, so we just use built-in new.
#define EATHREAD_USE_STANDARD_NEW 1
#else
#define EATHREAD_USE_STANDARD_NEW 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_NEW
//
// This is merely a wrapper for operator new which can be overridden and
// which has debug/release forms.
//
// Example usage:
// SomeClass* pObject = EATHREAD_NEW("SomeClass") SomeClass(1, 2, 3);
//
#ifndef EATHREAD_NEW
#if EATHREAD_USE_STANDARD_NEW
#define EATHREAD_NEW(name) new
#define EATHREAD_NEW_ALIGNED(alignment, offset, name) new
#define EATHREAD_DELETE delete
#else
#if defined(EA_DEBUG)
#define EATHREAD_NEW(name) new(name, 0, 0, __FILE__, __LINE__)
#define EATHREAD_NEW_ALIGNED(alignment, offset, name) new(alignment, offset, name, 0, 0, __FILE__, __LINE__)
#define EATHREAD_DELETE delete
#else
#define EATHREAD_NEW(name) new(name, 0, 0, 0, 0)
#define EATHREAD_NEW_ALIGNED(alignment, offset, name) new(alignment, offset, name, 0, 0, 0, 0)
#define EATHREAD_DELETE delete
#endif
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_HAS_EMULATED_AND_NATIVE_ATOMICS
//
// This symbol is defined if a platform has both native and emulated atomics.
// Currently the only platform that requires this is iOS as earlier versions
// of the operating system (ie: iOS 3) do not provide OS support for 64-bit
// atomics while later versions (ie: iOS 4/5) do.
#ifndef EATHREAD_HAS_EMULATED_AND_NATIVE_ATOMICS
#if defined(__APPLE__)
#define EATHREAD_HAS_EMULATED_AND_NATIVE_ATOMICS 1
#else
#define EATHREAD_HAS_EMULATED_AND_NATIVE_ATOMICS 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_GLIBC_BACKTRACE_AVAILABLE
//
// You generally need to be using GCC, GLIBC, and Linux for backtrace to be available.
// And even then it's available only some of the time.
//
#if !defined(EATHREAD_GLIBC_BACKTRACE_AVAILABLE)
#if (defined(__clang__) || defined(__GNUC__)) && (defined(EA_PLATFORM_LINUX) || defined(__APPLE__)) && !defined(__CYGWIN__) && !defined(EA_PLATFORM_ANDROID)
#define EATHREAD_GLIBC_BACKTRACE_AVAILABLE 1
#else
#define EATHREAD_GLIBC_BACKTRACE_AVAILABLE 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_GLIBC_VERSION
//
// We provide our own GLIBC numeric version to determine when system library
// calls are available.
//
#if defined(__GLIBC__)
#define EATHREAD_GLIBC_VERSION ((__GLIBC__ * 1000) + __GLIBC_MINOR__)
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_GETCALLSTACK_SUPPORTED
//
// Defined as 0 or 1.
// Identifies whether runtime callstack unwinding (i.e. GetCallstack()) is
// supported for the given platform. In some cases it may be that unwinding
// support code is present but it hasn't been tested for reliability and may
// have bugs preventing it from working properly. In some cases (e.g. x86)
// it may be that optimized builds make it difficult to read the callstack
// reliably, despite that we flag the platform as supported.
//
#if !defined(EATHREAD_GETCALLSTACK_SUPPORTED)
#if EATHREAD_GLIBC_BACKTRACE_AVAILABLE // Typically this means Linux on x86.
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_IPHONE)
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_ANDROID)
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_IPHONE_SIMULATOR)
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_WINDOWS_PHONE) && defined(EA_PROCESSOR_ARM)
#define EATHREAD_GETCALLSTACK_SUPPORTED 0
#elif defined(EA_PLATFORM_MICROSOFT)
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_LINUX)
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_OSX)
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_SONY)
#define EATHREAD_GETCALLSTACK_SUPPORTED 1
#elif defined(EA_PLATFORM_CYGWIN) // Support hasn't been verified.
#define EATHREAD_GETCALLSTACK_SUPPORTED 0
#elif defined(EA_PLATFORM_MINGW) // Support hasn't been verified.
#define EATHREAD_GETCALLSTACK_SUPPORTED 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_DEBUG_DETAIL_ENABLED
//
// Defined as 0 or 1.
// If true then detailed debug info is displayed. Can be enabled in opt builds.
//
#ifndef EATHREAD_DEBUG_DETAIL_ENABLED
#define EATHREAD_DEBUG_DETAIL_ENABLED 0
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_MIN_ABSOLUTE_TIME
//
// Defined as a time in milliseconds.
// Locks and waits allow the user to specify an absolute timeout time. In order
// to detect that the user accidentally specified a relative time, we define a
// minimum allowed absolute time which we assert on. This minimum time is one
// that in practice is impossible to be a future absolute time.
//
#ifndef EATHREAD_MIN_ABSOLUTE_TIME
#define EATHREAD_MIN_ABSOLUTE_TIME 10000
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED
//
// Defined as 0 or 1.
// If true then the platform supports a user specified thread affinity mask.
//
#ifndef EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED
#if defined(EA_PLATFORM_XBOXONE)
#define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 1
#elif defined(EA_PLATFORM_SONY)
#define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 1
#elif defined(EA_USE_CPP11_CONCURRENCY) && EA_USE_CPP11_CONCURRENCY
// CPP11 doesn't not provided a mechanism to set thread affinities.
#define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 0
#elif defined(EA_PLATFORM_ANDROID) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_UNIX)
#define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 0
#else
#define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 1
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_GLOBAL_VARIABLE_DLL_SAFETY
//
// Defined as 0 or 1.
//
//
#ifndef EATHREAD_GLOBAL_VARIABLE_DLL_SAFETY
#define EATHREAD_GLOBAL_VARIABLE_DLL_SAFETY 0
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_SCEDBG_ENABLED
//
// Defined as 0 or 1.
// Informs EAThread if Sony Debug libraries are available for us.
//
#ifndef EATHREAD_SCEDBG_ENABLED
#ifndef EA_SCEDBG_ENABLED
#define EATHREAD_SCEDBG_ENABLED 0
#else
#define EATHREAD_SCEDBG_ENABLED EA_SCEDBG_ENABLED
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_DEBUG_BREAK
//
#ifndef EATHREAD_DEBUG_BREAK
#ifdef __MSC_VER
#define EATHREAD_DEBUG_BREAK() __debugbreak()
#else
#define EATHREAD_DEBUG_BREAK() *(volatile int*)(0) = 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_C11_ATOMICS_AVAILABLE
//
#ifndef EATHREAD_C11_ATOMICS_AVAILABLE
#if (defined(EA_ANDROID_SDK_LEVEL) && (EA_ANDROID_SDK_LEVEL >= 21))
#define EATHREAD_C11_ATOMICS_AVAILABLE 1
#else
#define EATHREAD_C11_ATOMICS_AVAILABLE 0
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_ALIGNMENT_CHECK
//
namespace EA {
namespace Thread {
namespace detail {
// Used to assert that memory accesses on x86-64 are atomic when "naturally" aligned to the size of registers.
template <typename T>
inline bool IsNaturallyAligned(T* p)
{
return ((uintptr_t)p & (sizeof(EA_PLATFORM_WORD_SIZE) - 1)) == 0;
}
}}}
#ifndef EATHREAD_ALIGNMENT_CHECK
#define EATHREAD_ALIGNMENT_CHECK(address) EAT_ASSERT_MSG(EA::Thread::detail::IsNaturallyAligned(address), "address is not naturally aligned.")
#endif
///////////////////////////////////////////////////////////////////////////////
// EATHREAD_APPLE_GETMODULEINFO_ENABLED
//
// This functionality has been migrated to EACallstack. We provide a preprocessor switch for backwards compatibility
// until the code path is removed completely in a future release.
//
// Defined as 0 or 1.
//
#ifndef EATHREAD_APPLE_GETMODULEINFO_ENABLED
#define EATHREAD_APPLE_GETMODULEINFO_ENABLED 0
#endif
#endif // Header include guard
@@ -0,0 +1,15 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EATHREAD_DLLINFO_H
#define EATHREAD_DLLINFO_H
#include <eathread/internal/config.h>
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
#endif
@@ -0,0 +1,143 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// eathread_atomic.h
//
// Defines functionality for thread-safe primitive operations.
//
// EAThread atomics do NOT imply the use of read/write barriers. This is
// partly due to historical reasons and partly due to EAThread's internal
// code being optimized for not using barriers.
//
// In future, we are considering migrating the atomics interface which
// defaults atomics to use full read/write barriers while allowing users
// to opt-out of full barrier usage. The new C++11 interface already provides
// similar interfaces.
//
// http://en.cppreference.com/w/cpp/atomic/memory_order
//
// Created by Rob Parolin
/////////////////////////////////////////////////////////////////////////////
#ifndef EATHREAD_INTERNAL_EATHREAD_ATOMIC_H
#define EATHREAD_INTERNAL_EATHREAD_ATOMIC_H
#include <EABase/eabase.h>
#include <eathread/internal/config.h>
#include <eathread/internal/eathread_atomic_standalone.h>
#include <atomic>
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
#define EA_THREAD_ATOMIC_IMPLEMENTED
namespace EA
{
namespace Thread
{
/// class AtomicInt
///
/// Implements thread-safe access to an integer and primary operations on that integer.
/// AtomicIntegers are commonly used as lightweight flags and signals between threads
/// or as the synchronization object for spinlocks. Those familiar with the Win32 API
/// will find that AtomicInt32 is essentially a platform independent interface to
/// the Win32 InterlockedXXX family of functions. Those familiar with Linux may
/// find that AtomicInt32 is essentially a platform independent interface to atomic_t
/// functionality.
///
/// Note that the reference implementation defined here is itself not thread-safe.
/// A thread-safe version requires platform-specific code.
///
/// Example usage
/// AtomicInt32 i = 0;
///
/// ++i;
/// i--;
/// i += 7;
/// i -= 3;
/// i = 2;
///
/// int x = i.GetValue();
/// i.Increment();
/// bool oldValueWas6 = i.SetValueConditional(3, 6);
/// i.Add(4);
///
template <class T>
class AtomicInt
{
public:
typedef AtomicInt<T> ThisType;
typedef T ValueType;
/// AtomicInt
/// Empty constructor. Intentionally leaves mValue in an unspecified state.
/// This is done so that an AtomicInt acts like a standard built-in integer.
AtomicInt()
{}
AtomicInt(ValueType n)
{ SetValue(n); }
AtomicInt(const ThisType& x)
{ SetValue(x.GetValue()); }
AtomicInt& operator=(const ThisType& x)
{ SetValue(x.GetValue()); return *this; }
ValueType GetValue() const
{ return mValue.load(); }
ValueType GetValueRaw() const
{ return mValue; }
ValueType SetValue(ValueType n)
{ return mValue.exchange(n); }
bool SetValueConditional(ValueType n, ValueType condition)
{ return mValue.compare_exchange_strong(condition, n); }
ValueType Increment()
{ return mValue.operator++(); }
ValueType Decrement()
{ return mValue.operator--(); }
ValueType Add(ValueType n)
{ return mValue.fetch_add(n) + n; }
// operators
inline operator const ValueType() const { return GetValue(); }
inline ValueType operator =(ValueType n) { return mValue.operator=(n); }
inline ValueType operator+=(ValueType n) { return mValue.operator+=(n); }
inline ValueType operator-=(ValueType n) { return mValue.operator-=(n); }
inline ValueType operator++() { return mValue.operator++(); }
inline ValueType operator++(int) { return mValue.operator++(0); }
inline ValueType operator--() { return mValue.operator--(); }
inline ValueType operator--(int) { return mValue.operator--(0); }
protected:
std::atomic<ValueType> mValue;
};
} // namespace Thread
} // namespace EA
#endif // EATHREAD_INTERNAL_EATHREAD_ATOMIC_H
@@ -0,0 +1,36 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
/// Standalone atomic functions
/// These act the same as the class functions below.
/// The T return values are the previous value, except for the
/// AtomicFetchSwap function which returns the swapped out value.
///
/// T AtomicGetValue(volatile T*);
/// T AtomicGetValue(const volatile T*);
/// void AtomicSetValue(volatile T*, T value);
/// T AtomicFetchIncrement(volatile T*);
/// T AtomicFetchDecrement(volatile T*);
/// T AtomicFetchAdd(volatile T*, T value);
/// T AtomicFetchSub(volatile T*, T value);
/// T AtomicFetchOr(volatile T*, T value);
/// T AtomicFetchAnd(volatile T*, T value);
/// T AtomicFetchXor(volatile T*, T value);
/// T AtomicFetchSwap(volatile T*, T value);
/// T AtomicFetchSwapConditional(volatile T*, T value, T condition);
/// bool AtomicSetValueConditional(volatile T*, T value, T condition);
#if defined(EA_COMPILER_MSVC)
#include <eathread/internal/eathread_atomic_standalone_msvc.h>
#elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
#include <eathread/internal/eathread_atomic_standalone_gcc.h>
#else
#error unsupported platform
#endif
@@ -0,0 +1,199 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
namespace EA
{
namespace Thread
{
// TODO(rparolin): Consider use of clang builtin __sync_swap.
// https://clang.llvm.org/docs/LanguageExtensions.html#sync-swap
// TODO(rparolin): Consider use of C11 atomics
// https://clang.llvm.org/docs/LanguageExtensions.html#c11-atomic-builtins
namespace detail
{
template<class T>
inline T AtomicGetValue(volatile T* ptr);
} // namespace detail
// int
inline int AtomicGetValue(volatile int* ptr) { return detail::AtomicGetValue(ptr); }
inline int AtomicGetValue(const volatile int* ptr) { return AtomicGetValue(const_cast<volatile int*>(ptr)); }
inline int AtomicSetValue(volatile int* dest, int value) { return __sync_lock_test_and_set(dest, value); }
inline int AtomicFetchIncrement(volatile int* dest) { return __sync_fetch_and_add(dest, int(1)); }
inline int AtomicFetchDecrement(volatile int* dest) { return __sync_fetch_and_add(dest, int(-1)); }
inline int AtomicFetchAdd(volatile int* dest, int value) { return __sync_fetch_and_add(dest, value); }
inline int AtomicFetchSub(volatile int* dest, int value) { return __sync_fetch_and_sub(dest, value); }
inline int AtomicFetchOr(volatile int* dest, int value) { return __sync_fetch_and_or(dest, value); }
inline int AtomicFetchAnd(volatile int* dest, int value) { return __sync_fetch_and_and(dest, value); }
inline int AtomicFetchXor(volatile int* dest, int value) { return __sync_fetch_and_xor(dest, value); }
inline int AtomicFetchSwap(volatile int* dest, int value) { return __sync_lock_test_and_set(dest, value); }
inline int AtomicFetchSwapConditional(volatile int* dest, int value, int condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile int* dest, int value, int condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
// unsigned int
inline unsigned int AtomicGetValue(volatile unsigned int* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned int AtomicGetValue(const volatile unsigned int* ptr) { return AtomicGetValue(const_cast<volatile unsigned int*>(ptr)); }
inline unsigned int AtomicSetValue(volatile unsigned int* dest, unsigned int value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned int AtomicFetchIncrement(volatile unsigned int* dest) { return __sync_fetch_and_add(dest, (unsigned int)(1)); }
inline unsigned int AtomicFetchDecrement(volatile unsigned int* dest) { return __sync_fetch_and_add(dest, (unsigned int)(-1)); }
inline unsigned int AtomicFetchAdd(volatile unsigned int* dest, unsigned int value) { return __sync_fetch_and_add(dest, value); }
inline unsigned int AtomicFetchSub(volatile unsigned int* dest, unsigned int value) { return __sync_fetch_and_sub(dest, value); }
inline unsigned int AtomicFetchOr(volatile unsigned int* dest, unsigned int value) { return __sync_fetch_and_or(dest, value); }
inline unsigned int AtomicFetchAnd(volatile unsigned int* dest, unsigned int value) { return __sync_fetch_and_and(dest, value); }
inline unsigned int AtomicFetchXor(volatile unsigned int* dest, unsigned int value) { return __sync_fetch_and_xor(dest, value); }
inline unsigned int AtomicFetchSwap(volatile unsigned int* dest, unsigned int value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned int AtomicFetchSwapConditional(volatile unsigned int* dest, unsigned int value, unsigned int condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile unsigned int* dest, unsigned int value, unsigned int condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
// short
inline short AtomicGetValue(volatile short* ptr) { return detail::AtomicGetValue(ptr); }
inline short AtomicGetValue(const volatile short* ptr) { return AtomicGetValue(const_cast<volatile short*>(ptr)); }
inline short AtomicSetValue(volatile short* dest, short value) { return __sync_lock_test_and_set(dest, value); }
inline short AtomicFetchIncrement(volatile short* dest) { return __sync_fetch_and_add(dest, short(1)); }
inline short AtomicFetchDecrement(volatile short* dest) { return __sync_fetch_and_add(dest, short(-1)); }
inline short AtomicFetchAdd(volatile short* dest, short value) { return __sync_fetch_and_add(dest, value); }
inline short AtomicFetchSub(volatile short* dest, short value) { return __sync_fetch_and_sub(dest, value); }
inline short AtomicFetchOr(volatile short* dest, short value) { return __sync_fetch_and_or(dest, value); }
inline short AtomicFetchAnd(volatile short* dest, short value) { return __sync_fetch_and_and(dest, value); }
inline short AtomicFetchXor(volatile short* dest, short value) { return __sync_fetch_and_xor(dest, value); }
inline short AtomicFetchSwap(volatile short* dest, short value) { return __sync_lock_test_and_set(dest, value); }
inline short AtomicFetchSwapConditional(volatile short* dest, short value, short condition) { return __sync_val_compare_and_swap(reinterpret_cast<volatile unsigned short*>(dest), static_cast<unsigned short>(condition), static_cast<unsigned short>(value)); }
inline bool AtomicSetValueConditional(volatile short* dest, short value, short condition) { return __sync_bool_compare_and_swap(reinterpret_cast<volatile unsigned short*>(dest), static_cast<unsigned short>(condition), static_cast<unsigned short>(value)); }
// unsigned short
inline unsigned short AtomicGetValue(volatile unsigned short* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned short AtomicGetValue(const volatile unsigned short* ptr) { return AtomicGetValue(const_cast<volatile unsigned short*>(ptr)); }
inline unsigned short AtomicSetValue(volatile unsigned short* dest, unsigned short value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned short AtomicFetchIncrement(volatile unsigned short* dest) { return __sync_fetch_and_add(dest, (unsigned short)(1)); }
inline unsigned short AtomicFetchDecrement(volatile unsigned short* dest) { return __sync_fetch_and_add(dest, (unsigned short)(-1)); }
inline unsigned short AtomicFetchAdd(volatile unsigned short* dest, unsigned short value) { return __sync_fetch_and_add(dest, value); }
inline unsigned short AtomicFetchSub(volatile unsigned short* dest, unsigned short value) { return __sync_fetch_and_sub(dest, value); }
inline unsigned short AtomicFetchOr(volatile unsigned short* dest, unsigned short value) { return __sync_fetch_and_or(dest, value); }
inline unsigned short AtomicFetchAnd(volatile unsigned short* dest, unsigned short value) { return __sync_fetch_and_and(dest, value); }
inline unsigned short AtomicFetchXor(volatile unsigned short* dest, unsigned short value) { return __sync_fetch_and_xor(dest, value); }
inline unsigned short AtomicFetchSwap(volatile unsigned short* dest, unsigned short value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned short AtomicFetchSwapConditional(volatile unsigned short* dest, unsigned short value, unsigned short condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile unsigned short* dest, unsigned short value, unsigned short condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
// long
inline long AtomicGetValue(volatile long* ptr) { return detail::AtomicGetValue(ptr); }
inline long AtomicGetValue(const volatile long* ptr) { return AtomicGetValue(const_cast<volatile long*>(ptr)); }
inline long AtomicSetValue(volatile long* dest, long value) { return __sync_lock_test_and_set(dest, value); }
inline long AtomicFetchIncrement(volatile long* dest) { return __sync_fetch_and_add(dest, long(1)); }
inline long AtomicFetchDecrement(volatile long* dest) { return __sync_fetch_and_add(dest, long(-1)); }
inline long AtomicFetchAdd(volatile long* dest, long value) { return __sync_fetch_and_add(dest, value); }
inline long AtomicFetchSub(volatile long* dest, long value) { return __sync_fetch_and_sub(dest, value); }
inline long AtomicFetchOr(volatile long* dest, long value) { return __sync_fetch_and_or(dest, value); }
inline long AtomicFetchAnd(volatile long* dest, long value) { return __sync_fetch_and_and(dest, value); }
inline long AtomicFetchXor(volatile long* dest, long value) { return __sync_fetch_and_xor(dest, value); }
inline long AtomicFetchSwap(volatile long* dest, long value) { return __sync_lock_test_and_set(dest, value); }
inline long AtomicFetchSwapConditional(volatile long* dest, long value, long condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile long* dest, long value, long condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
// unsigned long
inline unsigned long AtomicGetValue(volatile unsigned long* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned long AtomicGetValue(const volatile unsigned long* ptr) { return AtomicGetValue(const_cast<volatile unsigned long*>(ptr)); }
inline unsigned long AtomicSetValue(volatile unsigned long* dest, unsigned long value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned long AtomicFetchIncrement(volatile unsigned long* dest) { return __sync_fetch_and_add(dest, (unsigned long)(1)); }
inline unsigned long AtomicFetchDecrement(volatile unsigned long* dest) { return __sync_fetch_and_add(dest, (unsigned long)(-1)); }
inline unsigned long AtomicFetchAdd(volatile unsigned long* dest, unsigned long value) { return __sync_fetch_and_add(dest, value); }
inline unsigned long AtomicFetchSub(volatile unsigned long* dest, unsigned long value) { return __sync_fetch_and_sub(dest, value); }
inline unsigned long AtomicFetchOr(volatile unsigned long* dest, unsigned long value) { return __sync_fetch_and_or(dest, value); }
inline unsigned long AtomicFetchAnd(volatile unsigned long* dest, unsigned long value) { return __sync_fetch_and_and(dest, value); }
inline unsigned long AtomicFetchXor(volatile unsigned long* dest, unsigned long value) { return __sync_fetch_and_xor(dest, value); }
inline unsigned long AtomicFetchSwap(volatile unsigned long* dest, unsigned long value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned long AtomicFetchSwapConditional(volatile unsigned long* dest, unsigned long value, unsigned long condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile unsigned long* dest, unsigned long value, unsigned long condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
// char32_t
#if EA_CHAR32_NATIVE
inline char32_t AtomicGetValue(volatile char32_t* ptr) { return detail::AtomicGetValue(ptr); }
inline char32_t AtomicGetValue(const volatile char32_t* ptr) { return AtomicGetValue(const_cast<volatile char32_t*>(ptr)); }
inline char32_t AtomicSetValue(volatile char32_t* dest, char32_t value) { return __sync_lock_test_and_set(dest, value); }
inline char32_t AtomicFetchIncrement(volatile char32_t* dest) { return __sync_fetch_and_add(dest, char32_t(1)); }
inline char32_t AtomicFetchDecrement(volatile char32_t* dest) { return __sync_fetch_and_add(dest, char32_t(-1)); }
inline char32_t AtomicFetchAdd(volatile char32_t* dest, char32_t value) { return __sync_fetch_and_add(dest, value); }
inline char32_t AtomicFetchSub(volatile char32_t* dest, char32_t value) { return __sync_fetch_and_sub(dest, value); }
inline char32_t AtomicFetchOr(volatile char32_t* dest, char32_t value) { return __sync_fetch_and_or(dest, value); }
inline char32_t AtomicFetchAnd(volatile char32_t* dest, char32_t value) { return __sync_fetch_and_and(dest, value); }
inline char32_t AtomicFetchXor(volatile char32_t* dest, char32_t value) { return __sync_fetch_and_xor(dest, value); }
inline char32_t AtomicFetchSwap(volatile char32_t* dest, char32_t value) { return __sync_lock_test_and_set(dest, value); }
inline char32_t AtomicFetchSwapConditional(volatile char32_t* dest, char32_t value, char32_t condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile char32_t* dest, char32_t value, char32_t condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
#endif
// long long
inline long long AtomicGetValue(volatile long long* ptr) { return detail::AtomicGetValue(ptr); }
inline long long AtomicGetValue(const volatile long long* ptr) { return AtomicGetValue(const_cast<volatile long long*>(ptr)); }
inline long long AtomicSetValue(volatile long long* dest, long long value) { return __sync_lock_test_and_set(dest, value); }
inline long long AtomicFetchIncrement(volatile long long* dest) { return __sync_fetch_and_add(dest, (long long)(1)); }
inline long long AtomicFetchDecrement(volatile long long* dest) { return __sync_fetch_and_add(dest, (long long)(-1)); }
inline long long AtomicFetchAdd(volatile long long* dest, long long value) { return __sync_fetch_and_add(dest, value); }
inline long long AtomicFetchSub(volatile long long* dest, long long value) { return __sync_fetch_and_sub(dest, value); }
inline long long AtomicFetchOr(volatile long long* dest, long long value) { return __sync_fetch_and_or(dest, value); }
inline long long AtomicFetchAnd(volatile long long* dest, long long value) { return __sync_fetch_and_and(dest, value); }
inline long long AtomicFetchXor(volatile long long* dest, long long value) { return __sync_fetch_and_xor(dest, value); }
inline long long AtomicFetchSwap(volatile long long* dest, long long value) { return __sync_lock_test_and_set(dest, value); }
inline long long AtomicFetchSwapConditional(volatile long long* dest, long long value, long long condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile long long* dest, long long value, long long condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
// unsigned long long
inline unsigned long long AtomicGetValue(volatile unsigned long long* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned long long AtomicGetValue(const volatile unsigned long long* ptr) { return AtomicGetValue(const_cast<volatile unsigned long long*>(ptr)); }
inline unsigned long long AtomicSetValue(volatile unsigned long long* dest, unsigned long long value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned long long AtomicFetchIncrement(volatile unsigned long long* dest) { return __sync_fetch_and_add(dest, (unsigned long long)(1)); }
inline unsigned long long AtomicFetchDecrement(volatile unsigned long long* dest) { return __sync_fetch_and_add(dest, (unsigned long long)(-1)); }
inline unsigned long long AtomicFetchAdd(volatile unsigned long long* dest, unsigned long long value) { return __sync_fetch_and_add(dest, value); }
inline unsigned long long AtomicFetchSub(volatile unsigned long long* dest, unsigned long long value) { return __sync_fetch_and_sub(dest, value); }
inline unsigned long long AtomicFetchOr(volatile unsigned long long* dest, unsigned long long value) { return __sync_fetch_and_or(dest, value); }
inline unsigned long long AtomicFetchAnd(volatile unsigned long long* dest, unsigned long long value) { return __sync_fetch_and_and(dest, value); }
inline unsigned long long AtomicFetchXor(volatile unsigned long long* dest, unsigned long long value) { return __sync_fetch_and_xor(dest, value); }
inline unsigned long long AtomicFetchSwap(volatile unsigned long long* dest, unsigned long long value) { return __sync_lock_test_and_set(dest, value); }
inline unsigned long long AtomicFetchSwapConditional(volatile unsigned long long* dest, unsigned long long value, unsigned long long condition) { return __sync_val_compare_and_swap(dest, condition, value); }
inline bool AtomicSetValueConditional(volatile unsigned long long* dest, unsigned long long value, unsigned long long condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
//
// You can not simply define a template for the above atomics due to the explicit 128bit overloads
// below. The compiler will prefer those overloads during overload resolution and attempt to convert
// temporaries as they are more specialized than a template.
//
// template<typename T> inline T AtomicGetValue(volatile T* source) { return __sync_fetch_and_add(source, (T)(0)); }
// template<typename T> inline void AtomicSetValue(volatile T* dest, T value) { __sync_lock_test_and_set(dest, value); }
// template<typename T> inline T AtomicFetchIncrement(volatile T* dest) { return __sync_fetch_and_add(dest, (T)(1)); }
// template<typename T> inline T AtomicFetchDecrement(volatile T* dest) { return __sync_fetch_and_add(dest, (T)(-1)); }
// template<typename T> inline T AtomicFetchAdd(volatile T* dest, T value) { return __sync_fetch_and_add(dest, value); }
// template<typename T> inline T AtomicFetchOr(volatile T* dest, T value) { return __sync_fetch_and_or(dest, value); }
// template<typename T> inline T AtomicFetchAnd(volatile T* dest, T value) { return __sync_fetch_and_and(dest, value); }
// template<typename T> inline T AtomicFetchXor(volatile T* dest, T value) { return __sync_fetch_and_xor(dest, value); }
// template<typename T> inline T AtomicFetchSwap(volatile T* dest, T value) { return __sync_lock_test_and_set(dest, value); }
// template<typename T> inline bool AtomicSetValueConditional(volatile T* dest, T value, T condition) { return __sync_bool_compare_and_swap(dest, condition, value); }
//
namespace detail
{
template<class T>
inline T AtomicGetValue(volatile T* ptr)
{
#if EA_PLATFORM_WORD_SIZE >= 8 && defined(EA_PROCESSOR_X86_64)
EATHREAD_ALIGNMENT_CHECK(ptr);
EACompilerMemoryBarrier();
T value = *ptr;
EACompilerMemoryBarrier();
return value;
#else
return AtomicFetchAdd(ptr, T(0));
#endif
}
} // namespace detail
} // namespace Thread
} // namespace EA
@@ -0,0 +1,249 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
/////////////////////////////////////////////////////////////////////////////
// InterlockedXXX intrinsics
//
#if defined(EA_PLATFORM_MICROSOFT)
EA_DISABLE_ALL_VC_WARNINGS()
#include <xatomic.h>
EA_RESTORE_ALL_VC_WARNINGS()
extern "C" long _InterlockedIncrement(long volatile* Addend);
extern "C" long _InterlockedDecrement(long volatile* Addend);
extern "C" long _InterlockedCompareExchange(long volatile* Dest, long Exchange, long Comp);
extern "C" long _InterlockedExchange(long volatile* Target, long Value);
extern "C" long _InterlockedExchangeAdd(long volatile* Addend, long Value);
extern "C" int64_t _InterlockedCompareExchange64(int64_t volatile* Dest, int64_t Exchange, int64_t Comp);
#pragma intrinsic (_InterlockedCompareExchange)
#define InterlockedCompareExchangeImp _InterlockedCompareExchange
#pragma intrinsic (_InterlockedExchange)
#define InterlockedExchangeImp _InterlockedExchange
#pragma intrinsic (_InterlockedExchangeAdd)
#define InterlockedExchangeAddImp _InterlockedExchangeAdd
#pragma intrinsic (_InterlockedIncrement)
#define InterlockedIncrementImp _InterlockedIncrement
#pragma intrinsic (_InterlockedDecrement)
#define InterlockedDecrementImp _InterlockedDecrement
#pragma intrinsic (_InterlockedCompareExchange64)
#define InterlockedCompareExchange64Imp _InterlockedCompareExchange64
inline bool InterlockedSetIfEqual(volatile int64_t* dest, int64_t newValue, int64_t condition)
{
return (InterlockedCompareExchange64Imp(dest, newValue, condition) == condition);
}
inline bool InterlockedSetIfEqual(volatile uint64_t* dest, uint64_t newValue, uint64_t condition)
{
return (InterlockedCompareExchange64Imp((int64_t volatile*)dest, (int64_t)newValue, (int64_t)condition) == (int64_t)condition);
}
#ifndef InterlockedCompareExchangeImp // If the above intrinsics aren't used...
extern "C" __declspec(dllimport) long __stdcall InterlockedIncrement(long volatile * pAddend);
extern "C" __declspec(dllimport) long __stdcall InterlockedDecrement(long volatile * pAddend);
extern "C" __declspec(dllimport) long __stdcall InterlockedExchange(long volatile * pTarget, long value);
extern "C" __declspec(dllimport) long __stdcall InterlockedExchangeAdd(long volatile * pAddend, long value);
extern "C" __declspec(dllimport) long __stdcall InterlockedCompareExchange(long volatile * pDestination, long value, long compare);
#define InterlockedCompareExchangeImp InterlockedCompareExchange
#define InterlockedExchangeImp InterlockedExchange
#define InterlockedExchangeAddImp InterlockedExchangeAdd
#define InterlockedIncrementImp InterlockedIncrement
#define InterlockedDecrementImp InterlockedDecrement
#endif
#if defined(EA_PROCESSOR_X86)
#define _InterlockedExchange64 _InterlockedExchange64_INLINE
#define _InterlockedExchangeAdd64 _InterlockedExchangeAdd64_INLINE
#define _InterlockedAnd64 _InterlockedAnd64_INLINE
#define _InterlockedOr64 _InterlockedOr64_INLINE
#define _InterlockedXor64 _InterlockedXor64_INLINE
#endif
#endif // EA_PLATFORM_MICROSOFT
namespace EA
{
namespace Thread
{
namespace detail
{
template<class T>
inline T AtomicGetValue(volatile T* ptr);
} // namespace detail
// int
inline int AtomicGetValue(volatile int* ptr) { return detail::AtomicGetValue(ptr); }
inline int AtomicGetValue(const volatile int* ptr) { return AtomicGetValue(const_cast<volatile int*>(ptr)); }
inline int AtomicSetValue(volatile int* ptr, int value) { return _InterlockedExchange((long*)ptr, (long)value); }
inline int AtomicFetchIncrement(volatile int* ptr) { return static_cast<int>(_InterlockedIncrement((long*)ptr)) - 1; }
inline int AtomicFetchDecrement(volatile int* ptr) { return static_cast<int>(_InterlockedDecrement((long*)ptr)) + 1; }
inline int AtomicFetchAdd(volatile int* ptr, int value) { return static_cast<int>(_InterlockedExchangeAdd((long*)ptr, (long)value)); }
inline int AtomicFetchSub(volatile int* ptr, int value) { return static_cast<int>(_InterlockedExchangeAdd((long*)ptr, -(long)value)); }
inline int AtomicFetchOr(volatile int* ptr, int value) { return static_cast<int>(_InterlockedOr((long*)ptr, (long)value)); }
inline int AtomicFetchAnd(volatile int* ptr, int value) { return static_cast<int>(_InterlockedAnd((long*)ptr, (long)value)); }
inline int AtomicFetchXor(volatile int* ptr, int value) { return static_cast<int>(_InterlockedXor((long*)ptr, (long)value)); }
inline int AtomicFetchSwap(volatile int* ptr, int value) { return static_cast<int>(_InterlockedExchange((long*)ptr, (long)value)); }
inline int AtomicFetchSwapConditional(volatile int* ptr, int value, int condition) { return _InterlockedCompareExchange((long*)ptr, (long)value, (long)condition); }
inline bool AtomicSetValueConditional(volatile int* ptr, int value, int condition) { return _InterlockedCompareExchange((long*)ptr, (long)value, (long)condition) == (long)condition; }
// unsigned int
inline unsigned int AtomicGetValue(volatile unsigned int* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned int AtomicGetValue(const volatile unsigned int* ptr) { return AtomicGetValue(const_cast<volatile unsigned int*>(ptr)); }
inline unsigned int AtomicSetValue(volatile unsigned int* ptr, unsigned int value) { return static_cast<unsigned int>(_InterlockedExchange((long*)ptr, (long)value)); }
inline unsigned int AtomicFetchIncrement(volatile unsigned int* ptr) { return static_cast<unsigned int>(_InterlockedExchangeAdd((long*)ptr, (long)1)); }
inline unsigned int AtomicFetchDecrement(volatile unsigned int* ptr) { return static_cast<unsigned int>(_InterlockedExchangeAdd((long*)ptr, (long)-1)); }
inline unsigned int AtomicFetchAdd(volatile unsigned int* ptr, unsigned int value) { return static_cast<unsigned int>(_InterlockedExchangeAdd((long*)ptr, (long)value)); }
inline unsigned int AtomicFetchSub(volatile unsigned int* ptr, unsigned int value) { return static_cast<unsigned int>(_InterlockedExchangeAdd((long*)ptr, -(long)value)); }
inline unsigned int AtomicFetchOr(volatile unsigned int* ptr, unsigned int value) { return static_cast<unsigned int>(_InterlockedOr((long*)ptr, (long)value)); }
inline unsigned int AtomicFetchAnd(volatile unsigned int* ptr, unsigned int value) { return static_cast<unsigned int>(_InterlockedAnd((long*)ptr, (long)value)); }
inline unsigned int AtomicFetchXor(volatile unsigned int* ptr, unsigned int value) { return static_cast<unsigned int>(_InterlockedXor((long*)ptr, (long)value)); }
inline unsigned int AtomicFetchSwap(volatile unsigned int* ptr, unsigned int value) { return static_cast<unsigned int>(_InterlockedExchange((long*)ptr, (long)value)); }
inline unsigned int AtomicFetchSwapConditional(volatile unsigned int* ptr, unsigned int value, unsigned int condition) { return (unsigned int)_InterlockedCompareExchange((long*)ptr, (long)value, (long)condition); }
inline bool AtomicSetValueConditional(volatile unsigned int* ptr, unsigned int value, unsigned int condition) { return _InterlockedCompareExchange((long*)ptr, (long)value, (long)condition) == (long)condition; }
// short
inline short AtomicGetValue(volatile short* ptr) { return detail::AtomicGetValue(ptr); }
inline short AtomicGetValue(const volatile short* ptr) { return AtomicGetValue(const_cast<volatile short*>(ptr)); }
inline short AtomicSetValue(volatile short* ptr, short value) { return static_cast<short>(_InterlockedExchange16((short*)ptr, (short)value)); }
inline short AtomicFetchIncrement(volatile short* ptr) { return static_cast<short>(_InterlockedExchangeAdd16((short*)ptr, (short)1)); }
inline short AtomicFetchDecrement(volatile short* ptr) { return static_cast<short>(_InterlockedExchangeAdd16((short*)ptr, (short)-1)); }
inline short AtomicFetchAdd(volatile short* ptr, short value) { return static_cast<short>(_InterlockedExchangeAdd16((short*)ptr, (short)value)); }
inline short AtomicFetchSub(volatile short* ptr, short value) { return static_cast<short>(_InterlockedExchangeAdd16((short*)ptr, -value)); }
inline short AtomicFetchOr(volatile short* ptr, short value) { return static_cast<short>(_InterlockedOr16((short*)ptr, (short)value)); }
inline short AtomicFetchAnd(volatile short* ptr, short value) { return static_cast<short>(_InterlockedAnd16((short*)ptr, (short)value)); }
inline short AtomicFetchXor(volatile short* ptr, short value) { return static_cast<short>(_InterlockedXor16((short*)ptr, (short)value)); }
inline short AtomicFetchSwap(volatile short* ptr, short value) { return static_cast<short>(_InterlockedExchange16((short*)ptr, (short)value)); }
inline short AtomicFetchSwapConditional(volatile short* ptr, short value, short condition) { return _InterlockedCompareExchange16(ptr, value, condition); }
inline bool AtomicSetValueConditional(volatile short* ptr, short value, short condition) { return _InterlockedCompareExchange16(ptr, value, condition) == condition; }
// unsigned short
inline unsigned short AtomicGetValue(volatile unsigned short* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned short AtomicGetValue(const volatile unsigned short* ptr) { return AtomicGetValue(const_cast<volatile unsigned short*>(ptr)); }
inline unsigned short AtomicSetValue(volatile unsigned short* ptr, unsigned short value) { return static_cast<unsigned short>(_InterlockedExchange16((short*)ptr, (short)value)); }
inline unsigned short AtomicFetchIncrement(volatile unsigned short* ptr) { return static_cast<unsigned short>(_InterlockedExchangeAdd16((short*)ptr, (short)1)); }
inline unsigned short AtomicFetchDecrement(volatile unsigned short* ptr) { return static_cast<unsigned short>(_InterlockedExchangeAdd16((short*)ptr, (short)-1)); }
inline unsigned short AtomicFetchAdd(volatile unsigned short* ptr, unsigned short value) { return static_cast<unsigned short>(_InterlockedExchangeAdd16((short*)ptr, (short)value)); }
inline unsigned short AtomicFetchSub(volatile unsigned short* ptr, unsigned short value) { return static_cast<unsigned short>(_InterlockedExchangeAdd16((short*)ptr, -(short)value)); }
inline unsigned short AtomicFetchOr(volatile unsigned short* ptr, unsigned short value) { return static_cast<unsigned short>(_InterlockedOr16((short*)ptr, (short)value)); }
inline unsigned short AtomicFetchAnd(volatile unsigned short* ptr, unsigned short value) { return static_cast<unsigned short>(_InterlockedAnd16((short*)ptr, (short)value)); }
inline unsigned short AtomicFetchXor(volatile unsigned short* ptr, unsigned short value) { return static_cast<unsigned short>(_InterlockedXor16((short*)ptr, (short)value)); }
inline unsigned short AtomicFetchSwap(volatile unsigned short* ptr, unsigned short value) { return static_cast<unsigned short>(_InterlockedExchange16((short*)ptr, (short)value)); }
inline unsigned short AtomicFetchSwapConditional(volatile unsigned short* ptr, unsigned short value, unsigned short condition) { return (unsigned short)_InterlockedCompareExchange16((short*)ptr, (short)value, (short)condition); }
inline bool AtomicSetValueConditional(volatile unsigned short* ptr, unsigned short value, unsigned short condition) { return _InterlockedCompareExchange16((short*)ptr, (short)value, (short)condition) == (short)condition; }
// long
inline long AtomicGetValue(volatile long* ptr) { return detail::AtomicGetValue(ptr); }
inline long AtomicGetValue(const volatile long* ptr) { return AtomicGetValue(const_cast<volatile long*>(ptr)); }
inline long AtomicSetValue(volatile long* ptr, long value) { return _InterlockedExchange(ptr, value); }
inline long AtomicFetchIncrement(volatile long* ptr) { return _InterlockedIncrement(ptr) - 1; }
inline long AtomicFetchDecrement(volatile long* ptr) { return _InterlockedDecrement(ptr) + 1; }
inline long AtomicFetchAdd(volatile long* ptr, long value) { return _InterlockedExchangeAdd(ptr, value); }
inline long AtomicFetchSub(volatile long* ptr, long value) { return _InterlockedExchangeAdd(ptr, -value); }
inline long AtomicFetchOr(volatile long* ptr, long value) { return _InterlockedOr(ptr, value); }
inline long AtomicFetchAnd(volatile long* ptr, long value) { return _InterlockedAnd(ptr, value); }
inline long AtomicFetchXor(volatile long* ptr, long value) { return _InterlockedXor(ptr, value); }
inline long AtomicFetchSwap(volatile long* ptr, long value) { return _InterlockedExchange(ptr, value); }
inline long AtomicFetchSwapConditional(volatile long* ptr, long value, long condition) { return _InterlockedCompareExchange(ptr, value, condition); }
inline bool AtomicSetValueConditional(volatile long* ptr, long value, long condition) { return _InterlockedCompareExchange(ptr, value, condition) == condition; }
// unsigned long
inline unsigned long AtomicGetValue(volatile unsigned long* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned long AtomicGetValue(const volatile unsigned long* ptr) { return AtomicGetValue(const_cast<volatile unsigned long*>(ptr)); }
inline unsigned long AtomicSetValue(volatile unsigned long* ptr, unsigned long value) { return static_cast<unsigned long>(_InterlockedExchange((long*)ptr, (long)value)); }
inline unsigned long AtomicFetchIncrement(volatile unsigned long* ptr) { return static_cast<unsigned long>(_InterlockedIncrement((long*)ptr)) - 1; }
inline unsigned long AtomicFetchDecrement(volatile unsigned long* ptr) { return static_cast<unsigned long>(_InterlockedDecrement((long*)ptr)) + 1; }
inline unsigned long AtomicFetchAdd(volatile unsigned long* ptr, unsigned long value) { return static_cast<unsigned long>(_InterlockedExchangeAdd((long*)ptr, (long)value)); }
inline unsigned long AtomicFetchSub(volatile unsigned long* ptr, unsigned long value) { return static_cast<unsigned long>(_InterlockedExchangeAdd((long*)ptr, -(long)value)); }
inline unsigned long AtomicFetchOr(volatile unsigned long* ptr, unsigned long value) { return static_cast<unsigned long>(_InterlockedOr((long*)ptr, (long)value)); }
inline unsigned long AtomicFetchAnd(volatile unsigned long* ptr, unsigned long value) { return static_cast<unsigned long>(_InterlockedAnd((long*)ptr, (long)value)); }
inline unsigned long AtomicFetchXor(volatile unsigned long* ptr, unsigned long value) { return static_cast<unsigned long>(_InterlockedXor((long*)ptr, (long)value)); }
inline unsigned long AtomicFetchSwap(volatile unsigned long* ptr, unsigned long value) { return static_cast<unsigned long>(_InterlockedExchange((long*)ptr, (long)value)); }
inline unsigned long AtomicFetchSwapConditional(volatile unsigned long* ptr, unsigned long value, unsigned long condition) { return static_cast<unsigned long>(_InterlockedCompareExchange((long*)ptr, (long)value, (long)condition)); }
inline bool AtomicSetValueConditional(volatile unsigned long* ptr, unsigned long value, unsigned long condition) { return static_cast<unsigned long>(_InterlockedCompareExchange((long*)ptr, (long)value, (long)condition)) == condition; }
// char32_t
#if EA_CHAR32_NATIVE
inline char32_t AtomicGetValue(volatile char32_t* ptr) { return detail::AtomicGetValue(ptr); }
inline char32_t AtomicGetValue(const volatile char32_t* ptr) { return AtomicGetValue(const_cast<volatile char32_t*>(ptr)); }
inline char32_t AtomicSetValue(volatile char32_t* ptr, char32_t value) { return static_cast<char32_t>(_InterlockedExchange((long*)ptr, (long)value)); }
inline char32_t AtomicFetchIncrement(volatile char32_t* ptr) { return static_cast<char32_t>(_InterlockedExchangeAdd((long*)ptr, (long)1)); }
inline char32_t AtomicFetchDecrement(volatile char32_t* ptr) { return static_cast<char32_t>(_InterlockedExchangeAdd((long*)ptr, (long)-1)); }
inline char32_t AtomicFetchAdd(volatile char32_t* ptr, char32_t value) { return static_cast<char32_t>(_InterlockedExchangeAdd((long*)ptr, (long)value)); }
inline char32_t AtomicFetchSub(volatile char32_t* ptr, char32_t value) { return static_cast<char32_t>(_InterlockedExchangeAdd((long*)ptr, -(long)value)); }
inline char32_t AtomicFetchOr(volatile char32_t* ptr, char32_t value) { return static_cast<char32_t>(_InterlockedOr((long*)ptr, (long)value)); }
inline char32_t AtomicFetchAnd(volatile char32_t* ptr, char32_t value) { return static_cast<char32_t>(_InterlockedAnd((long*)ptr, (long)value)); }
inline char32_t AtomicFetchXor(volatile char32_t* ptr, char32_t value) { return static_cast<char32_t>(_InterlockedXor((long*)ptr, (long)value)); }
inline char32_t AtomicFetchSwap(volatile char32_t* ptr, char32_t value) { return static_cast<char32_t>(_InterlockedExchange((long*)ptr, (long)value)); }
inline char32_t AtomicFetchSwapConditional(volatile char32_t* ptr, char32_t value, unsigned int condition) { return static_cast<char32_t>(_InterlockedCompareExchange((long*)ptr, (long)value, (long)condition)); }
inline bool AtomicSetValueConditional(volatile char32_t* ptr, char32_t value, unsigned int condition) { return _InterlockedCompareExchange((long*)ptr, (long)value, (long)condition) == (long)condition; }
#endif
// long long
inline long long AtomicGetValue(volatile long long* ptr) { return detail::AtomicGetValue(ptr); }
inline long long AtomicGetValue(const volatile long long* ptr) { return AtomicGetValue(const_cast<volatile long long*>(ptr)); }
inline long long AtomicSetValue(volatile long long* ptr, long long value) { return static_cast<long long>(_InterlockedExchange64(ptr, value)); }
inline long long AtomicFetchIncrement(volatile long long* ptr) { return static_cast<long long>(_InterlockedExchangeAdd64(ptr, (long long)1)); }
inline long long AtomicFetchDecrement(volatile long long* ptr) { return static_cast<long long>(_InterlockedExchangeAdd64(ptr, (long long)-1)); }
inline long long AtomicFetchAdd(volatile long long* ptr, long long value) { return static_cast<long long>(_InterlockedExchangeAdd64(ptr, value)); }
inline long long AtomicFetchSub(volatile long long* ptr, long long value) { return static_cast<long long>(_InterlockedExchangeAdd64(ptr, -(long long)value)); }
inline long long AtomicFetchOr(volatile long long* ptr, long long value) { return static_cast<long long>(_InterlockedOr64(ptr, value)); }
inline long long AtomicFetchAnd(volatile long long* ptr, long long value) { return static_cast<long long>(_InterlockedAnd64(ptr, value)); }
inline long long AtomicFetchXor(volatile long long* ptr, long long value) { return static_cast<long long>(_InterlockedXor64(ptr, value)); }
inline long long AtomicFetchSwap(volatile long long* ptr, long long value) { return static_cast<long long>(_InterlockedExchange64(ptr, value)); }
inline long long AtomicFetchSwapConditional(volatile long long* ptr, long long value, long long condition) { return _InterlockedCompareExchange64(ptr, value, condition); }
inline bool AtomicSetValueConditional(volatile long long* ptr, long long value, long long condition) { return _InterlockedCompareExchange64(ptr, value, condition) == condition; }
// unsigned long long
inline unsigned long long AtomicGetValue(volatile unsigned long long* ptr) { return detail::AtomicGetValue(ptr); }
inline unsigned long long AtomicGetValue(const volatile unsigned long long* ptr) { return AtomicGetValue(const_cast<volatile unsigned long long*>(ptr)); }
inline unsigned long long AtomicSetValue(volatile unsigned long long* ptr, unsigned long long value) { return static_cast<unsigned long long>(_InterlockedExchange64(reinterpret_cast<volatile long long*>(ptr), (long long)value)); }
inline unsigned long long AtomicFetchIncrement(volatile unsigned long long* ptr) { return static_cast<unsigned long long>(_InterlockedExchangeAdd64(reinterpret_cast<volatile long long*>(ptr), (long long)1)); }
inline unsigned long long AtomicFetchDecrement(volatile unsigned long long* ptr) { return static_cast<unsigned long long>(_InterlockedExchangeAdd64(reinterpret_cast<volatile long long*>(ptr), (long long)-1)); }
inline unsigned long long AtomicFetchAdd(volatile unsigned long long* ptr, unsigned long long value) { return static_cast<unsigned long long>(_InterlockedExchangeAdd64(reinterpret_cast<volatile long long*>(ptr), (long long)value)); }
inline unsigned long long AtomicFetchSub(volatile unsigned long long* ptr, unsigned long long value) { return static_cast<unsigned long long>(_InterlockedExchangeAdd64(reinterpret_cast<volatile long long*>(ptr), -(long long)value)); }
inline unsigned long long AtomicFetchOr(volatile unsigned long long* ptr, unsigned long long value) { return static_cast<unsigned long long>(_InterlockedOr64(reinterpret_cast<volatile long long*>(ptr), (long long)value)); }
inline unsigned long long AtomicFetchAnd(volatile unsigned long long* ptr, unsigned long long value) { return static_cast<unsigned long long>(_InterlockedAnd64(reinterpret_cast<volatile long long*>(ptr),(long long) value)); }
inline unsigned long long AtomicFetchXor(volatile unsigned long long* ptr, unsigned long long value) { return static_cast<unsigned long long>(_InterlockedXor64(reinterpret_cast<volatile long long*>(ptr),(long long) value)); }
inline unsigned long long AtomicFetchSwap(volatile unsigned long long* ptr, unsigned long long value) { return static_cast<unsigned long long>(_InterlockedExchange64(reinterpret_cast<volatile long long*>(ptr),(long long) value)); }
inline unsigned long long AtomicFetchSwapConditional(volatile unsigned long long* ptr, unsigned long long value, unsigned long long condition) { return static_cast<unsigned long long>(_InterlockedCompareExchange64(reinterpret_cast<volatile long long*>(ptr), (long long)value, (long long)condition)); }
inline bool AtomicSetValueConditional(volatile unsigned long long* ptr, unsigned long long value, unsigned long long condition) { return static_cast<unsigned long long>(_InterlockedCompareExchange64(reinterpret_cast<volatile long long*>(ptr), (long long)value, (long long)condition)) == condition; }
namespace detail
{
template<class T>
inline T AtomicGetValue(volatile T* ptr)
{
#if EA_PLATFORM_WORD_SIZE >= 8 && defined(EA_PROCESSOR_X86_64)
EATHREAD_ALIGNMENT_CHECK(ptr);
EACompilerMemoryBarrier();
T value = *ptr;
EACompilerMemoryBarrier();
return value;
#else
return AtomicFetchAdd(ptr, T(0));
#endif
}
} // namespace detail
} // namespace Thread
} // namespace EA
@@ -0,0 +1,32 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
/////////////////////////////////////////////////////////////////////////////
// NOTE(rparolin): Provides a unified method of access to EAThread global
// variables that (when specified by the user) can become DLL safe by adding a
// dependency on EAStdC EAGlobal implementation.
/////////////////////////////////////////////////////////////////////////////
#ifndef EATHREAD_INTERNAL_GLOBAL_H
#define EATHREAD_INTERNAL_GLOBAL_H
#if EATHREAD_GLOBAL_VARIABLE_DLL_SAFETY
#include <EAStdC/EAGlobal.h>
#define EATHREAD_GLOBALVARS (*EA::StdC::AutoStaticOSGlobalPtr<EA::Thread::EAThreadGlobalVars, 0xdabbad00>().get())
#define EATHREAD_GLOBALVARS_CREATE_INSTANCE EA::StdC::AutoStaticOSGlobalPtr<EA::Thread::EAThreadGlobalVars, 0xdabbad00> gGlobalVarsInstance;
#define EATHREAD_GLOBALVARS_EXTERN_INSTANCE
#else
#define EATHREAD_GLOBALVARS gEAThreadGlobalVars
#define EATHREAD_GLOBALVARS_CREATE_INSTANCE EA::Thread::EAThreadGlobalVars gEAThreadGlobalVars
#define EATHREAD_GLOBALVARS_EXTERN_INSTANCE extern EA::Thread::EAThreadGlobalVars gEAThreadGlobalVars
#endif
#endif
@@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
#ifndef EATHREAD_INTERNAL_TIMINGS_H
#define EATHREAD_INTERNAL_TIMINGS_H
namespace EA
{
namespace Thread
{
#if defined(EA_PLATFORM_SONY)
// RelativeTimeoutFromAbsoluteTimeout returns a relative timeout in microseconds.
inline uint32_t RelativeTimeoutFromAbsoluteTimeout(EA::Thread::ThreadTime timeoutAbsolute)
{
using namespace EA::Thread;
EAT_ASSERT((timeoutAbsolute == kTimeoutImmediate) || (timeoutAbsolute > EATHREAD_MIN_ABSOLUTE_TIME)); // Assert that the user didn't make the mistake of treating time as relative instead of absolute.
uint32_t timeoutRelative = 0;
if (timeoutAbsolute == kTimeoutNone)
{
timeoutRelative = 0xffffffff;
}
else if (timeoutAbsolute == kTimeoutImmediate)
{
timeoutRelative = 0;
}
else
{
ThreadTime timeCurrent(GetThreadTime());
timeoutRelative = (timeoutAbsolute > timeCurrent) ? EA_THREADTIME_AS_UINT_MICROSECONDS(timeoutAbsolute - timeCurrent) : 0;
}
EAT_ASSERT((timeoutRelative == 0xffffffff) || (timeoutRelative < 100000000)); // Assert that the timeout is a sane value and didn't wrap around.
return timeoutRelative;
}
#endif
}
}
#endif