Make smallbuddy handle larger requests correctly (#556)

* Fail more abruptly if the bounds are not exact.

* Move bounding from Pool into Backend.

This commit makes the rounding and the bounding occur in the same
function.

* Enable smallbuddyrange to handle larger requests

The smallbuddy can now pass the larger requests up the range chain if
it cannot satisfy it itself.

* Test larger requests for meta-data.
This commit is contained in:
Matthew Parkinson
2022-09-14 12:12:06 +01:00
committed by GitHub
parent 0ea12d9725
commit 11c18082d6
6 changed files with 70 additions and 20 deletions

View File

@@ -86,6 +86,10 @@ namespace snmalloc
}
void* pb = __builtin_cheri_bounds_set_exact(a.unsafe_ptr(), size);
SNMALLOC_ASSERT(
__builtin_cheri_tag_get(pb) && "capptr_bound exactness failed.");
return CapPtr<T, BOut>::unsafe_from(static_cast<T*>(pb));
}

View File

@@ -39,7 +39,7 @@ namespace snmalloc
* does not avail itself of this degree of freedom.
*/
template<typename T>
static capptr::Arena<void>
static capptr::Alloc<void>
alloc_meta_data(LocalState* local_state, size_t size)
{
capptr::Arena<void> p;
@@ -61,9 +61,13 @@ namespace snmalloc
}
if (p == nullptr)
{
errno = ENOMEM;
return nullptr;
}
return p;
return capptr_to_user_address_control(
Aal::capptr_bound<void, capptr::bounds::AllocFull>(p, size));
}
/**

View File

@@ -174,13 +174,22 @@ namespace snmalloc
base,
length,
[this](CapPtr<void, ChunkBounds> base, size_t align, bool) {
CapPtr<void, ChunkBounds> overflow =
buddy_small
.add_block(
base.template as_reinterpret<FreeChunk<ChunkBounds>>(), align)
.template as_reinterpret<void>();
if (overflow != nullptr)
parent.dealloc_range(overflow, bits::one_at_bit(MIN_CHUNK_BITS));
if (align < MIN_CHUNK_SIZE)
{
CapPtr<void, ChunkBounds> overflow =
buddy_small
.add_block(
base.template as_reinterpret<FreeChunk<ChunkBounds>>(),
align)
.template as_reinterpret<void>();
if (overflow != nullptr)
parent.dealloc_range(
overflow, bits::one_at_bit(MIN_CHUNK_BITS));
}
else
{
parent.dealloc_range(base, align);
}
});
}
@@ -204,7 +213,8 @@ namespace snmalloc
CapPtr<void, ChunkBounds> alloc_range(size_t size)
{
SNMALLOC_ASSERT(size < MIN_CHUNK_SIZE);
if (size >= MIN_CHUNK_SIZE)
return parent.alloc_range(size);
auto result = buddy_small.remove_block(size);
if (result != nullptr)
@@ -218,8 +228,6 @@ namespace snmalloc
CapPtr<void, ChunkBounds> alloc_range_with_leftover(size_t size)
{
SNMALLOC_ASSERT(size < MIN_CHUNK_SIZE);
auto rsize = bits::next_pow2(size);
auto result = alloc_range(rsize);
@@ -236,8 +244,6 @@ namespace snmalloc
void dealloc_range(CapPtr<void, ChunkBounds> base, size_t size)
{
SNMALLOC_ASSERT(size < MIN_CHUNK_SIZE);
add_range(base, size);
}
};

View File

@@ -122,7 +122,7 @@ namespace snmalloc
{
Backend::template alloc_meta_data<void*>(local_state, size)
}
->ConceptSame<capptr::Arena<void>>;
->ConceptSame<capptr::Alloc<void>>;
}
&&requires(
LocalState& local_state,

View File

@@ -137,11 +137,8 @@ namespace snmalloc
Config::Pal::error("Failed to initialise thread local allocator.");
}
p = capptr_to_user_address_control(
Aal::capptr_bound<T, capptr::bounds::AllocFull>(
capptr::Arena<T>::unsafe_from(new (raw.unsafe_ptr())
T(std::forward<Args>(args)...)),
sizeof(T)));
p = capptr::Alloc<T>::unsafe_from(new (raw.unsafe_ptr())
T(std::forward<Args>(args)...));
FlagLock f(pool.lock);
p->list_next = pool.list;

View File

@@ -1,3 +1,5 @@
#include <array>
#include <iostream>
#include <snmalloc/snmalloc.h>
#include <test/opt.h>
#include <test/setup.h>
@@ -24,6 +26,23 @@ struct PoolBEntry : Pooled<PoolBEntry>
using PoolB = Pool<PoolBEntry, Alloc::Config>;
struct PoolLargeEntry : Pooled<PoolLargeEntry>
{
std::array<int, 2'000'000> payload;
PoolLargeEntry()
{
printf(".");
fflush(stdout);
payload[0] = 1;
printf("first %d\n", payload[0]);
payload[1'999'999] = 1;
printf("last %d\n", payload[1'999'999]);
};
};
using PoolLarge = Pool<PoolLargeEntry, Alloc::Config>;
void test_alloc()
{
auto ptr = PoolA::acquire();
@@ -116,6 +135,18 @@ void test_iterator()
PoolA::release(after_iteration_ptr);
}
void test_large()
{
printf(".");
fflush(stdout);
PoolLargeEntry* p = PoolLarge::acquire();
printf(".");
fflush(stdout);
PoolLarge::release(p);
printf(".");
fflush(stdout);
}
int main(int argc, char** argv)
{
setup();
@@ -128,10 +159,18 @@ int main(int argc, char** argv)
#endif
test_alloc();
std::cout << "test_alloc passed" << std::endl;
test_constructor();
std::cout << "test_constructor passed" << std::endl;
test_alloc_many();
std::cout << "test_alloc_many passed" << std::endl;
test_double_alloc();
std::cout << "test_double_alloc passed" << std::endl;
test_different_alloc();
std::cout << "test_different_alloc passed" << std::endl;
test_iterator();
std::cout << "test_iterator passed" << std::endl;
test_large();
std::cout << "test_large passed" << std::endl;
return 0;
}