blob: 0ef46acf99c232afe5198694b47a13953188e9bd [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"
#if ENABLE_OOP_NATIVE_CODEGEN
#include "JITServer/JITServer.h"
#include "PageAllocatorPool.h"
CriticalSection PageAllocatorPool::cs;
PageAllocatorPool* PageAllocatorPool::Instance = nullptr;
PageAllocatorPool::PageAllocatorPool()
:pageAllocators(&NoThrowHeapAllocator::Instance),
idleCleanupTimer(NULL),
activePageAllocatorCount(0)
{
idleCleanupTimer = CreateThreadpoolTimer(IdleCleanupRoutine, NULL, NULL);
}
PageAllocatorPool::~PageAllocatorPool()
{
AutoCriticalSection autoCS(&cs);
RemoveAll();
}
void PageAllocatorPool::Initialize()
{
Instance = HeapNewNoThrow(PageAllocatorPool);
if (Instance == nullptr)
{
Js::Throw::FatalInternalError();
}
}
void PageAllocatorPool::Shutdown()
{
AutoCriticalSection autoCS(&cs);
Assert(Instance);
if (Instance)
{
PageAllocatorPool* localInstance = Instance;
Instance = nullptr;
if (localInstance->idleCleanupTimer)
{
CloseThreadpoolTimer(localInstance->idleCleanupTimer);
}
HeapDelete(localInstance);
}
}
void PageAllocatorPool::RemoveAll()
{
Assert(cs.IsLocked());
while (!pageAllocators.Empty())
{
HeapDelete(pageAllocators.Pop());
}
}
unsigned int PageAllocatorPool::GetInactivePageAllocatorCount()
{
AutoCriticalSection autoCS(&cs);
return pageAllocators.Count();
}
PageAllocator* PageAllocatorPool::GetPageAllocator()
{
AutoCriticalSection autoCS(&cs);
PageAllocator* pageAllocator = nullptr;
if (pageAllocators.Count() > 0)
{
// TODO: OOP JIT, select the page allocator with right count of free pages
// base on some heuristic
pageAllocator = this->pageAllocators.Pop();
}
else
{
pageAllocator = HeapNew(PageAllocator, nullptr, Js::Configuration::Global.flags, PageAllocatorType_BGJIT,
AutoSystemInfo::Data.IsLowMemoryProcess() ? PageAllocator::DefaultLowMaxFreePageCount : PageAllocator::DefaultMaxFreePageCount);
}
activePageAllocatorCount++;
return pageAllocator;
}
void PageAllocatorPool::ReturnPageAllocator(PageAllocator* pageAllocator)
{
AutoCriticalSection autoCS(&cs);
if (!this->pageAllocators.PrependNoThrow(&NoThrowHeapAllocator::Instance, pageAllocator))
{
HeapDelete(pageAllocator);
}
activePageAllocatorCount--;
if (activePageAllocatorCount == 0 || GetInactivePageAllocatorCount() > (uint)Js::Configuration::Global.flags.JITServerMaxInactivePageAllocatorCount)
{
PageAllocatorPool::IdleCleanup();
}
}
void PageAllocatorPool::IdleCleanup()
{
AutoCriticalSection autoCS(&cs);
if (Instance)
{
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = Js::Configuration::Global.flags.JITServerIdleTimeout * -10000LL; // wait for JITServerIdleTimeout milliseconds to do the cleanup
if (Instance->idleCleanupTimer)
{
// Setting the timer cancels the previous timer, if any.
SetThreadpoolTimer(Instance->idleCleanupTimer, (PFILETIME)&liDueTime, 0, 0);
}
else
{
Instance->RemoveAll();
}
}
}
VOID CALLBACK PageAllocatorPool::IdleCleanupRoutine(
_Inout_ PTP_CALLBACK_INSTANCE,
_Inout_opt_ PVOID,
_Inout_ PTP_TIMER)
{
AutoCriticalSection autoCS(&cs);
if (Instance)
{
// TODO: OOP JIT, use better stragtegy to do the cleanup, like do not remove all,
// instead keep couple inactivate page allocator for next calls
Instance->RemoveAll();
}
}
#endif