diff --git a/src/mem/address_space.h b/src/mem/address_space.h index d416e1c..7d4d6d9 100644 --- a/src/mem/address_space.h +++ b/src/mem/address_space.h @@ -237,6 +237,38 @@ namespace snmalloc return res; } + /** + * Aligns block to next power of 2 above size, and unused space at the end + * of the block is retained by the address space manager. + * + * This is useful for allowing the space required for alignment to be + * used, by smaller objects. + */ + template + void* reserve_with_left_over(size_t size) + { + SNMALLOC_ASSERT(size >= sizeof(void*)); + + size = bits::align_up(size, sizeof(void*)); + + size_t rsize = bits::next_pow2(size); + + auto res = reserve(rsize); + + if (res != nullptr) + { + if (rsize > size) + { + FlagLock lock(spin_lock); + add_range(pointer_offset(res, size), rsize - size); + } + + if constexpr (committed) + commit_block(res, size); + } + return res; + } + /** * Default constructor. An address-space manager constructed in this way * does not own any memory at the start and will request any that it needs diff --git a/src/mem/largealloc.h b/src/mem/largealloc.h index 4304751..c3fbdc8 100644 --- a/src/mem/largealloc.h +++ b/src/mem/largealloc.h @@ -57,7 +57,7 @@ namespace snmalloc // global state of the allocator. This is currently stored in the memory // provider, so we add this in. template - class MemoryProviderStateMixin : public PalNotificationObject + class MemoryProviderStateMixin { /** * Simple flag for checking if another instance of lazy-decommit is @@ -141,8 +141,8 @@ namespace snmalloc // Allocate permanent storage for the allocator usung temporary allocator MemoryProviderStateMixin* allocated = reinterpret_cast*>( - local.template reserve( - bits::next_pow2(sizeof(MemoryProviderStateMixin)))); + local.template reserve_with_left_over( + sizeof(MemoryProviderStateMixin))); if (allocated == nullptr) error("Failed to initialise system!"); @@ -153,8 +153,10 @@ namespace snmalloc // Register this allocator for low-memory call-backs if constexpr (pal_supports) { - allocated->PalNotificationObject::pal_notify = &(allocated->process); - PAL::register_for_low_memory_callback(allocated); + auto callback = + allocated->template alloc_chunk( + allocated); + PAL::register_for_low_memory_callback(callback); } return allocated; @@ -207,15 +209,26 @@ namespace snmalloc lazy_decommit_guard.clear(); } - /*** - * Method for callback object to perform lazy decommit. - */ - static void process(PalNotificationObject* p) + class LowMemoryNotificationObject : public PalNotificationObject { - // Unsafe downcast here. Don't want vtable and RTTI. - auto self = reinterpret_cast*>(p); - self->lazy_decommit(); - } + MemoryProviderStateMixin* memory_provider; + + /*** + * Method for callback object to perform lazy decommit. + */ + static void process(PalNotificationObject* p) + { + // Unsafe downcast here. Don't want vtable and RTTI. + auto self = reinterpret_cast(p); + self->memory_provider->lazy_decommit(); + } + + public: + LowMemoryNotificationObject( + MemoryProviderStateMixin* memory_provider) + : PalNotificationObject(&process), memory_provider(memory_provider) + {} + }; public: /** @@ -227,8 +240,8 @@ namespace snmalloc { // Cache line align size_t size = bits::align_up(sizeof(T), 64); - size = bits::next_pow2(bits::max(size, alignment)); - void* p = address_space.template reserve(size); + size = bits::max(size, alignment); + void* p = address_space.template reserve_with_left_over(size); if (p == nullptr) return nullptr; diff --git a/src/pal/pal_consts.h b/src/pal/pal_consts.h index fd79d87..58e6454 100644 --- a/src/pal/pal_consts.h +++ b/src/pal/pal_consts.h @@ -70,9 +70,13 @@ namespace snmalloc */ struct PalNotificationObject { - std::atomic pal_next; + std::atomic pal_next = nullptr; void (*pal_notify)(PalNotificationObject* self); + + PalNotificationObject(void (*pal_notify)(PalNotificationObject* self)) + : pal_notify(pal_notify) + {} }; /*** diff --git a/src/test/perf/low_memory/low-memory.cc b/src/test/perf/low_memory/low-memory.cc index 83d8742..9bdd90b 100644 --- a/src/test/perf/low_memory/low-memory.cc +++ b/src/test/perf/low_memory/low-memory.cc @@ -58,7 +58,7 @@ void advance(PalNotificationObject* unused) global_epoch++; } -PalNotificationObject update_epoch = {nullptr, &advance}; +PalNotificationObject update_epoch{&advance}; bool has_pressure() {