Implements protection on remote messages queues

This extends the freelist protection to the remote message queues. They
effectively perform doubly linked list entries for the message queue
with the enqueue operation first linking in the previous pointer, and
then then atomically setting the next.  This ensures that the visible
states always satisfy the invariant that the forward and backward
pointers are correct for any visisble object.

There is a key_global that is used for all remote deallocations. The
remote cache uses the same protection to build the temporary lists
before forwarding to the next allocator.

The mpscq is integrated into the remoteallocator as it is no longer
a reusable datastructure, but a special purpose implementation.
This commit is contained in:
Matthew Parkinson
2021-07-14 19:49:21 +01:00
committed by Matthew Parkinson
parent c58b0a5f4d
commit b501da69db
10 changed files with 295 additions and 295 deletions

View File

@@ -18,34 +18,6 @@ namespace snmalloc
sizeof(SlabLink) <= MIN_ALLOC_SIZE,
"Need to be able to pack a SlabLink into any free small alloc");
/**
* This struct is used inside FreeListBuilder to account for the
* alignment space that is wasted in sizeof.
*
* This is part of Metaslab abstraction.
*/
struct MetaslabEnd
{
/**
* The number of deallocation required until we hit a slow path. This
* counts down in two different ways that are handled the same on the
* fast path. The first is
* - deallocations until the slab has sufficient entries to be considered
* useful to allocate from. This could be as low as 1, or when we have
* a requirement for entropy then it could be much higher.
* - deallocations until the slab is completely unused. This is needed
* to be detected, so that the statistics can be kept up to date, and
* potentially return memory to the a global pool of slabs/chunks.
*/
uint16_t needed = 0;
/**
* Flag that is used to indicate that the slab is currently not active.
* I.e. it is not in a CoreAllocator cache for the appropriate sizeclass.
*/
bool sleeping = false;
};
// The Metaslab represent the status of a single slab.
// This can be either a short or a standard slab.
class alignas(CACHELINE_SIZE) Metaslab : public SlabLink
@@ -59,19 +31,38 @@ namespace snmalloc
* Spare 32bits are used for the fields in MetaslabEnd.
*/
#ifdef CHECK_CLIENT
FreeListBuilder<true, MetaslabEnd> free_queue;
FreeListBuilder<true> free_queue;
#else
FreeListBuilder<false, MetaslabEnd> free_queue;
FreeListBuilder<false> free_queue;
#endif
/**
* The number of deallocation required until we hit a slow path. This
* counts down in two different ways that are handled the same on the
* fast path. The first is
* - deallocations until the slab has sufficient entries to be considered
* useful to allocate from. This could be as low as 1, or when we have
* a requirement for entropy then it could be much higher.
* - deallocations until the slab is completely unused. This is needed
* to be detected, so that the statistics can be kept up to date, and
* potentially return memory to the a global pool of slabs/chunks.
*/
uint16_t needed_ = 0;
/**
* Flag that is used to indicate that the slab is currently not active.
* I.e. it is not in a CoreAllocator cache for the appropriate sizeclass.
*/
bool sleeping_ = false;
uint16_t& needed()
{
return free_queue.s.needed;
return needed_;
}
bool& sleeping()
{
return free_queue.s.sleeping;
return sleeping_;
}
/**
@@ -151,13 +142,17 @@ namespace snmalloc
LocalEntropy& entropy,
sizeclass_t sizeclass)
{
FreeListKey key(entropy.get_constant_key());
FreeListIter tmp_fl;
meta->free_queue.close(tmp_fl, entropy);
auto p = tmp_fl.take(entropy);
meta->free_queue.close(tmp_fl, key);
auto p = tmp_fl.take(key);
fast_free_list = tmp_fl;
#ifdef CHECK_CLIENT
entropy.refresh_bits();
#else
UNUSED(entropy);
#endif
// Treat stealing the free list as allocating it all.