@@ -27,7 +27,11 @@ namespace snmalloc
2727 friend class Pool;
2828
2929 private:
30- MPMCStack<T, PreZeroed> stack;
30+ // Queue of elements in not currently in use
31+ // Must hold lock to modify
32+ capptr::Alloc<T> front{nullptr };
33+ capptr::Alloc<T> back{nullptr };
34+
3135 FlagWord lock{};
3236 capptr::Alloc<T> list{nullptr };
3337
@@ -121,12 +125,20 @@ namespace snmalloc
121125 static T* acquire (Args&&... args)
122126 {
123127 PoolState<T>& pool = get_state ();
124- auto p = capptr::Alloc<T>::unsafe_from (pool.stack .pop ());
125-
126- if (p != nullptr )
127128 {
128- p->set_in_use ();
129- return p.unsafe_ptr ();
129+ FlagLock f (pool.lock );
130+ if (pool.front != nullptr )
131+ {
132+ auto p = pool.front ;
133+ auto next = p->next ;
134+ if (next == nullptr )
135+ {
136+ pool.back = nullptr ;
137+ }
138+ pool.front = next;
139+ p->set_in_use ();
140+ return p.unsafe_ptr ();
141+ }
130142 }
131143
132144 auto raw =
@@ -137,8 +149,8 @@ namespace snmalloc
137149 Config::Pal::error (" Failed to initialise thread local allocator." );
138150 }
139151
140- p = capptr::Alloc<T>::unsafe_from (new (raw.unsafe_ptr ())
141- T (std::forward<Args>(args)...));
152+ auto p = capptr::Alloc<T>::unsafe_from (new (raw.unsafe_ptr ())
153+ T (std::forward<Args>(args)...));
142154
143155 FlagLock f (pool.lock );
144156 p->list_next = pool.list ;
@@ -159,16 +171,23 @@ namespace snmalloc
159171 // is returned without the constructor being run, so the object is reused
160172 // without re-initialisation.
161173 p->reset_in_use ();
162- get_state (). stack . push ( p);
174+ restore (p, p);
163175 }
164176
165177 static T* extract (T* p = nullptr )
166178 {
179+ PoolState<T>& pool = get_state ();
167180 // Returns a linked list of all objects in the stack, emptying the stack.
168181 if (p == nullptr )
169- return get_state ().stack .pop_all ();
182+ {
183+ FlagLock f (pool.lock );
184+ auto result = pool.front ;
185+ pool.front = nullptr ;
186+ pool.back = nullptr ;
187+ return result.unsafe_ptr ();
188+ }
170189
171- return p->next ;
190+ return p->next . unsafe_ptr () ;
172191 }
173192
174193 /* *
@@ -178,9 +197,43 @@ namespace snmalloc
178197 */
179198 static void restore (T* first, T* last)
180199 {
181- // Pushes a linked list of objects onto the stack. Use to put a linked
182- // list returned by extract back onto the stack.
183- get_state ().stack .push (first, last);
200+ PoolState<T>& pool = get_state ();
201+ last->next = nullptr ;
202+ FlagLock f (pool.lock );
203+
204+ if (pool.front == nullptr )
205+ {
206+ pool.front = capptr::Alloc<T>::unsafe_from (first);
207+ }
208+ else
209+ {
210+ pool.back ->next = capptr::Alloc<T>::unsafe_from (first);
211+ }
212+
213+ pool.back = capptr::Alloc<T>::unsafe_from (last);
214+ }
215+
216+ /* *
217+ * Return to the pool a list of object previously retrieved by `extract`
218+ *
219+ * Do not return objects from `acquire`.
220+ */
221+ static void restore_front (T* first, T* last)
222+ {
223+ PoolState<T>& pool = get_state ();
224+ last->next = nullptr ;
225+ FlagLock f (pool.lock );
226+
227+ if (pool.front == nullptr )
228+ {
229+ pool.back = capptr::Alloc<T>::unsafe_from (last);
230+ }
231+ else
232+ {
233+ last->next = pool.front ;
234+ pool.back ->next = capptr::Alloc<T>::unsafe_from (first);
235+ }
236+ pool.front = capptr::Alloc<T>::unsafe_from (first);
184237 }
185238
186239 static T* iterate(T* p = nullptr )
@@ -200,7 +253,7 @@ namespace snmalloc
200253 static void sort ()
201254 {
202255 // Marker is used to signify free elements.
203- auto marker = reinterpret_cast <T*>(1 );
256+ auto marker = capptr::Alloc<T>:: unsafe_from ( reinterpret_cast <T*>(1 ) );
204257
205258 // Extract all the elements and mark them as free.
206259 T* curr = extract ();
@@ -222,7 +275,7 @@ namespace snmalloc
222275 {
223276 if (curr->next == marker)
224277 {
225- get_state (). stack . push ( curr);
278+ restore_front (curr, curr);
226279 }
227280 curr = iterate(curr);
228281 }
0 commit comments