Skip to content

Commit 5877da2

Browse files
committed
Safely set parent for shared objects
1 parent b0188dd commit 5877da2

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

std/experimental/allocator/building_blocks/affix_allocator.d

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
7171

7272
static if (is(Allocator == RCIAllocator) || is(Allocator == RCISharedAllocator))
7373
{
74+
static if (is(Allocator == RCISharedAllocator))
75+
{
76+
shared bool nullParent = true;
77+
shared bool nullParentWait = true;
78+
}
79+
7480
@nogc nothrow pure @safe
7581
Allocator parent()
7682
{
@@ -104,9 +110,22 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
104110
}
105111
else
106112
{
107-
auto fn = (() @trusted =>
108-
cast(RCIAllocator function() @nogc nothrow pure @safe)(&wrapProcAllocatorObject))();
109-
_parent = fn();
113+
import core.atomic : cas, atomicLoad, atomicStore;
114+
115+
if ((() @trusted => cas(&nullParent, true, false))())
116+
{
117+
auto fn = (() @trusted =>
118+
cast(RCISharedAllocator function() @nogc nothrow pure @safe)
119+
(&wrapProcAllocatorObject))();
120+
_parent = fn();
121+
// Notify other threads that the parent has been set
122+
atomicStore(nullParentWait, false);
123+
}
124+
else
125+
{
126+
// Busy-wait for the parent to be set
127+
while(atomicLoad(nullParentWait)) {}
128+
}
110129
}
111130
}
112131

@@ -600,3 +619,10 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
600619
assert(a.parent.bytesUsed == 100 + uint.sizeof);
601620
assert((() nothrow @nogc => a.deallocate(b))());
602621
}
622+
623+
@system unittest
624+
{
625+
import std.experimental.allocator : RCISharedAllocator;
626+
627+
AffixAllocator!(RCISharedAllocator, size_t) a;
628+
}

0 commit comments

Comments
 (0)