From 58ce068257d4ba050ccc403c1a74d7479859418c Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Thu, 28 Sep 2023 23:43:25 +0100 Subject: [PATCH 1/8] Template construction of Pool elements The Pool class is used by verona-rt. The recent changes made this less nice to consume as an API. This change makes the construction logic a template parameter to the Pool. This enables standard allocation to be used from Verona. --- src/snmalloc/mem/corealloc.h | 36 ++++++++++++++- src/snmalloc/mem/pool.h | 88 ++++++++++-------------------------- src/snmalloc/mem/pooled.h | 2 +- src/test/func/pool/pool.cc | 18 ++++---- 4 files changed, 68 insertions(+), 76 deletions(-) diff --git a/src/snmalloc/mem/corealloc.h b/src/snmalloc/mem/corealloc.h index cb70f5d77..7a67ad34f 100644 --- a/src/snmalloc/mem/corealloc.h +++ b/src/snmalloc/mem/corealloc.h @@ -1015,9 +1015,43 @@ namespace snmalloc } }; + template + class ConstructCoreAlloc + { + using CA = CoreAllocator; + + public: + static capptr::Alloc make(LocalCache* lc) + { + size_t size = sizeof(CA); + size_t round_sizeof = Aal::capptr_size_round(size); + size_t request_size = bits::next_pow2(round_sizeof); + size_t spare = request_size - round_sizeof; + + auto raw = + Config::Backend::template alloc_meta_data(nullptr, request_size); + + if (raw == nullptr) + { + Config::Pal::error("Failed to initialise thread local allocator."); + } + + capptr::Alloc spare_start = pointer_offset(raw, round_sizeof); + Range r{spare_start, spare}; + + auto p = capptr::Alloc::unsafe_from( + new (raw.unsafe_ptr()) CA(r, lc)); + + // Remove excess from the permissions. + p = Aal::capptr_bound(p, round_sizeof); + return p; + } + }; + /** * Use this alias to access the pool of allocators throughout snmalloc. */ template - using AllocPool = Pool, Config, Config::pool>; + using AllocPool = + Pool, ConstructCoreAlloc, Config::pool>; } // namespace snmalloc diff --git a/src/snmalloc/mem/pool.h b/src/snmalloc/mem/pool.h index cbcbdb12d..3fa4c2f1c 100644 --- a/src/snmalloc/mem/pool.h +++ b/src/snmalloc/mem/pool.h @@ -22,7 +22,7 @@ namespace snmalloc { template< typename TT, - SNMALLOC_CONCEPT(IsConfig) Config, + typename Construct, PoolState& get_state()> friend class Pool; @@ -45,50 +45,10 @@ namespace snmalloc * SingletonPoolState::pool is the default provider for the PoolState within * the Pool class. */ - template + template class SingletonPoolState { - /** - * SFINAE helper. Matched only if `T` implements `ensure_init`. Calls it - * if it exists. - */ - template - SNMALLOC_FAST_PATH static auto call_ensure_init(SharedStateHandle_*, int) - -> decltype(SharedStateHandle_::ensure_init()) - { - static_assert( - std::is_same::value, - "SFINAE parameter, should only be used with Config"); - SharedStateHandle_::ensure_init(); - } - - /** - * SFINAE helper. Matched only if `T` does not implement `ensure_init`. - * Does nothing if called. - */ - template - SNMALLOC_FAST_PATH static auto call_ensure_init(SharedStateHandle_*, long) - { - static_assert( - std::is_same::value, - "SFINAE parameter, should only be used with Config"); - } - - /** - * Call `Config::ensure_init()` if it is implemented, do nothing - * otherwise. - */ - SNMALLOC_FAST_PATH static void ensure_init() - { - call_ensure_init(nullptr, 0); - } - - static void make_pool(PoolState*) noexcept - { - ensure_init(); - // Default initializer already called on PoolState, no need to use - // placement new. - } + static void make_pool(PoolState*) noexcept {} public: /** @@ -101,6 +61,23 @@ namespace snmalloc } }; + /** + * @brief Default construct helper for the pool. Just uses `new`. This can't + * be used by the allocator pool as it has not created memory yet. + * + * @tparam T + */ + template + class DefaultConstruct + { + public: + template + static capptr::Alloc make(Args&&... args) + { + return capptr::Alloc::unsafe_from(new T(std::forward(args)...)); + } + }; + /** * Wrapper class to access a pool of a particular type of object. * @@ -116,8 +93,8 @@ namespace snmalloc */ template< typename T, - SNMALLOC_CONCEPT(IsConfig) Config, - PoolState& get_state() = SingletonPoolState::pool> + typename ConstructT = DefaultConstruct, + PoolState& get_state() = SingletonPoolState::pool> class Pool { public: @@ -141,26 +118,7 @@ namespace snmalloc } } - size_t request_size = bits::next_pow2(sizeof(T)); - size_t round_sizeof = Aal::capptr_size_round(sizeof(T)); - size_t spare = request_size - round_sizeof; - - auto raw = - Config::Backend::template alloc_meta_data(nullptr, request_size); - - if (raw == nullptr) - { - Config::Pal::error("Failed to initialise thread local allocator."); - } - - capptr::Alloc spare_start = pointer_offset(raw, round_sizeof); - Range r{spare_start, spare}; - - auto p = capptr::Alloc::unsafe_from( - new (raw.unsafe_ptr()) T(r, std::forward(args)...)); - - // Remove excess from the permissions. - p = Aal::capptr_bound(p, round_sizeof); + auto p = ConstructT::make(std::forward(args)...); FlagLock f(pool.lock); p->list_next = pool.list; diff --git a/src/snmalloc/mem/pooled.h b/src/snmalloc/mem/pooled.h index 7fb0ce33e..0b9df03e2 100644 --- a/src/snmalloc/mem/pooled.h +++ b/src/snmalloc/mem/pooled.h @@ -29,7 +29,7 @@ namespace snmalloc public: template< typename TT, - SNMALLOC_CONCEPT(IsConfig) Config, + typename Construct, PoolState& get_state()> friend class Pool; diff --git a/src/test/func/pool/pool.cc b/src/test/func/pool/pool.cc index 600118d58..ba2b9ef89 100644 --- a/src/test/func/pool/pool.cc +++ b/src/test/func/pool/pool.cc @@ -11,26 +11,26 @@ struct PoolAEntry : Pooled { int field; - PoolAEntry(Range&) : field(1){}; + PoolAEntry() : field(1){}; }; -using PoolA = Pool; +using PoolA = Pool; struct PoolBEntry : Pooled { int field; - PoolBEntry(Range&) : field(0){}; - PoolBEntry(Range&, int f) : field(f){}; + PoolBEntry() : field(0){}; + PoolBEntry(int f) : field(f){}; }; -using PoolB = Pool; +using PoolB = Pool; struct PoolLargeEntry : Pooled { std::array payload; - PoolLargeEntry(Range&) + PoolLargeEntry() { printf("."); fflush(stdout); @@ -41,18 +41,18 @@ struct PoolLargeEntry : Pooled }; }; -using PoolLarge = Pool; +using PoolLarge = Pool; template struct PoolSortEntry : Pooled> { int field; - PoolSortEntry(Range&, int f) : field(f){}; + PoolSortEntry(int f) : field(f){}; }; template -using PoolSort = Pool, Alloc::Config>; +using PoolSort = Pool>; void test_alloc() { From 78f76ec40b79e34acd972a30b902f4cae8b4321d Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Thu, 28 Sep 2023 23:44:52 +0100 Subject: [PATCH 2/8] Clangformat --- src/snmalloc/mem/corealloc.h | 3 +-- src/snmalloc/mem/pool.h | 9 +++------ src/snmalloc/mem/pooled.h | 5 +---- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/snmalloc/mem/corealloc.h b/src/snmalloc/mem/corealloc.h index 7a67ad34f..135d76b0b 100644 --- a/src/snmalloc/mem/corealloc.h +++ b/src/snmalloc/mem/corealloc.h @@ -1039,8 +1039,7 @@ namespace snmalloc capptr::Alloc spare_start = pointer_offset(raw, round_sizeof); Range r{spare_start, spare}; - auto p = capptr::Alloc::unsafe_from( - new (raw.unsafe_ptr()) CA(r, lc)); + auto p = capptr::Alloc::unsafe_from(new (raw.unsafe_ptr()) CA(r, lc)); // Remove excess from the permissions. p = Aal::capptr_bound(p, round_sizeof); diff --git a/src/snmalloc/mem/pool.h b/src/snmalloc/mem/pool.h index 3fa4c2f1c..f906bbe7b 100644 --- a/src/snmalloc/mem/pool.h +++ b/src/snmalloc/mem/pool.h @@ -20,10 +20,7 @@ namespace snmalloc template class PoolState { - template< - typename TT, - typename Construct, - PoolState& get_state()> + template& get_state()> friend class Pool; private: @@ -64,8 +61,8 @@ namespace snmalloc /** * @brief Default construct helper for the pool. Just uses `new`. This can't * be used by the allocator pool as it has not created memory yet. - * - * @tparam T + * + * @tparam T */ template class DefaultConstruct diff --git a/src/snmalloc/mem/pooled.h b/src/snmalloc/mem/pooled.h index 0b9df03e2..43a2795d7 100644 --- a/src/snmalloc/mem/pooled.h +++ b/src/snmalloc/mem/pooled.h @@ -27,10 +27,7 @@ namespace snmalloc class Pooled { public: - template< - typename TT, - typename Construct, - PoolState& get_state()> + template& get_state()> friend class Pool; /// Used by the pool for chaining together entries when not in use. From 644e5463463174de36754fcece57c7317b88e903 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 2 Oct 2023 15:09:58 +0100 Subject: [PATCH 3/8] Drop parameter from acquire Pool::acquire took a list of parameters to initialise the object that it constructed. But if this was serviced from the pool, the parameter would be ignored. This is not an ideal API. This PR removes the ability to pass a parameter. --- src/snmalloc/mem/corealloc.h | 7 +++---- src/snmalloc/mem/localalloc.h | 2 +- src/snmalloc/mem/pool.h | 10 ++++------ src/test/func/pool/pool.cc | 16 +++++----------- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/snmalloc/mem/corealloc.h b/src/snmalloc/mem/corealloc.h index 135d76b0b..d26837b8d 100644 --- a/src/snmalloc/mem/corealloc.h +++ b/src/snmalloc/mem/corealloc.h @@ -621,8 +621,7 @@ namespace snmalloc template< typename Config_ = Config, typename = std::enable_if_t> - CoreAllocator(Range& spare, LocalCache* cache) - : attached_cache(cache) + CoreAllocator(Range& spare) { init(spare); } @@ -1021,7 +1020,7 @@ namespace snmalloc using CA = CoreAllocator; public: - static capptr::Alloc make(LocalCache* lc) + static capptr::Alloc make() { size_t size = sizeof(CA); size_t round_sizeof = Aal::capptr_size_round(size); @@ -1039,7 +1038,7 @@ namespace snmalloc capptr::Alloc spare_start = pointer_offset(raw, round_sizeof); Range r{spare_start, spare}; - auto p = capptr::Alloc::unsafe_from(new (raw.unsafe_ptr()) CA(r, lc)); + auto p = capptr::Alloc::unsafe_from(new (raw.unsafe_ptr()) CA(r)); // Remove excess from the permissions. p = Aal::capptr_bound(p, round_sizeof); diff --git a/src/snmalloc/mem/localalloc.h b/src/snmalloc/mem/localalloc.h index 75be56ecc..e26243a9b 100644 --- a/src/snmalloc/mem/localalloc.h +++ b/src/snmalloc/mem/localalloc.h @@ -393,7 +393,7 @@ namespace snmalloc // Initialise the global allocator structures ensure_init(); // Grab an allocator for this thread. - init(AllocPool::acquire(&(this->local_cache))); + init(AllocPool::acquire()); } // Return all state in the fast allocator and release the underlying diff --git a/src/snmalloc/mem/pool.h b/src/snmalloc/mem/pool.h index f906bbe7b..0033fd456 100644 --- a/src/snmalloc/mem/pool.h +++ b/src/snmalloc/mem/pool.h @@ -68,10 +68,9 @@ namespace snmalloc class DefaultConstruct { public: - template - static capptr::Alloc make(Args&&... args) + static capptr::Alloc make() { - return capptr::Alloc::unsafe_from(new T(std::forward(args)...)); + return capptr::Alloc::unsafe_from(new T()); } }; @@ -95,8 +94,7 @@ namespace snmalloc class Pool { public: - template - static T* acquire(Args&&... args) + static T* acquire() { PoolState& pool = get_state(); { @@ -115,7 +113,7 @@ namespace snmalloc } } - auto p = ConstructT::make(std::forward(args)...); + auto p = ConstructT::make(); FlagLock f(pool.lock); p->list_next = pool.list; diff --git a/src/test/func/pool/pool.cc b/src/test/func/pool/pool.cc index ba2b9ef89..2ed960a45 100644 --- a/src/test/func/pool/pool.cc +++ b/src/test/func/pool/pool.cc @@ -21,7 +21,6 @@ struct PoolBEntry : Pooled int field; PoolBEntry() : field(0){}; - PoolBEntry(int f) : field(f){}; }; using PoolB = Pool; @@ -48,7 +47,7 @@ struct PoolSortEntry : Pooled> { int field; - PoolSortEntry(int f) : field(f){}; + PoolSortEntry() : field(1){}; }; template @@ -73,13 +72,8 @@ void test_constructor() SNMALLOC_CHECK(ptr2 != nullptr); SNMALLOC_CHECK(ptr2->field == 0); - auto ptr3 = PoolB::acquire(1); - SNMALLOC_CHECK(ptr3 != nullptr); - SNMALLOC_CHECK(ptr3->field == 1); - PoolA::release(ptr1); PoolB::release(ptr2); - PoolB::release(ptr3); } void test_alloc_many() @@ -181,8 +175,8 @@ void test_sort() // This test checks that `sort` puts the elements in the right order, // so it is the same as if they had been allocated in that order. - auto a1 = PoolSort::acquire(1); - auto a2 = PoolSort::acquire(1); + auto a1 = PoolSort::acquire(); + auto a2 = PoolSort::acquire(); auto position1 = position(a1); auto position2 = position(a2); @@ -201,8 +195,8 @@ void test_sort() PoolSort::sort(); - auto b1 = PoolSort::acquire(1); - auto b2 = PoolSort::acquire(1); + auto b1 = PoolSort::acquire(); + auto b2 = PoolSort::acquire(); SNMALLOC_CHECK(position1 == position(b1)); SNMALLOC_CHECK(position2 == position(b2)); From a0cbe79e2c7fad53c9cf3a377c4d8062696a3404 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 2 Oct 2023 15:30:39 +0100 Subject: [PATCH 4/8] Add concept --- src/snmalloc/mem/pool.h | 7 +++++-- src/snmalloc/mem/pooled.h | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/snmalloc/mem/pool.h b/src/snmalloc/mem/pool.h index 0033fd456..8db58eccc 100644 --- a/src/snmalloc/mem/pool.h +++ b/src/snmalloc/mem/pool.h @@ -20,7 +20,10 @@ namespace snmalloc template class PoolState { - template& get_state()> + template< + typename TT, + SNMALLOC_CONCEPT(Constructable) Construct, + PoolState& get_state()> friend class Pool; private: @@ -89,7 +92,7 @@ namespace snmalloc */ template< typename T, - typename ConstructT = DefaultConstruct, + SNMALLOC_CONCEPT(Constructable) ConstructT = DefaultConstruct, PoolState& get_state() = SingletonPoolState::pool> class Pool { diff --git a/src/snmalloc/mem/pooled.h b/src/snmalloc/mem/pooled.h index 43a2795d7..0adb7ec31 100644 --- a/src/snmalloc/mem/pooled.h +++ b/src/snmalloc/mem/pooled.h @@ -15,6 +15,16 @@ namespace snmalloc template class PoolState; +#ifdef __cpp_concepts + template + concept Constructable = requires() + { + { + C::make() + } -> ConceptSame>; + }; +#endif // __cpp_concepts + /** * Required to be implemented by all types that are pooled. * @@ -27,7 +37,10 @@ namespace snmalloc class Pooled { public: - template& get_state()> + template< + typename TT, + SNMALLOC_CONCEPT(Constructable) Construct, + PoolState& get_state()> friend class Pool; /// Used by the pool for chaining together entries when not in use. From e25291d4a01cb7ce3b7e7c03542d8aff2d8c870e Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 2 Oct 2023 15:31:42 +0100 Subject: [PATCH 5/8] Clangformat --- src/snmalloc/mem/pooled.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/snmalloc/mem/pooled.h b/src/snmalloc/mem/pooled.h index 0adb7ec31..4e7c76884 100644 --- a/src/snmalloc/mem/pooled.h +++ b/src/snmalloc/mem/pooled.h @@ -17,12 +17,11 @@ namespace snmalloc #ifdef __cpp_concepts template - concept Constructable = requires() - { - { - C::make() - } -> ConceptSame>; - }; + concept Constructable = requires() { + { + C::make() + } -> ConceptSame>; + }; #endif // __cpp_concepts /** From 6da23952f3b4abe2f2ae6ac1388bf493b3250305 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 2 Oct 2023 15:38:30 +0100 Subject: [PATCH 6/8] Fix CHERI test --- src/test/func/cheri/cheri.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/func/cheri/cheri.cc b/src/test/func/cheri/cheri.cc index 4efaec6b7..09dce5fed 100644 --- a/src/test/func/cheri/cheri.cc +++ b/src/test/func/cheri/cheri.cc @@ -134,7 +134,7 @@ int main() std::is_same_v>); LocalCache lc{&StandardConfig::unused_remote}; - auto* ca = AllocPool::acquire(&lc); + auto* ca = AllocPool::acquire(); SNMALLOC_CHECK(cap_len_is(ca, sizeof(*ca))); SNMALLOC_CHECK(cap_vmem_perm_is(ca, false)); From 8fe23fa8a2558a1d094135c41e29ac65a67c0d86 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 2 Oct 2023 15:46:51 +0100 Subject: [PATCH 7/8] Fix CHERI test again --- src/test/func/cheri/cheri.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/func/cheri/cheri.cc b/src/test/func/cheri/cheri.cc index 09dce5fed..cde8be071 100644 --- a/src/test/func/cheri/cheri.cc +++ b/src/test/func/cheri/cheri.cc @@ -133,7 +133,6 @@ int main() static_assert( std::is_same_v>); - LocalCache lc{&StandardConfig::unused_remote}; auto* ca = AllocPool::acquire(); SNMALLOC_CHECK(cap_len_is(ca, sizeof(*ca))); From f9c225db95f4bf6246496ccce053c8d4967e363f Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Tue, 3 Oct 2023 14:34:01 +0100 Subject: [PATCH 8/8] Update src/snmalloc/mem/corealloc.h --- src/snmalloc/mem/corealloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snmalloc/mem/corealloc.h b/src/snmalloc/mem/corealloc.h index d26837b8d..e2a99f2c5 100644 --- a/src/snmalloc/mem/corealloc.h +++ b/src/snmalloc/mem/corealloc.h @@ -1040,7 +1040,7 @@ namespace snmalloc auto p = capptr::Alloc::unsafe_from(new (raw.unsafe_ptr()) CA(r)); - // Remove excess from the permissions. + // Remove excess from the bounds. p = Aal::capptr_bound(p, round_sizeof); return p; }