/**
* 该模块定义了一些原子操作。
* License: BSD
* Authors: Lucifer (786325481@QQ.com)
* Copyright: Copyright (C) 2008 Lucifer. All rights reserved.
*/
/**
* The atomic module is intended to provide some basic support for lock-free
* concurrent programming. Some common operations are defined, each of which
* may be performed using the specified memory barrier or a less granular
* barrier if the hardware does not support the version requested. This
* model is based on a design by Alexander Terekhov as outlined in
*
* this thread. Another useful reference for memory ordering on modern
* architectures is this
* article by Paul McKenney.
*
* Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved.
* License: BSD style: $(LICENSE)
* Authors: Sean Kelly
*/
module system.threading.Atomic;
import system.Traits;
/*
version(Windows)
{
private extern(Windows) int InterlockedIncrement(ref int);
private extern(Windows) int InterlockedDecrement(ref int);
private extern(Windows) int InterlockedExchange(ref int, int);
private extern(Windows) int InterlockedExchangeAdd(ref int, int);
private extern(C) void* InterlockedExchangePointer(ref void*, void*);
private extern(Windows) int InterlockedCompareExchange(ref int, int, int);
private extern(C) void* InterlockedCompareExchangePointer(ref void*, void*, void*);
}
*/
/**
* Memory synchronization flag. If the supplied option is not available on the
* current platform then a stronger method will be used instead.
*/
public enum MemorySemantics
{
Raw, /// not sequenced
HoistLoadBarrier, /// hoist-load barrier
HoistStoreBarrier, /// hoist-store barrier
SinkLoadBarrier, /// sink-load barrier
SinkStoreBarrier, /// sink-store barrier
Acquire, /// hoist-load + hoist-store barrier
Release, /// sink-load + sink-store barrier
FullFence /// fully sequenced (acquire + release)
}
//Internal Type Checking
private template IsValidAtomicType(T)
{
const bool IsValidAtomicType = T.sizeof == byte.sizeof ||
T.sizeof == short.sizeof ||
T.sizeof == int.sizeof ||
T.sizeof == long.sizeof;
}
private template IsValidNumericType(T)
{
const bool IsValidNumericType = IsIntegerType!(T) ||
IsPointerType!(T) ;
}
private template IsHoistOperation(MemorySemantics ms)
{
const bool IsHoistOperation = ms == MemorySemantics.HoistLoadBarrier ||
ms == MemorySemantics.HoistStoreBarrier ||
ms == MemorySemantics.Acquire ||
ms == MemorySemantics.FullFence;
}
private template IsSinkOperation(MemorySemantics ms)
{
const bool IsSinkOperation = ms == MemorySemantics.SinkLoadBarrier ||
ms == MemorySemantics.SinkStoreBarrier ||
ms == MemorySemantics.Release ||
ms == MemorySemantics.FullFence;
}
// x86 Value Requirements
// NOTE: Strictly speaking, the x86 supports atomic operations on
// unaligned values. However, this is far slower than the
// common case, so such behavior should be prohibited.
private template AtomicValueIsProperlyAligned(T)
{
bool AtomicValueIsProperlyAligned(size_t address)
{
return address % T.sizeof == 0;
}
}
//x86 Synchronization Requirements
// NOTE: While x86 loads have acquire semantics for stores, it appears
// that independent loads may be reordered by some processors
// (notably the AMD64). This implies that the hoist-load barrier
// op requires an ordering instruction, which also extends this
// requirement to acquire ops (though hoist-store should not need
// one if support is added for this later). However, since no
// modern architectures will reorder dependent loads to occur
// before the load they depend on (except the Alpha), raw loads
// are actually a possible means of ordering specific sequences
// of loads in some instances. The original atomic<>
// implementation provides a 'ddhlb' ordering specifier for
// data-dependent loads to handle this situation, but as there
// are no plans to support the Alpha there is no reason to add
// that option here.
//
// For reference, the old behavior (acquire semantics for loads)
// required a memory barrier if: ms == MemorySemantics.FullFence || IsSinkOperation!(ms)
private template NeedLoadBarrier(MemorySemantics ms)
{
const bool NeedLoadBarrier = ms != MemorySemantics.Raw;
}
// NOTE: x86 stores implicitly have release semantics so a membar is only
// necessary on acquires.
private template NeedStoreBarrier(MemorySemantics ms)
{
const bool NeedStoreBarrier = ms == MemorySemantics.FullFence || IsHoistOperation!(ms) ;
}
version(D_InlineAsm_X86)
{
version(X86)
{
pragma( msg, "system.threading.Atomic: using IA-32 inline asm" );
version = Has32BitOps;
version = Has64BitCAS;
}
version(X86_64)
{
pragma( msg, "system.threading.Atomic: using AMD64 inline asm" );
version = Has64BitOps;
}
/**
* Supported MemorySemantics values:
* MemorySemantics.Raw
* MemorySemantics.HoistLoadBarrier
* MemorySemantics.Acquire
* MemorySemantics.FullFence
*/
template atomicLoad( T, MemorySemantics ms = MemorySemantics.FullFence )
{
static assert( ms == MemorySemantics.Raw ||
ms == MemorySemantics.HoistLoadBarrier ||
ms == MemorySemantics.Acquire ||
ms == MemorySemantics.FullFence,
"ms must be one of: MemorySemantics.Raw, MemorySemantics.HoistLoadBarrier, MemorySemantics.Acquire, MemorySemantics.FullFence.");
/**
* Refreshes the contents of 'value' from main memory. This operation is
* both lock-free and atomic.
*
* Params:
* value = The value to load. This value must be properly aligned.
*
* Returns:
* The loaded value.
*/
T atomicLoad(ref T value)
in
{
assert( AtomicValueIsProperlyAligned!(T)(cast(size_t)(&value)) );
}
body
{
static if( T.sizeof == byte.sizeof )
{
//1 Byte Load
static if( NeedLoadBarrier!(ms) )
{
asm
{
mov DL, 42;
mov AL, 42;
mov ECX, value;
lock;
cmpxchg [ECX], DL;
}
}
else
{
synchronized
{
return value;
}
}
}//static if( T.sizeof == byte.sizeof )
else static if( T.sizeof == short.sizeof )
{
//2 Byte Load
static if( NeedLoadBarrier!(ms) )
{
asm
{
mov DX, 42;
mov AX, 42;
mov ECX, value;
lock;
cmpxchg [ECX], DX;
}
}
else
{
synchronized
{
return value;
}
}
}//else static if( T.sizeof == short.sizeof )
else static if( T.sizeof == int.sizeof )
{
//4 Byte Load
static if( NeedLoadBarrier!(ms) )
{
asm
{
mov EDX, 42;
mov EAX, 42;
mov ECX, value;
lock;
cmpxchg [ECX], EDX;
}
}
else
{
synchronized
{
return value;
}
}
}//else static if( T.sizeof == int.sizeof )
else static if( T.sizeof == long.sizeof )
{
//8 Byte Load
version(Has64BitOps)
{
//8 Byte Load on 64-Bit Processor
static if( NeedLoadBarrier!(ms) )
{
asm
{
mov RAX, value;
lock;
mov RAX, [RAX];
}
}
else
{
synchronized
{
return value;
}
}
}//version(Has64BitOps)
else
{
//8 Byte Load on 32-Bit Processor
static assert(false, "This operation is only available on 64-bit platforms.");
}
}//else static if( T.sizeof == long.sizeof )
else
{
//Not a 1, 2, 4, or 8 Byte Type
static assert(false, "Invalid template type specified.");
}
}
}
/**
* Supported MemorySemantics values:
* MemorySemantics.Raw
* MemorySemantics.SinkStoreBarrier
* MemorySemantics.Acquire
* MemorySemantics.Release
* MemorySemantics.FullFence
*/
template atomicStore(T, MemorySemantics ms = MemorySemantics.FullFence )
{
static assert( ms == MemorySemantics.Raw ||
ms == MemorySemantics.SinkStoreBarrier ||
ms == MemorySemantics.Acquire ||
ms == MemorySemantics.Release ||
ms == MemorySemantics.FullFence,
"ms must be one of: MemorySemantics.Raw, MemorySemantics.SinkStoreBarrier, MemorySemantics.Acquire, MemorySemantics.Acquire, MemorySemantics.Release, MemorySemantics.FullFence." );
/**
* Stores 'newval' to the memory referenced by 'value'. This operation
* is both lock-free and atomic.
*
* Params:
* value = The destination variable.
* newValue = The value to store.
*/
void atomicStore(ref T value, T newValue)
in
{
assert( AtomicValueIsProperlyAligned!(T)(cast(size_t)(&value)) );
}
body
{
static if( T.sizeof == byte.sizeof )
{
//1 Byte Store
static if( NeedStoreBarrier!(ms) )
{
asm
{
mov EAX, value;
mov DL, newValue;
lock;
xchg [EAX], DL;
}
}
else
{
asm
{
mov EAX, val;
mov DL, newval;
mov [EAX], DL;
}
}
}
else static if( T.sizeof == short.sizeof )
{
//2 Byte Store
static if( NeedStoreBarrier!(ms) )
{
asm
{
mov EAX, value;
mov DX, newValue;
lock;
xchg [EAX], DX;
}
}
else
{
mov EAX, value;
mov DX, newValue;
xchg [EAX], DX;
}
}
else static if( T.sizeof == int.sizeof )
{
//4 Byte Store
static if( NeedStoreBarrier!(ms) )
{
asm
{
mov EAX, value;
mov EDX, newValue;
lock;
xchg [EAX], EDX;
}
}
else
{
asm
{
mov EAX, value;
mov EDX, newValue;
xchg [EAX], EDX;
}
}
}
else static if( T.sizeof == long.sizeof )
{
//8 Byte Store
version( Has64BitOps )
{
//8 Byte Store on 64-Bit Processor
static if( NeedStoreBarrier!(ms) )
{
asm
{
mov RAX, value;
mov RBX, newValue;
lock;
xchg [RAX], RBX;
}
}
else
{
asm
{
mov RAX, value;
mov RDX, newValue;
xchg [RAX], RDX;
}
}
}
else
{
//8 Byte Store on 32-Bit Processor
static assert(false, "This operation is only available on 64-bit platforms.");
}
}
else
{
//Not a 1, 2, 4, or 8 Byte Type
static assert(false, "Invalid template type specified.");
}
}
}
/**
* Supported MemorySemantics values:
* MemorySemantics.Raw
* MemorySemantics.SinkStoreBarrier
* MemorySemantics.Acquire
* MemorySemantics.Release
* MemorySemantics.FullFence
*/
template atomicCAS(T, MemorySemantics ms = MemorySemantics.FullFence)
{
static assert( ms == MemorySemantics.Raw ||
ms == MemorySemantics.SinkStoreBarrier ||
ms == MemorySemantics.Acquire ||
ms == MemorySemantics.Release ||
ms == MemorySemantics.FullFence,
"ms must be one of: MemorySemantics.Raw, MemorySemantics.SinkStoreBarrier, MemorySemantics.Acquire, MemorySemantics.Acquire, MemorySemantics.Release, MemorySemantics.FullFence." );
/**
* Stores 'newValue' to the memory referenced by 'value' if val is equal to
* 'equalTo'. This operation is both lock-free and atomic.
*
* Params:
* value = The destination variable.
* newValue = The value to store.
* equalTo = The comparison value.
*
* Returns:
* true if the store occurred, false if not.
*/
bool atomicCAS(ref T value, T newValue, T equalTo)
in
{
// NOTE: 32 bit x86 systems support 8 byte CAS, which only requires
// 4 byte alignment, so use size_t as the align type here.
static if( T.sizeof > size_t.sizeof )
assert( AtomicValueIsProperlyAligned!(size_t)( cast(size_t) (&value) ) );
else
assert( AtomicValueIsProperlyAligned!(T)( cast(size_t) (&value) ) );
}
body
{
static if( T.sizeof == byte.sizeof )
{
//1 Byte CAS
asm
{
mov DL, newValue;
mov AL, equalTo;
mov ECX, value;
lock;
cmpxchg [ECX], DL;
setz AL;
}
}
else static if( T.sizeof == short.sizeof )
{
//2 Byte CAS
asm
{
mov DX, newValue;
mov AX, equalTo;
mov ECX, value;
lock;
cmpxchg [ECX], DX;
setz AL;
}
}
else static if( T.sizeof == int.sizeof )
{
//4 Byte CAS
asm
{
mov EDX, newValue;
mov EAX, equalTo;
mov ECX, value;
lock;
cmpxchg [ECX], EDX;
setz AL;
}
}
else static if( T.sizeof == long.sizeof )
{
//8 Byte CAS
version(Has64BitOps)
{
//8 Byte CAS on 64-bit Processor
asm
{
mov RDX, newValue;
mov RAX, equalTo;
mov RCX, value;
lock;
cmpxchg [RCX], RDX;
setz AL;
}
}
else version(Has64BitCAS)
{
//8 Byte CAS on 32-Bit Processor
asm
{
push EDI;
push EBX;
lea EDI, newValue;
mov EBX, [EDI];
mov ECX, 4[EDI];
lea EDI, equalTo;
mov EAX, [EDI];
mov EDX, 4[EDI];
mov EDI, value;
lock;
cmpxch8b [EDI];
setz AL;
pop EBX;
pop EDI;
}
}
}
else
{
//Not a 1, 2, 4, or 8 Byte Type
static assert(false, "Invalid template type specified.");
}
}
}
/**
* Supported MemorySemantics values:
* MemorySemantics.Raw
* MemorySemantics.SinkStoreBarrier
* MemorySemantics.Acquire
* MemorySemantics.Release
* MemorySemantics.FullFence
*/
template atomicIncrement(T, MemorySemantics ms = MemorySemantics.FullFence)
{
// NOTE: This operation is only valid for integer or pointer types
static assert( IsValidNumericType!(T) );
static assert( ms == MemorySemantics.Raw ||
ms == MemorySemantics.SinkStoreBarrier ||
ms == MemorySemantics.Acquire ||
ms == MemorySemantics.Release ||
ms == MemorySemantics.FullFence,
"ms must be one of: MemorySemantics.Raw, MemorySemantics.SinkStoreBarrier, MemorySemantics.Acquire, MemorySemantics.Acquire, MemorySemantics.Release, MemorySemantics.FullFence." );
/**
* This operation is only legal for built-in value and pointer types,
* and is equivalent to an atomic "value = value + 1" operation. This
* function exists to facilitate use of the optimized increment
* instructions provided by some architecures. If no such instruction
* exists on the target platform then the behavior will perform the
* operation using more traditional means. This operation is both
* lock-free and atomic.
*
* Params:
* value = The value to increment.
*
* Returns:
* The result of an atomicLoad of val immediately following the
* increment operation. This value is not required to be equal to the
* newly stored value. Thus, competing writes are allowed to occur
* between the increment and successive load operation.
*/
T atomicIncrement(ref T value)
in
{
assert( AtomicTypeIsProperlyAligned!(T)(cast(size_t)(&value)) );
}
body
{
static if( T.sizeof == byte.sizeof )
{
//1 Byte Increment
asm
{
mov EAX, value;
lock;
inc [EAX];
mov AL, [EAX];
}
}
else static if( T.sizeof == short.sizeof )
{
//2 Byte Increment
asm
{
mov EAX, value;
lock;
inc short ptr [EAX];
mov AX, [EAX];
}
}
else static if( T.sizeof == int.sizeof )
{
//4 Byte Increment
asm
{
mov EAX, value;
lock;
inc int ptr [EAX];
mov EAX, [EAX];
}
}
else static if( T.sizeof == long.sizeof )
{
//8 Byte Increment
version(Has64BitOps)
{
//8 Byte Increment on 64-Bit Processor
asm
{
mov RAX, value;
lock;
inc qword ptr [RAX];
mov RAX, [RAX];
}
}
else
{
//8 Byte Increment on 32-Bit Processor
static assert(false, "This operation is only available on 64-bit platforms.");
}
}
else
{
//Not a 1, 2, 4, or 8 Byte Type
static assert(false, "Invalid template type specified.");
}
}
}
/**
* Supported MemorySemantics values:
* MemorySemantics.Raw
* MemorySemantics.SinkStoreBarrier
* MemorySemantics.Acquire
* MemorySemantics.Release
* MemorySemantics.FullFence
*/
template atomicDecrement(T, MemorySemantics ms = MemorySemantics.FullFence)
{
//NOTE: This operation is only valid for integer or pointer types
static assert( IsValidNumericType!(T) );
static assert( ms == MemorySemantics.Raw ||
ms == MemorySemantics.SinkStoreBarrier ||
ms == MemorySemantics.Acquire ||
ms == MemorySemantics.Release ||
ms == MemorySemantics.FullFence,
"ms must be one of: MemorySemantics.Raw, MemorySemantics.SinkStoreBarrier, MemorySemantics.Acquire, MemorySemantics.Acquire, MemorySemantics.Release, MemorySemantics.FullFence." );
/**
* This operation is only legal for built-in value and pointer types,
* and is equivalent to an atomic "value = value - 1" operation. This
* function exists to facilitate use of the optimized decrement
* instructions provided by some architecures. If no such instruction
* exists on the target platform then the behavior will perform the
* operation using more traditional means. This operation is both
* lock-free and atomic.
*
* Params:
* value = The value to decrement.
*
* Returns:
* The result of an atomicLoad of val immediately following the
* increment operation. This value is not required to be equal to the
* newly stored value. Thus, competing writes are allowed to occur
* between the increment and successive load operation.
*/
T atomicDecrement(ref T value)
in
{
assert( AtomicValueIsProperlyAligned!(T)(cast(size_t)(&value)) );
}
body
{
static if( T.sizeof == byte.sizeof )
{
//1 Byte Decrement
asm
{
mov EAX, value;
lock;
dec [EAX];
mov AL, [EAX];
}
}
else static if( T.sizeof == short.sizeof )
{
//2 Byte Decrement
asm
{
mov EAX, value;
lock;
dec short ptr [EAX];
mov AX, [EAX];
}
}
else static if( T.sizeof == int.sizeof )
{
//4 Byte Decrement
asm
{
mov EAX, value;
lock;
dec int ptr [EAX];
mov EAX, [EAX];
}
}
else static if( T.sizeof == long.sizeof )
{
//8 Byte Decrement
version(Has64BitOps)
{
// 8 Byte Decrement on 64-Bit Processor
asm
{
mov RAX, value;
lock;
dec qword ptr [RAX];
mov RAX, [RAX];
}
}
else
{
//8 Byte Decrement on 32-Bit Processor
static assert(false, "This operation is only available on 64-bit platforms.");
}
}
else
{
static assert(false, "Invalid template type specified.");
}
}
}
/**
* Supported MemorySemantics values:
* MemorySemantics.Raw
* MemorySemantics.SinkStoreBarrier
* MemorySemantics.Acquire
* MemorySemantics.Release
* MemorySemantics.FullFence
*/
template atomicAdd(T, MemorySemantics ms = MemorySemantics.FullFence)
{
static assert( IsValidNumericType!(T) );
static assert( ms == MemorySemantics.Raw ||
ms == MemorySemantics.SinkStoreBarrier ||
ms == MemorySemantics.Acquire ||
ms == MemorySemantics.Release ||
ms == MemorySemantics.FullFence,
"ms must be one of: MemorySemantics.Raw, MemorySemantics.SinkStoreBarrier, MemorySemantics.Acquire, MemorySemantics.Acquire, MemorySemantics.Release, MemorySemantics.FullFence." );
/**
* Adds two integers and replaces the first integer with the sum, as an atomic operation.
*/
void atomicAdd(ref T value, T newValue)
in
{
assert( AtomicValueIsProperlyAligned!(T)(cast(size_t)(&value)) );
}
body
{
static if( T.sizeof == byte.sizeof )
{
//1 Byte Add
asm
{
mov EAX, value;
mov DL, newValue;
lock;
xadd [EAX], DL;
}
}
else static if( T.sizeof == short.sizeof )
{
//2 Byte Add
asm
{
mov EAX, value;
mov DX, newValue;
lock;
xadd [EAX], DX;
}
}
else static if( T.sizeof == int.sizeof )
{
//4 Byte Add
asm
{
mov EAX, value;
mov EDX, newValue;
lock;
xadd [EAX], EDX;
}
}
else static if( T.sizeof == long.sizeof )
{
//8 Byte Add
version(Has64BitOps)
{
asm
{
mov RAX, value;
mov RDX, newValue;
lock;
xadd [RAX], RDX;
}
}
else
{
//8 Byte Store on 32-Bit Processor
static assert(false, "This operation is only available on 64-bit platforms.");
}
}
else
{
//Not a 1, 2, 4, or 8 Byte Type
static assert(false, "Invalid template type specified.");
}
}
}
}
else version(LDC)
{
/*******************************
* LDC Atomics Implementation
*******************************/
import ldc.intrinsics;
/*******************************
* Atomic Load
*******************************/
public enum MemorySemantics
{
Raw, /// not sequenced
HoistLoadBarrier, /// hoist-load barrier
HoistStoreBarrier, /// hoist-store barrier
SinkLoadBarrier, /// sink-load barrier
SinkStoreBarrier, /// sink-store barrier
Acquire, /// hoist-load + hoist-store barrier
Release, /// sink-load + sink-store barrier
FullFence /// fully sequenced (acquire + release)
}
template atomicLoad(T, MemorySemantics ms = MemorySemantics.FullFence)
{
T atomicLoad(ref T val)
{
llvm_memory_barrier(
ms == MemorySemantics.HoistLoadBarrier || ms == MemorySemantics.Acquire || ms == MemorySemantics.FullFence,
ms == MemorySemantics.HoistStoreBarrier || ms == MemorySemantics.Acquir || ms == MemorySemantics.FullFence,
ms == MemorySemantics.SinkLoadBarrier || ms == MemorySemantics.Release || ms == MemorySemantics.FullFence,
ms == MemorySemantics.SinkStoreBarrier || ms == MemorySemantics.Release || ms == MemorySemantics.FullFence,
false);
static if (IsPointerType!(T))
{
return cast(T)llvm_atomic_load_add!(size_t)(cast(size_t*)&val, 0);
}
else static if (is(T == bool))
{
return llvm_atomic_load_add!(ubyte)(cast(ubyte*)&val, cast(ubyte)0) ? 1 : 0;
}
else
{
return llvm_atomic_load_add!(T)(&val, cast(T)0);
}
}
}
/***************
* Atomic Store
***************/
template atomicStore(T, MemorySemantics ms = MemorySemantics.FullFence)
{
void atomicStore( ref T val, T newval )
{
llvm_memory_barrier(
ms == MemorySemantics.HoistLoadBarrier || ms == MemorySemantics.Acquire || ms == MemorySemantics.FullFence,
ms == MemorySemantics.HoistStoreBarrier || ms == MemorySemantics.Acquir || ms == MemorySemantics.FullFence,
ms == MemorySemantics.SinkLoadBarrier || ms == MemorySemantics.Release || ms == MemorySemantics.FullFence,
ms == MemorySemantics.SinkStoreBarrier || ms == MemorySemantics.Release || ms == MemorySemantics.FullFence,
false);
static if (IsPointerType!(T))
{
llvm_atomic_swap!(size_t)(cast(size_t*)&val, cast(size_t)newval);
}
else static if (is(T == bool))
{
llvm_atomic_swap!(ubyte)(cast(ubyte*)&val, newval?1:0);
}
else
{
llvm_atomic_swap!(T)(&val, newval);
}
}
}
/********************
* Atomic CAS
********************/
template atomicCAS(T, MemorySemantics ms = MemorySemantics.FullFence)
{
bool atomicStoreIf( ref T val, T newval, T equalTo )
{
llvm_memory_barrier(
ms == MemorySemantics.HoistLoadBarrier || ms == MemorySemantics.Acquire || ms == MemorySemantics.FullFence,
ms == MemorySemantics.HoistStoreBarrier || ms == MemorySemantics.Acquir || ms == MemorySemantics.FullFence,
ms == MemorySemantics.SinkLoadBarrier || ms == MemorySemantics.Release || ms == MemorySemantics.FullFence,
ms == MemorySemantics.SinkStoreBarrier || ms == MemorySemantics.Release || ms == MemorySemantics.FullFence,
false);
T oldval = void;
static if (IsPointerType!(T))
{
oldval = cast(T)llvm_atomic_cmp_swap!(size_t)(cast(size_t*)&val, cast(size_t)equalTo, cast(size_t)newval);
}
else static if (is(T == bool))
{
oldval = llvm_atomic_cmp_swap!(ubyte)(cast(ubyte*)&val, equalTo?1:0, newval?1:0)?0:1;
}
else
{
oldval = llvm_atomic_cmp_swap!(T)(&val, equalTo, newval);
}
return oldval == equalTo;
}
}
/*****************************
* Atomic Increment
*****************************/
template atomicIncrement(T, MemorySemantics ms = MemorySemantics.FullFence)
{
//
// NOTE: This operation is only valid for integer or pointer types
//
static assert( IsValidNumericType!(T) );
T atomicIncrement( ref T val )
{
static if (IsPointerType!(T))
{
llvm_atomic_load_add!(size_t)(cast(size_t*)&val, 1);
}
else
{
llvm_atomic_load_add!(T)(&val, cast(T)1);
}
return val;
}
}
/***************************
* Atomic Decrement
***************************/
template atomicDecrement( msync ms = msync.seq, T )
{
//
// NOTE: This operation is only valid for integer or pointer types
//
static assert( IsValidNumericType!(T) );
T atomicDecrement( ref T val )
{
static if (IsPointerType!(T))
{
llvm_atomic_load_sub!(size_t)(cast(size_t*)&val, 1);
}
else
{
llvm_atomic_load_sub!(T)(&val, cast(T)1);
}
return val;
}
}
}