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:
committed by
GitHub
parent
c082a331e2
commit
8840b386bc
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{}
|
||||
};
|
||||
|
||||
/***
|
||||
|
||||
@@ -58,7 +58,7 @@ void advance(PalNotificationObject* unused)
|
||||
global_epoch++;
|
||||
}
|
||||
|
||||
PalNotificationObject update_epoch = {nullptr, &advance};
|
||||
PalNotificationObject update_epoch{&advance};
|
||||
|
||||
bool has_pressure()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user