@@ -760,6 +760,7 @@ struct SharedFreeList(ParentAllocator,
760760 " Maximum size must accommodate a pointer." );
761761
762762 import core.atomic : atomicOp, cas;
763+ import core.internal.spinlock : SpinLock;
763764
764765 static if (minSize != chooseAtRuntime)
765766 {
@@ -854,6 +855,10 @@ struct SharedFreeList(ParentAllocator,
854855 assert (nodes);
855856 atomicOp! (" -=" )(nodes, 1 );
856857 }
858+ private void resetNodes () shared
859+ {
860+ nodes = 0 ;
861+ }
857862 private bool nodesFull () shared
858863 {
859864 return nodes >= approxMaxLength;
@@ -863,6 +868,7 @@ struct SharedFreeList(ParentAllocator,
863868 {
864869 private static void incNodes () { }
865870 private static void decNodes () { }
871+ private static void resetNodes () { }
866872 private enum bool nodesFull = false ;
867873 }
868874
@@ -924,6 +930,8 @@ struct SharedFreeList(ParentAllocator,
924930
925931 mixin (forwardToMember(" parent" , " expand" ));
926932
933+ private SpinLock lock;
934+
927935 private struct Node { Node* next; }
928936 static assert (ParentAllocator.alignment >= Node.alignof);
929937 private Node* _root;
@@ -958,18 +966,22 @@ struct SharedFreeList(ParentAllocator,
958966 assert (bytes < size_t .max / 2 );
959967 if (! freeListEligible(bytes)) return parent.allocate(bytes);
960968 if (maxSize != unbounded) bytes = max;
961- // Pop off the freelist
962- shared Node* oldRoot = void , next = void ;
963- do
969+
970+ // Try to pop off the freelist
971+ lock.lock();
972+ if (! _root)
964973 {
965- oldRoot = _root; // atomic load
966- if (! oldRoot) return allocateFresh(bytes);
967- next = oldRoot.next; // atomic load
974+ lock.unlock();
975+ return allocateFresh (bytes);
976+ }
977+ else
978+ {
979+ auto oldRoot = _root;
980+ _root = _root.next;
981+ decNodes();
982+ lock.unlock();
983+ return (cast (ubyte * ) oldRoot)[0 .. bytes];
968984 }
969- while (! cas(&_root, oldRoot, next));
970- // great, snatched the root
971- decNodes();
972- return (cast (ubyte * ) oldRoot)[0 .. bytes];
973985 }
974986
975987 private void [] allocateFresh (const size_t bytes) shared
@@ -984,14 +996,11 @@ struct SharedFreeList(ParentAllocator,
984996 if (! nodesFull && freeListEligible(b.length))
985997 {
986998 auto newRoot = cast (shared Node* ) b.ptr;
987- shared Node* oldRoot;
988- do
989- {
990- oldRoot = _root;
991- newRoot.next = oldRoot;
992- }
993- while (! cas(&_root, oldRoot, newRoot));
999+ lock.lock();
1000+ newRoot.next = _root;
1001+ _root = newRoot;
9941002 incNodes();
1003+ lock.unlock();
9951004 return true ;
9961005 }
9971006 static if (hasMember! (ParentAllocator, " deallocate" ))
@@ -1004,20 +1013,25 @@ struct SharedFreeList(ParentAllocator,
10041013 bool deallocateAll () shared
10051014 {
10061015 bool result = false ;
1016+ lock.lock();
1017+ scope (exit) lock.unlock();
10071018 static if (hasMember! (ParentAllocator, " deallocateAll" ))
10081019 {
10091020 result = parent.deallocateAll();
10101021 }
10111022 else static if (hasMember! (ParentAllocator, " deallocate" ))
10121023 {
10131024 result = true ;
1014- for (auto n = _root; n; n = n.next )
1025+ for (auto n = _root; n;)
10151026 {
1027+ auto tmp = n.next;
10161028 if (! parent.deallocate((cast (ubyte * )n)[0 .. max]))
10171029 result = false ;
1030+ n = tmp;
10181031 }
10191032 }
10201033 _root = null ;
1034+ resetNodes();
10211035 return result;
10221036 }
10231037}
@@ -1058,6 +1072,18 @@ unittest
10581072 }
10591073}
10601074
1075+ unittest
1076+ {
1077+ import std.experimental.allocator.mallocator : Mallocator;
1078+ static shared SharedFreeList! (Mallocator, 64 , 128 , 10 ) a;
1079+ auto b = a.allocate(100 );
1080+ a.deallocate(b);
1081+ assert (a.nodes == 1 );
1082+ b = [];
1083+ a.deallocateAll();
1084+ assert (a.nodes == 0 );
1085+ }
1086+
10611087unittest
10621088{
10631089 import std.experimental.allocator.mallocator : Mallocator;
0 commit comments