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:
committed by
GitHub
parent
0ea12d9725
commit
11c18082d6
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user