Make debug_check_empty not use statistics
Debug_check_empty now empties the free lists, and checks it empties all the queues in the allocator. This does not require statistic tracking to work anymore. This additionally can check internal regression that cause leaks that are not the clients fault.
This commit is contained in:
@@ -875,6 +875,60 @@ namespace snmalloc
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* If result parameter is non-null, then is_empty is passsed into the
|
||||
* the location pointed to by result.
|
||||
*
|
||||
* Otherwise, asserts that it is empty.
|
||||
**/
|
||||
void debug_is_empty(bool* result)
|
||||
{
|
||||
auto test = [&result](bool value) {
|
||||
if (!value)
|
||||
{
|
||||
if (result != nullptr)
|
||||
*result = false;
|
||||
else
|
||||
error("debug_is_empty: found non-empty allocator");
|
||||
}
|
||||
};
|
||||
|
||||
// Destroy the message queue so that it has no stub message.
|
||||
Remote* p = message_queue().destroy();
|
||||
|
||||
while (p != nullptr)
|
||||
{
|
||||
Remote* n = p->non_atomic_next;
|
||||
handle_dealloc_remote(p);
|
||||
p = n;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < NUM_SMALL_CLASSES; i++)
|
||||
{
|
||||
auto prev = small_fast_free_lists[i].value;
|
||||
small_fast_free_lists[i].value = nullptr;
|
||||
while (prev != nullptr)
|
||||
{
|
||||
auto n = Metaslab::follow_next(prev);
|
||||
dealloc(prev);
|
||||
prev = n;
|
||||
}
|
||||
|
||||
test(small_classes[i].is_empty());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < NUM_MEDIUM_CLASSES; i++)
|
||||
{
|
||||
test(medium_classes[i].is_empty());
|
||||
}
|
||||
|
||||
test(super_available.is_empty());
|
||||
test(super_only_short_available.is_empty());
|
||||
|
||||
// Place the static stub message on the queue.
|
||||
init_message_queue();
|
||||
}
|
||||
|
||||
template<Boundary location>
|
||||
static uintptr_t
|
||||
external_pointer(void* p, sizeclass_t sizeclass, size_t end_point)
|
||||
@@ -1116,7 +1170,7 @@ namespace snmalloc
|
||||
if (void* replacement = Replacement(this))
|
||||
{
|
||||
return reinterpret_cast<Allocator*>(replacement)
|
||||
->template small_alloc_slow<zero_mem, allow_reserve>(sizeclass);
|
||||
->template small_alloc_inner<zero_mem, allow_reserve>(sizeclass);
|
||||
}
|
||||
|
||||
stats().sizeclass_alloc(sizeclass);
|
||||
|
||||
@@ -120,32 +120,18 @@ namespace snmalloc
|
||||
auto* alloc = Parent::iterate();
|
||||
|
||||
bool done = false;
|
||||
bool okay = true;
|
||||
|
||||
size_t non_empty_count = 0;
|
||||
while (!done)
|
||||
{
|
||||
done = true;
|
||||
alloc = Parent::iterate();
|
||||
non_empty_count = 0;
|
||||
okay = true;
|
||||
|
||||
while (alloc != nullptr)
|
||||
{
|
||||
// Destroy the message queue so that it has no stub message.
|
||||
Remote* p = alloc->message_queue().destroy();
|
||||
|
||||
while (p != nullptr)
|
||||
{
|
||||
Remote* next = p->non_atomic_next;
|
||||
alloc->handle_dealloc_remote(p);
|
||||
p = next;
|
||||
}
|
||||
|
||||
// Check that the allocator has freed all memory.
|
||||
if (!alloc->stats().is_empty())
|
||||
non_empty_count++;
|
||||
|
||||
// Place the static stub message on the queue.
|
||||
alloc->init_message_queue();
|
||||
alloc->debug_is_empty(&okay);
|
||||
|
||||
// Post all remotes, including forwarded ones. If any allocator posts,
|
||||
// repeat the loop.
|
||||
@@ -162,13 +148,18 @@ namespace snmalloc
|
||||
|
||||
if (result != nullptr)
|
||||
{
|
||||
*result = non_empty_count == 0;
|
||||
*result = okay;
|
||||
return;
|
||||
}
|
||||
|
||||
if (non_empty_count != 0)
|
||||
if (!okay)
|
||||
{
|
||||
error("debug_check_empty: found non-empty allocators");
|
||||
alloc = Parent::iterate();
|
||||
while (alloc != nullptr)
|
||||
{
|
||||
alloc->debug_is_empty(nullptr);
|
||||
alloc = Parent::iterate(alloc);
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED(result);
|
||||
|
||||
Reference in New Issue
Block a user