Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 102 additions & 90 deletions src/core/atomic.d
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,16 @@ in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
}

/**
* Stores 'writeThis' to the memory referenced by 'here' if the value
* referenced by 'here' is equal to 'ifThis'. This operation is both
* lock-free and atomic.
* Performs either compare-and-set or compare-and-swap (or exchange).
*
* There are two categories of overloads in this template:
* the first one does a simple compare-and-set, and returns a boolean if the
* operation happened. The value this is written (`writeThis`) can be an rvalue.
* the second category does a compare-and-swap, or compare-and-exchange,
* and expects `writeThis` to be a pointer type, where the previous value
* of `here` will be written.
*
* This operation is both lock-free and atomic.
*
* Params:
* here = The address of the destination variable.
Expand All @@ -276,112 +283,117 @@ in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
* Returns:
* true if the store occurred, false if not.
*/
bool cas(MemoryOrder succ = MemoryOrder.seq,MemoryOrder fail = MemoryOrder.seq,T,V1,V2)(T* here, V1 ifThis, V2 writeThis) pure nothrow @nogc @trusted
if (!is(T == shared) && is(T : V1))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
template cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq)
{
// resolve implicit conversions
T arg1 = ifThis;
T arg2 = writeThis;

static if (__traits(isFloating, T))
/// Compare-and-set for non-shared values
bool cas(T, V1, V2)(T* here, V1 ifThis, V2 writeThis) pure nothrow @nogc @trusted
if (!is(T == shared) && is(T : V1))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
alias IntTy = IntForFloat!T;
return atomicCompareExchangeStrongNoResult!(succ, fail)(cast(IntTy*)here, *cast(IntTy*)&arg1, *cast(IntTy*)&arg2);
// resolve implicit conversions
T arg1 = ifThis;
T arg2 = writeThis;

static if (__traits(isFloating, T))
{
alias IntTy = IntForFloat!T;
return atomicCompareExchangeStrongNoResult!(succ, fail)(
cast(IntTy*)here, *cast(IntTy*)&arg1, *cast(IntTy*)&arg2);
}
else
return atomicCompareExchangeStrongNoResult!(succ, fail)(here, arg1, arg2);
}
else
return atomicCompareExchangeStrongNoResult!(succ, fail)(here, arg1, arg2);
}

/// Ditto
bool cas(MemoryOrder succ = MemoryOrder.seq,MemoryOrder fail = MemoryOrder.seq,T,V1,V2)(shared(T)* here, V1 ifThis, V2 writeThis) pure nothrow @nogc @trusted
/// Compare-and-set for shared value type
bool cas(T, V1, V2)(shared(T)* here, V1 ifThis, V2 writeThis) pure nothrow @nogc @trusted
if (!is(T == class) && (is(T : V1) || is(shared T : V1)))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
static if (is (V1 == shared U1, U1))
alias Thunk1 = U1;
else
alias Thunk1 = V1;
static if (is (V2 == shared U2, U2))
alias Thunk2 = U2;
else
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
import core.internal.traits : hasUnsharedIndirections;
static assert(!hasUnsharedIndirections!V2, "Copying `" ~ V2.stringof ~ "* writeThis` to `" ~ shared(T).stringof ~ "* here` would violate shared.");
alias Thunk2 = V2;
static if (is (V1 == shared U1, U1))
alias Thunk1 = U1;
else
alias Thunk1 = V1;
static if (is (V2 == shared U2, U2))
alias Thunk2 = U2;
else
{
import core.internal.traits : hasUnsharedIndirections;
static assert(!hasUnsharedIndirections!V2,
"Copying `" ~ V2.stringof ~ "* writeThis` to `" ~
shared(T).stringof ~ "* here` would violate shared.");
alias Thunk2 = V2;
}
return cas(cast(T*)here, *cast(Thunk1*)&ifThis, *cast(Thunk2*)&writeThis);
}
return cas!(succ, fail)(cast(T*)here, *cast(Thunk1*)&ifThis, *cast(Thunk2*)&writeThis);
}

/// Ditto
bool cas(MemoryOrder succ = MemoryOrder.seq,MemoryOrder fail = MemoryOrder.seq,T,V1,V2)(shared(T)* here, shared(V1) ifThis, shared(V2) writeThis) pure nothrow @nogc @trusted
/// Compare-and-set for `shared` reference type (`class`)
bool cas(T, V1, V2)(shared(T)* here, shared(V1) ifThis, shared(V2) writeThis)
pure nothrow @nogc @trusted
if (is(T == class))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
return atomicCompareExchangeStrongNoResult!(succ, fail)(cast(T*)here, cast(V1)ifThis, cast(V2)writeThis);
}
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
return atomicCompareExchangeStrongNoResult!(succ, fail)(
cast(T*)here, cast(V1)ifThis, cast(V2)writeThis);
}

/**
* Stores 'writeThis' to the memory referenced by 'here' if the value
* referenced by 'here' is equal to the value referenced by 'ifThis'.
* The prior value referenced by 'here' is written to `ifThis` and
* returned to the user. This operation is both lock-free and atomic.
*
* Params:
* here = The address of the destination variable.
* writeThis = The value to store.
* ifThis = The address of the value to compare, and receives the prior value of `here` as output.
*
* Returns:
* true if the store occurred, false if not.
*/
bool cas(MemoryOrder succ = MemoryOrder.seq,MemoryOrder fail = MemoryOrder.seq,T,V)(T* here, T* ifThis, V writeThis) pure nothrow @nogc @trusted
/// Compare-and-exchange for non-`shared` types
bool cas(T, V)(T* here, T* ifThis, V writeThis) pure nothrow @nogc @trusted
if (!is(T == shared) && !is(V == shared))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
// resolve implicit conversions
T arg1 = writeThis;

static if (__traits(isFloating, T))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
alias IntTy = IntForFloat!T;
return atomicCompareExchangeStrong!(succ, fail)(cast(IntTy*)here, cast(IntTy*)ifThis, *cast(IntTy*)&writeThis);
// resolve implicit conversions
T arg1 = writeThis;

static if (__traits(isFloating, T))
{
alias IntTy = IntForFloat!T;
return atomicCompareExchangeStrong!(succ, fail)(
cast(IntTy*)here, cast(IntTy*)ifThis, *cast(IntTy*)&writeThis);
}
else
return atomicCompareExchangeStrong!(succ, fail)(here, ifThis, writeThis);
}
else
return atomicCompareExchangeStrong!(succ, fail)(here, ifThis, writeThis);
}

/// Ditto
bool cas(MemoryOrder succ = MemoryOrder.seq,MemoryOrder fail = MemoryOrder.seq,T,V1,V2)(shared(T)* here, V1* ifThis, V2 writeThis) pure nothrow @nogc @trusted
/// Compare and exchange for mixed-`shared`ness types
bool cas(T, V1, V2)(shared(T)* here, V1* ifThis, V2 writeThis) pure nothrow @nogc @trusted
if (!is(T == class) && (is(T : V1) || is(shared T : V1)))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
static if (is (V1 == shared U1, U1))
alias Thunk1 = U1;
else
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
import core.internal.traits : hasUnsharedIndirections;
static assert(!hasUnsharedIndirections!V1, "Copying `" ~ shared(T).stringof ~ "* here` to `" ~ V1.stringof ~ "* ifThis` would violate shared.");
alias Thunk1 = V1;
}
static if (is (V2 == shared U2, U2))
alias Thunk2 = U2;
else
{
import core.internal.traits : hasUnsharedIndirections;
static assert(!hasUnsharedIndirections!V2, "Copying `" ~ V2.stringof ~ "* writeThis` to `" ~ shared(T).stringof ~ "* here` would violate shared.");
alias Thunk2 = V2;
static if (is (V1 == shared U1, U1))
alias Thunk1 = U1;
else
{
import core.internal.traits : hasUnsharedIndirections;
static assert(!hasUnsharedIndirections!V1,
"Copying `" ~ shared(T).stringof ~ "* here` to `" ~
V1.stringof ~ "* ifThis` would violate shared.");
alias Thunk1 = V1;
}
static if (is (V2 == shared U2, U2))
alias Thunk2 = U2;
else
{
import core.internal.traits : hasUnsharedIndirections;
static assert(!hasUnsharedIndirections!V2,
"Copying `" ~ V2.stringof ~ "* writeThis` to `" ~
shared(T).stringof ~ "* here` would violate shared.");
alias Thunk2 = V2;
}
static assert (is(T : Thunk1),
"Mismatching types for `here` and `ifThis`: `" ~
shared(T).stringof ~ "` and `" ~ V1.stringof ~ "`.");
return cas(cast(T*)here, cast(Thunk1*)ifThis, *cast(Thunk2*)&writeThis);
}
static assert (is(T : Thunk1), "Mismatching types for `here` and `ifThis`: `" ~ shared(T).stringof ~ "` and `" ~ V1.stringof ~ "`.");
return cas!(succ, fail)(cast(T*)here, cast(Thunk1*)ifThis, *cast(Thunk2*)&writeThis);
}

/// Ditto
bool cas(MemoryOrder succ = MemoryOrder.seq,MemoryOrder fail = MemoryOrder.seq,T,V)(shared(T)* here, shared(T)* ifThis, shared(V) writeThis) pure nothrow @nogc @trusted
/// Compare-and-exchange for `class`
bool cas(T, V)(shared(T)* here, shared(T)* ifThis, shared(V) writeThis)
pure nothrow @nogc @trusted
if (is(T == class))
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
return atomicCompareExchangeStrong!(succ, fail)(cast(T*)here, cast(T*)ifThis, cast(V)writeThis);
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
return atomicCompareExchangeStrong!(succ, fail)(
cast(T*)here, cast(T*)ifThis, cast(V)writeThis);
}
}

/**
Expand Down