499 lines
12 KiB
C
499 lines
12 KiB
C
/**
|
|
* @file kAtomic.x.h
|
|
*
|
|
* @internal
|
|
* Copyright (C) 2012-2021 by LMI Technologies Inc.
|
|
* Licensed under the MIT License.
|
|
* Redistributed files must retain the above copyright notice.
|
|
*/
|
|
#ifndef K_API_ATOMIC_X_H
|
|
#define K_API_ATOMIC_X_H
|
|
|
|
/**
|
|
* @internal
|
|
* @class kAtomic
|
|
* @ingroup kApi-Threads
|
|
* @brief Implements shared support functions for atomic variable classes.
|
|
*/
|
|
typedef struct kAtomicStatic
|
|
{
|
|
k32u placeholder; //unused
|
|
} kAtomicStatic;
|
|
|
|
kDeclareStaticClassEx(k, kAtomic)
|
|
|
|
kFx(kStatus) xkAtomic_InitStatic();
|
|
kFx(kStatus) xkAtomic_ReleaseStatic();
|
|
|
|
/*
|
|
* Forward Declarations
|
|
*/
|
|
|
|
kInlineFx(void) kAtomic32s_Init(kAtomic32s* atomic, k32s value);
|
|
kInlineFx(k32s) kAtomic32s_Increment(kAtomic32s* atomic);
|
|
kInlineFx(k32s) kAtomic32s_Decrement(kAtomic32s* atomic);
|
|
kInlineFx(k32s) kAtomic32s_Exchange(kAtomic32s* atomic, k32s value);
|
|
kInlineFx(kBool) kAtomic32s_CompareExchange(kAtomic32s* atomic, k32s oldValue, k32s value);
|
|
kInlineFx(k32s) kAtomic32s_Get(kAtomic32s* atomic);
|
|
kInlineFx(void) kAtomicPointer_Init(kAtomicPointer* atomic, kPointer value);
|
|
kInlineFx(kPointer) kAtomicPointer_Exchange(kAtomicPointer* atomic, kPointer value);
|
|
kInlineFx(kBool) kAtomicPointer_CompareExchange(kAtomicPointer* atomic, kPointer oldValue, kPointer value);
|
|
kInlineFx(kPointer) kAtomicPointer_Get(kAtomicPointer* atomic);
|
|
|
|
#if defined(K_WINDOWS)
|
|
|
|
# include <intrin.h>
|
|
|
|
kInlineFx(k32s) xkAtomic32s_IncrementImpl(kAtomic32s* atomic)
|
|
{
|
|
return _InterlockedIncrement((volatile long*)atomic);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_DecrementImpl(kAtomic32s* atomic)
|
|
{
|
|
return _InterlockedDecrement((volatile long*)atomic);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_ExchangeImpl(kAtomic32s* atomic, k32s value)
|
|
{
|
|
return _InterlockedExchange((volatile long*)atomic, value);
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomic32s_CompareExchangeImpl(kAtomic32s* atomic, k32s oldValue, k32s value)
|
|
{
|
|
return (_InterlockedCompareExchange((volatile long*)atomic, value, oldValue) == oldValue);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_GetImpl(kAtomic32s* atomic)
|
|
{
|
|
k32s value;
|
|
|
|
do
|
|
{
|
|
value = *atomic;
|
|
}
|
|
while (!kAtomic32s_CompareExchange(atomic, value, value));
|
|
|
|
return value;
|
|
}
|
|
|
|
//c++/cli can't handle interlocked pointer intrinsics
|
|
# if defined(K_CPP_CLI)
|
|
# pragma managed(push, off)
|
|
# endif
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_ExchangeImpl(kAtomicPointer* atomic, kPointer value)
|
|
{
|
|
return _InterlockedExchangePointer(atomic, value);
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomicPointer_CompareExchangeImpl(void* volatile* atomic, kPointer oldValue, kPointer value)
|
|
{
|
|
return (_InterlockedCompareExchangePointer(atomic, value, oldValue) == oldValue);
|
|
}
|
|
|
|
# if defined(K_CPP_CLI)
|
|
# pragma managed(pop)
|
|
# endif
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_GetImpl(kAtomicPointer* atomic)
|
|
{
|
|
kPointer value;
|
|
|
|
do
|
|
{
|
|
value = *atomic;
|
|
}
|
|
while (!kAtomicPointer_CompareExchange(atomic, value, value));
|
|
|
|
return value;
|
|
}
|
|
|
|
#elif defined(K_DARWIN)
|
|
|
|
# include <libkern/OSAtomic.h>
|
|
|
|
kInlineFx(k32s) xkAtomic32s_IncrementImpl(kAtomic32s* atomic)
|
|
{
|
|
return OSAtomicIncrement32Barrier(atomic);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_DecrementImpl(kAtomic32s* atomic)
|
|
{
|
|
return OSAtomicDecrement32Barrier(atomic);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_ExchangeImpl(kAtomic32s* atomic, k32s value)
|
|
{
|
|
k32s oldValue;
|
|
|
|
do
|
|
{
|
|
oldValue = *atomic;
|
|
}
|
|
while (!OSAtomicCompareAndSwapIntBarrier(oldValue, value, atomic));
|
|
|
|
return oldValue;
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomic32s_CompareExchangeImpl(kAtomic32s* atomic, k32s oldValue, k32s value)
|
|
{
|
|
return OSAtomicCompareAndSwapIntBarrier(oldValue, value, atomic);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_GetImpl(kAtomic32s* atomic)
|
|
{
|
|
k32s value;
|
|
|
|
do
|
|
{
|
|
value = *atomic;
|
|
}
|
|
while (!kAtomic32s_CompareExchange(atomic, value, value));
|
|
|
|
return value;
|
|
}
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_ExchangeImpl(kAtomicPointer* atomic, kPointer value)
|
|
{
|
|
kPointer oldValue;
|
|
|
|
do
|
|
{
|
|
oldValue = *atomic;
|
|
}
|
|
while (!OSAtomicCompareAndSwapPtrBarrier(oldValue, value, atomic));
|
|
|
|
return oldValue;
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomicPointer_CompareExchangeImpl(kAtomicPointer* atomic, kPointer oldValue, kPointer value)
|
|
{
|
|
return OSAtomicCompareAndSwapPtrBarrier(oldValue, value, atomic);
|
|
}
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_GetImpl(kAtomicPointer* atomic)
|
|
{
|
|
kPointer value;
|
|
|
|
do
|
|
{
|
|
value = *atomic;
|
|
}
|
|
while (!kAtomicPointer_CompareExchange(atomic, value, value));
|
|
|
|
return value;
|
|
}
|
|
|
|
#elif defined(K_TI_BIOS)
|
|
|
|
typedef k32u xkAtomicIntFlags;
|
|
|
|
# if defined(K_TI_CCS)
|
|
|
|
kInlineFx(xkAtomicIntFlags) xkAtomic_DisableInterrupts()
|
|
{
|
|
return _disable_interrupts();
|
|
}
|
|
|
|
kInlineFx(void) xkAtomic_RestoreInterrupts(xkAtomicIntFlags flags)
|
|
{
|
|
return _restore_interrupts(flags);
|
|
}
|
|
|
|
# else
|
|
|
|
kInlineFx(xkAtomicIntFlags) xkAtomic_InterruptFlags(void)
|
|
{
|
|
xkAtomicIntFlags flags;
|
|
|
|
asm volatile (" mvc .s2 CSR,%0\n" : "=b"(flags));
|
|
|
|
return flags;
|
|
}
|
|
|
|
kInlineFx(void) xkAtomic_SetInterruptFlags(xkAtomicIntFlags flags)
|
|
{
|
|
asm volatile (" mvc .s2 %0,CSR\n" : : "b"(flags) : "memory");
|
|
}
|
|
|
|
kInlineFx(xkAtomicIntFlags) xkAtomic_DisableInterrupts()
|
|
{
|
|
xkAtomicIntFlags flags = xkAtomic_InterruptFlags();
|
|
|
|
xkAtomic_SetInterruptFlags(flags & ~1);
|
|
|
|
return flags;
|
|
}
|
|
|
|
kInlineFx(void) xkAtomic_RestoreInterrupts(xkAtomicIntFlags flags)
|
|
{
|
|
xkAtomic_SetInterruptFlags(flags);
|
|
}
|
|
|
|
# endif
|
|
|
|
kInlineFx(k32s) xkAtomic32s_IncrementImpl(kAtomic32s* atomic)
|
|
{
|
|
k32s newValue;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
newValue = *atomic + 1;
|
|
*atomic = newValue;
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return newValue;
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_DecrementImpl(kAtomic32s* atomic)
|
|
{
|
|
k32s newValue;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
newValue = *atomic - 1;
|
|
*atomic = newValue;
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return newValue;
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_ExchangeImpl(kAtomic32s* atomic, k32s value)
|
|
{
|
|
k32s oldValue;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
oldValue = *atomic;
|
|
*atomic = value;
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return oldValue;
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomic32s_CompareExchangeImpl(kAtomic32s* atomic, k32s oldValue, k32s value)
|
|
{
|
|
kBool exchanged = kFALSE;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
if (*atomic == oldValue)
|
|
{
|
|
*atomic = value;
|
|
exchanged = kTRUE;
|
|
}
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return exchanged;
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_GetImpl(kAtomic32s* atomic)
|
|
{
|
|
k32s value;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
value = *atomic;
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return value;
|
|
}
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_ExchangeImpl(kAtomicPointer* atomic, kPointer value)
|
|
{
|
|
kPointer oldValue;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
oldValue = *atomic;
|
|
*atomic = value;
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return oldValue;
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomicPointer_CompareExchangeImpl(kAtomicPointer* atomic, kPointer oldValue, kPointer value)
|
|
{
|
|
kBool exchanged = kFALSE;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
if (*atomic == oldValue)
|
|
{
|
|
*atomic = value;
|
|
exchanged = kTRUE;
|
|
}
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return exchanged;
|
|
}
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_GetImpl(kAtomicPointer* atomic)
|
|
{
|
|
kPointer value;
|
|
xkAtomicIntFlags intFlags;
|
|
|
|
intFlags = xkAtomic_DisableInterrupts();
|
|
{
|
|
value = *atomic;
|
|
}
|
|
xkAtomic_RestoreInterrupts(intFlags);
|
|
|
|
return value;
|
|
}
|
|
|
|
#elif defined (K_VX_KERNEL)
|
|
|
|
//not inlined
|
|
kFx(k32s) xkAtomic32s_IncrementImpl(kAtomic32s* atomic);
|
|
kFx(k32s) xkAtomic32s_DecrementImpl(kAtomic32s* atomic);
|
|
kFx(k32s) xkAtomic32s_ExchangeImpl(kAtomic32s* atomic, k32s value);
|
|
kFx(kBool) xkAtomic32s_CompareExchangeImpl(kAtomic32s* atomic, k32s oldValue, k32s value);
|
|
kFx(k32s) xkAtomic32s_GetImpl(kAtomic32s* atomic);
|
|
kFx(kPointer) xkAtomicPointer_ExchangeImpl(kAtomicPointer* atomic, kPointer value);
|
|
kFx(kBool) xkAtomicPointer_CompareExchangeImpl(kAtomicPointer* atomic, kPointer oldValue, kPointer value);
|
|
kFx(kPointer) xkAtomicPointer_GetImpl(kAtomicPointer* atomic);
|
|
|
|
#elif defined (K_GCC)
|
|
|
|
kInlineFx(k32s) xkAtomic32s_IncrementImpl(kAtomic32s* atomic)
|
|
{
|
|
return __sync_add_and_fetch(atomic, 1);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_DecrementImpl(kAtomic32s* atomic)
|
|
{
|
|
return __sync_sub_and_fetch(atomic, 1);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_ExchangeImpl(kAtomic32s* atomic, k32s value)
|
|
{
|
|
k32s oldValue;
|
|
|
|
do
|
|
{
|
|
oldValue = *atomic;
|
|
}
|
|
while (!__sync_bool_compare_and_swap(atomic, oldValue, value));
|
|
|
|
return oldValue;
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomic32s_CompareExchangeImpl(kAtomic32s* atomic, k32s oldValue, k32s value)
|
|
{
|
|
return __sync_bool_compare_and_swap(atomic, oldValue, value);
|
|
}
|
|
|
|
kInlineFx(k32s) xkAtomic32s_GetImpl(kAtomic32s* atomic)
|
|
{
|
|
k32s value;
|
|
|
|
do
|
|
{
|
|
value = *atomic;
|
|
}
|
|
while (!kAtomic32s_CompareExchange(atomic, value, value));
|
|
|
|
return value;
|
|
}
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_ExchangeImpl(kAtomicPointer* atomic, kPointer value)
|
|
{
|
|
kPointer oldValue;
|
|
|
|
do
|
|
{
|
|
oldValue = *atomic;
|
|
}
|
|
while (!__sync_bool_compare_and_swap(atomic, oldValue, value));
|
|
|
|
return oldValue;
|
|
}
|
|
|
|
kInlineFx(kBool) xkAtomicPointer_CompareExchangeImpl(kAtomicPointer* atomic, kPointer oldValue, kPointer value)
|
|
{
|
|
return __sync_bool_compare_and_swap(atomic, oldValue, value);
|
|
}
|
|
|
|
kInlineFx(kPointer) xkAtomicPointer_GetImpl(kAtomicPointer* atomic)
|
|
{
|
|
kPointer value;
|
|
|
|
do
|
|
{
|
|
value = *atomic;
|
|
}
|
|
while (!kAtomicPointer_CompareExchange(atomic, value, value));
|
|
|
|
return value;
|
|
}
|
|
|
|
#else
|
|
|
|
kFx(k32s) xkAtomic32s_IncrementImpl(kAtomic32s* atomic)
|
|
{
|
|
kAssert(kFALSE);
|
|
return 0;
|
|
}
|
|
|
|
kFx(k32s) xkAtomic32s_DecrementImpl(kAtomic32s* atomic)
|
|
{
|
|
kAssert(kFALSE);
|
|
return 0;
|
|
}
|
|
|
|
kFx(k32s) xkAtomic32s_ExchangeImpl(kAtomic32s* atomic, k32s value)
|
|
{
|
|
kAssert(kFALSE);
|
|
return 0;
|
|
}
|
|
|
|
kFx(kBool) xkAtomic32s_CompareExchangeImpl(kAtomic32s* atomic, k32s oldValue, k32s value)
|
|
{
|
|
kAssert(kFALSE);
|
|
return kFALSE;
|
|
}
|
|
|
|
kFx(k32s) xkAtomic32s_GetImpl(kAtomic32s* atomic)
|
|
{
|
|
kAssert(kFALSE);
|
|
return 0;
|
|
}
|
|
|
|
kFx(kPointer) xkAtomicPointer_ExchangeImpl(kAtomicPointer* atomic, kPointer value)
|
|
{
|
|
kAssert(kFALSE);
|
|
return kNULL;
|
|
}
|
|
|
|
kFx(kBool) xkAtomicPointer_CompareExchangeImpl(kAtomicPointer* atomic, kPointer oldValue, kPointer value)
|
|
{
|
|
kAssert(kFALSE);
|
|
return kFALSE;
|
|
}
|
|
|
|
kFx(kPointer) xkAtomicPointer_GetImpl(kAtomicPointer* atomic)
|
|
{
|
|
kAssert(kFALSE);
|
|
return kNULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|