Metaslab: SlabLink field rather than parent class
Introduce Metaslab::from_link(SlabLink*) to encapsulate the "container of" dance. Note that Metaslab was not a standard layout type prior to this change (since both SlabLink and Metaslab defined non-static data members), and so the reinterpret_cast<>s replaced here with ::from_link() were UB, but everyone lays out classes as one expects so it was fine in practice. Most of the uses of ::from_link() are already guarded by checks that the link pointer is not nullptr, but in src/mem/corealloc.h:/debug_is_empty_impl we shift to testing the link pointer explicitly before converting to the metaslab. Despite that Metaslab is now standard layout, we still don't fall back to the inter-convertibility of a standard layout class and its first[*] data member since we're going to want to put a common initial sequence across Metaslab and ChunkRecord and the SlabLink isn't likely to be in it.
This commit is contained in:
committed by
Nathaniel Wesley Filardo
parent
c70c23ad74
commit
dac1ba6a6c
@@ -304,7 +304,7 @@ namespace snmalloc
|
||||
while (curr != nullptr)
|
||||
{
|
||||
auto nxt = curr->get_next();
|
||||
auto meta = reinterpret_cast<Metaslab*>(curr);
|
||||
auto meta = Metaslab::from_link(curr);
|
||||
if (meta->needed() == 0)
|
||||
{
|
||||
prev->pop();
|
||||
@@ -348,7 +348,7 @@ namespace snmalloc
|
||||
// Wake slab up.
|
||||
meta->set_not_sleeping(sizeclass);
|
||||
|
||||
alloc_classes[sizeclass].insert(meta);
|
||||
alloc_classes[sizeclass].insert(&meta->link);
|
||||
alloc_classes[sizeclass].length++;
|
||||
|
||||
#ifdef SNMALLOC_TRACING
|
||||
@@ -593,7 +593,7 @@ namespace snmalloc
|
||||
auto& sl = alloc_classes[sizeclass];
|
||||
if (likely(!(sl.is_empty())))
|
||||
{
|
||||
auto meta = reinterpret_cast<Metaslab*>(sl.pop());
|
||||
auto meta = Metaslab::from_link(sl.pop());
|
||||
// Drop length of sl, and empty count if it was empty.
|
||||
alloc_classes[sizeclass].length--;
|
||||
if (meta->needed() == 0)
|
||||
@@ -736,17 +736,18 @@ namespace snmalloc
|
||||
auto test = [&result](auto& queue) {
|
||||
if (!queue.is_empty())
|
||||
{
|
||||
auto curr = reinterpret_cast<Metaslab*>(queue.get_next());
|
||||
auto curr = queue.get_next();
|
||||
while (curr != nullptr)
|
||||
{
|
||||
if (curr->needed() != 0)
|
||||
auto currmeta = Metaslab::from_link(curr);
|
||||
if (currmeta->needed() != 0)
|
||||
{
|
||||
if (result != nullptr)
|
||||
*result = false;
|
||||
else
|
||||
error("debug_is_empty: found non-empty allocator");
|
||||
}
|
||||
curr = reinterpret_cast<Metaslab*>(curr->get_next());
|
||||
curr = currmeta->link.get_next();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,10 +16,19 @@ namespace snmalloc
|
||||
|
||||
// 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
|
||||
class alignas(CACHELINE_SIZE) Metaslab
|
||||
{
|
||||
public:
|
||||
constexpr Metaslab() : SlabLink(true) {}
|
||||
// TODO: Annotate with CHERI subobject unbound for pointer arithmetic
|
||||
SlabLink link;
|
||||
|
||||
constexpr Metaslab() : link(true) {}
|
||||
|
||||
/**
|
||||
* Metaslab::link points at another link field. To get the actual Metaslab,
|
||||
* use this encapsulation of the container-of logic.
|
||||
*/
|
||||
static Metaslab* from_link(SlabLink* ptr);
|
||||
|
||||
/**
|
||||
* Data-structure for building the free list for this slab.
|
||||
@@ -160,6 +169,12 @@ namespace snmalloc
|
||||
}
|
||||
};
|
||||
|
||||
Metaslab* Metaslab::from_link(SlabLink* lptr)
|
||||
{
|
||||
return pointer_offset_signed<Metaslab>(
|
||||
lptr, -static_cast<ptrdiff_t>(offsetof(Metaslab, link)));
|
||||
}
|
||||
|
||||
struct RemoteAllocator;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user