BlockAllocator.cpp [plain text]
#include "config.h"
#include "BlockAllocator.h"
#include "MarkedBlock.h"
#include <wtf/CurrentTime.h>
namespace JSC {
BlockAllocator::BlockAllocator()
: m_numberOfFreeBlocks(0)
, m_isCurrentlyAllocating(false)
, m_blockFreeingThreadShouldQuit(false)
, m_blockFreeingThread(GCActivityCallback::s_shouldCreateGCTimer ?
createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree") : 0)
{
ASSERT(m_blockFreeingThread || !GCActivityCallback::s_shouldCreateGCTimer);
}
BlockAllocator::~BlockAllocator()
{
releaseFreeBlocks();
{
MutexLocker locker(m_freeBlockLock);
m_blockFreeingThreadShouldQuit = true;
m_freeBlockCondition.broadcast();
}
if (GCActivityCallback::s_shouldCreateGCTimer)
waitForThreadCompletion(m_blockFreeingThread);
}
void BlockAllocator::releaseFreeBlocks()
{
while (true) {
MarkedBlock* block;
{
MutexLocker locker(m_freeBlockLock);
if (!m_numberOfFreeBlocks)
block = 0;
else {
block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
ASSERT(block);
m_numberOfFreeBlocks--;
}
}
if (!block)
break;
MarkedBlock::destroy(block);
}
}
void BlockAllocator::waitForRelativeTimeWhileHoldingLock(double relative)
{
if (m_blockFreeingThreadShouldQuit)
return;
m_freeBlockCondition.timedWait(m_freeBlockLock, currentTime() + relative);
}
void BlockAllocator::waitForRelativeTime(double relative)
{
MutexLocker locker(m_freeBlockLock);
waitForRelativeTimeWhileHoldingLock(relative);
}
void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator)
{
static_cast<BlockAllocator*>(blockAllocator)->blockFreeingThreadMain();
}
void BlockAllocator::blockFreeingThreadMain()
{
while (!m_blockFreeingThreadShouldQuit) {
waitForRelativeTime(1.0);
if (m_blockFreeingThreadShouldQuit)
break;
if (m_isCurrentlyAllocating) {
m_isCurrentlyAllocating = false;
continue;
}
size_t currentNumberOfFreeBlocks = m_numberOfFreeBlocks;
if (!currentNumberOfFreeBlocks)
continue;
size_t desiredNumberOfFreeBlocks = currentNumberOfFreeBlocks / 2;
while (!m_blockFreeingThreadShouldQuit) {
MarkedBlock* block;
{
MutexLocker locker(m_freeBlockLock);
if (m_numberOfFreeBlocks <= desiredNumberOfFreeBlocks)
block = 0;
else {
block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
ASSERT(block);
m_numberOfFreeBlocks--;
}
}
if (!block)
break;
MarkedBlock::destroy(block);
}
}
}
}