Skip to content

Commit

Permalink
Make smallbuddy handle larger requests correctly (#556)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
mjp41 authored Sep 14, 2022
1 parent 0ea12d9 commit 11c1808
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 20 deletions.
4 changes: 4 additions & 0 deletions src/snmalloc/aal/aal_cheri.h
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down
8 changes: 6 additions & 2 deletions src/snmalloc/backend/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
}

/**
Expand Down
30 changes: 18 additions & 12 deletions src/snmalloc/backend_helpers/smallbuddyrange.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
}

Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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);
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/snmalloc/mem/backend_concept.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 2 additions & 5 deletions src/snmalloc/mem/pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions src/test/func/pool/pool.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <array>
#include <iostream>
#include <snmalloc/snmalloc.h>
#include <test/opt.h>
#include <test/setup.h>
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand All @@ -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;
}

0 comments on commit 11c1808

Please sign in to comment.