Make LowMemoryNotification object allocated (#281)

* Make LowMemoryNotification object allocated

This makes a separate allocation for the callback object.  This makes
it easier for different callbacks to be used.

* Add reserve_with_leftover to address_space

The address_space now supports reserving for non-power of 2 allocations
and the space that is used for rounding up is retained by the
address_space.  This means that we can more tightly pack the allocators
internal objects.
This commit is contained in:
Matthew Parkinson
2021-02-23 14:51:44 +00:00
committed by GitHub
parent c082a331e2
commit 8840b386bc
4 changed files with 66 additions and 17 deletions

View File

@@ -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<bool committed>
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<false>(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

View File

@@ -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<SNMALLOC_CONCEPT(ConceptPAL) PAL>
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<PAL>* allocated =
reinterpret_cast<MemoryProviderStateMixin<PAL>*>(
local.template reserve<true>(
bits::next_pow2(sizeof(MemoryProviderStateMixin<PAL>))));
local.template reserve_with_left_over<true>(
sizeof(MemoryProviderStateMixin<PAL>)));
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<LowMemoryNotification, PAL>)
{
allocated->PalNotificationObject::pal_notify = &(allocated->process);
PAL::register_for_low_memory_callback(allocated);
auto callback =
allocated->template alloc_chunk<LowMemoryNotificationObject, 1>(
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<MemoryProviderStateMixin<PAL>*>(p);
self->lazy_decommit();
}
MemoryProviderStateMixin<PAL>* 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<LowMemoryNotificationObject*>(p);
self->memory_provider->lazy_decommit();
}
public:
LowMemoryNotificationObject(
MemoryProviderStateMixin<PAL>* 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<true>(size);
size = bits::max(size, alignment);
void* p = address_space.template reserve_with_left_over<true>(size);
if (p == nullptr)
return nullptr;

View File

@@ -70,9 +70,13 @@ namespace snmalloc
*/
struct PalNotificationObject
{
std::atomic<PalNotificationObject*> pal_next;
std::atomic<PalNotificationObject*> pal_next = nullptr;
void (*pal_notify)(PalNotificationObject* self);
PalNotificationObject(void (*pal_notify)(PalNotificationObject* self))
: pal_notify(pal_notify)
{}
};
/***

View File

@@ -58,7 +58,7 @@ void advance(PalNotificationObject* unused)
global_epoch++;
}
PalNotificationObject update_epoch = {nullptr, &advance};
PalNotificationObject update_epoch{&advance};
bool has_pressure()
{