#include "CopiedBlock.h"
#include "CopyWorkList.h"
#include "MarkedBlock.h"
+#include "JSCInlines.h"
#include "WeakBlock.h"
#include <wtf/CurrentTime.h>
namespace JSC {
+inline ThreadIdentifier createBlockFreeingThread(BlockAllocator* allocator)
+{
+ if (!GCActivityCallback::s_shouldCreateGCTimer)
+ return 0; // No block freeing thread.
+ ThreadIdentifier identifier = createThread(allocator->blockFreeingThreadStartFunc, allocator, "JavaScriptCore::BlockFree");
+ RELEASE_ASSERT(identifier);
+ return identifier;
+}
+
BlockAllocator::BlockAllocator()
: m_superRegion()
, m_copiedRegionSet(CopiedBlock::blockSize)
, m_numberOfEmptyRegions(0)
, m_isCurrentlyAllocating(false)
, m_blockFreeingThreadShouldQuit(false)
-#if PLATFORM(IOS)
- , m_blockFreeingThread(GCActivityCallback::s_shouldCreateGCTimer ?
- createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree") : 0)
-#else
- , m_blockFreeingThread(createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree"))
-#endif
+ , m_blockFreeingThread(createBlockFreeingThread(this))
{
-#if PLATFORM(IOS)
- RELEASE_ASSERT(m_blockFreeingThread || !GCActivityCallback::s_shouldCreateGCTimer);
-#else
- RELEASE_ASSERT(m_blockFreeingThread);
-#endif
m_regionLock.Init();
}
{
releaseFreeRegions();
{
- MutexLocker locker(m_emptyRegionConditionLock);
+ std::lock_guard<std::mutex> lock(m_emptyRegionConditionMutex);
m_blockFreeingThreadShouldQuit = true;
- m_emptyRegionCondition.broadcast();
+ m_emptyRegionCondition.notify_all();
}
-#if PLATFORM(IOS)
- if (GCActivityCallback::s_shouldCreateGCTimer)
+ if (m_blockFreeingThread)
waitForThreadCompletion(m_blockFreeingThread);
-#else
- waitForThreadCompletion(m_blockFreeingThread);
-#endif
ASSERT(allRegionSetsAreEmpty());
ASSERT(m_emptyRegions.isEmpty());
}
}
}
-void BlockAllocator::waitForRelativeTimeWhileHoldingLock(double relative)
+void BlockAllocator::waitForDuration(std::chrono::milliseconds duration)
{
- if (m_blockFreeingThreadShouldQuit)
- return;
+ std::unique_lock<std::mutex> lock(m_emptyRegionConditionMutex);
- m_emptyRegionCondition.timedWait(m_emptyRegionConditionLock, currentTime() + relative);
-}
-
-void BlockAllocator::waitForRelativeTime(double relative)
-{
// If this returns early, that's fine, so long as it doesn't do it too
// frequently. It would only be a bug if this function failed to return
// when it was asked to do so.
-
- MutexLocker locker(m_emptyRegionConditionLock);
- waitForRelativeTimeWhileHoldingLock(relative);
+ if (m_blockFreeingThreadShouldQuit)
+ return;
+
+ m_emptyRegionCondition.wait_for(lock, duration);
}
void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator)
while (!m_blockFreeingThreadShouldQuit) {
// Generally wait for one second before scavenging free blocks. This
// may return early, particularly when we're being asked to quit.
- waitForRelativeTime(1.0);
+ waitForDuration(std::chrono::seconds(1));
if (m_blockFreeingThreadShouldQuit)
break;
// Sleep until there is actually work to do rather than waking up every second to check.
{
- MutexLocker locker(m_emptyRegionConditionLock);
+ std::unique_lock<std::mutex> lock(m_emptyRegionConditionMutex);
SpinLockHolder regionLocker(&m_regionLock);
while (!m_numberOfEmptyRegions && !m_blockFreeingThreadShouldQuit) {
m_regionLock.Unlock();
- m_emptyRegionCondition.wait(m_emptyRegionConditionLock);
+ m_emptyRegionCondition.wait(lock);
m_regionLock.Lock();
}
currentNumberOfEmptyRegions = m_numberOfEmptyRegions;