Merge pull request #128 from microsoft/low-memory-async

Make Lazy Decomit asynchronous
This commit is contained in:
Matthew Parkinson
2020-03-03 11:29:23 +00:00
committed by GitHub
4 changed files with 161 additions and 98 deletions

View File

@@ -10,8 +10,8 @@ namespace snmalloc
{
/**
* This PAL supports low memory notifications. It must implement a
* `low_memory_epoch` method that returns a `uint64_t` of the number of
* times that a low-memory notification has been raised and an
* `register_for_low_memory_callback` method that allows callbacks to be
* registered when the platform detects low-memory and an
* `expensive_low_memory_check()` method that returns a `bool` indicating
* whether low memory conditions are still in effect.
*/
@@ -53,4 +53,63 @@ namespace snmalloc
* Default Tag ID for the Apple class
*/
static const int PALAnonDefaultID = 241;
/**
* This struct is used to represent callbacks for notification from the
* platform. It contains a next pointer as client is responsible for
* allocation as we cannot assume an allocator at this point.
**/
struct PalNotificationObject
{
std::atomic<PalNotificationObject*> pal_next;
void (*pal_notify)(PalNotificationObject* self);
};
/***
* Wrapper for managing notifications for PAL events
**/
class PalNotifier
{
/**
* List of callbacks to notify
**/
std::atomic<PalNotificationObject*> callbacks = nullptr;
public:
/**
* Register a callback object to be notified
*
* The object should never be deallocated by the client after calling
* this.
**/
void register_notification(PalNotificationObject* callback)
{
callback->pal_next = nullptr;
auto prev = &callbacks;
auto curr = prev->load();
do
{
while (curr != nullptr)
{
prev = &(curr->pal_next);
curr = prev->load();
}
} while (!prev->compare_exchange_weak(curr, callback));
}
/**
* Calls the pal_notify of all the registered objects.
**/
void notify_all()
{
PalNotificationObject* curr = callbacks;
while (curr != nullptr)
{
curr->pal_notify(curr);
curr = curr->pal_next;
}
}
};
} // namespace snmalloc

View File

@@ -20,23 +20,25 @@ namespace snmalloc
{
class PALWindows
{
/**
* The number of times that the memory pressure notification has fired.
*/
static inline std::atomic<uint64_t> pressure_epoch;
/**
* A flag indicating that we have tried to register for low-memory
* notifications.
*/
static inline std::atomic<bool> registered_for_notifications;
static inline HANDLE lowMemoryObject;
/**
* List of callbacks for low-memory notification
**/
static inline PalNotifier low_memory_callbacks;
/**
* Callback, used when the system delivers a low-memory notification. This
* simply increments an atomic counter each time the notification is raised.
* calls all the handlers registered with the PAL.
*/
static void CALLBACK low_memory(_In_ PVOID, _In_ BOOLEAN)
{
pressure_epoch++;
low_memory_callbacks.notify_all();
}
public:
@@ -76,17 +78,6 @@ namespace snmalloc
# endif
;
/**
* Counter values for the number of times that a low-pressure notification
* has been delivered. Callers should compare this with a previous value
* to see if the low memory state has been triggered since they last
* checked.
*/
uint64_t low_memory_epoch()
{
return pressure_epoch.load(std::memory_order_acquire);
}
/**
* Check whether the low memory state is still in effect. This is an
* expensive operation and should not be on any fast paths.
@@ -98,6 +89,17 @@ namespace snmalloc
return result;
}
/**
* Register callback object for low-memory notifications.
* Client is responsible for allocation, and ensuring the object is live
* for the duration of the program.
**/
static void
register_for_low_memory_callback(PalNotificationObject* callback)
{
low_memory_callbacks.register_notification(callback);
}
static void error(const char* const str)
{
puts(str);