This source file includes following definitions.
- create
- run
- m_task
- create
- performTask
- m_nextFireTime
- setFiredFunction
- setFireInterval
- stop
- isActive
- fireTime
- fire
- m_nestedCount
- m_context
- setWorkerGlobalScope
- run
- runDebuggerTask
- run
- runCleanupTasks
- terminate
- postTask
- postTaskAndTerminate
- postDebuggerTask
#include "config.h"
#include "core/workers/WorkerRunLoop.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerThread.h"
#include "platform/PlatformThreadData.h"
#include "platform/SharedTimer.h"
#include "platform/ThreadTimers.h"
#include "platform/heap/ThreadState.h"
#include "wtf/CurrentTime.h"
namespace WebCore {
class WorkerRunLoopTask : public blink::WebThread::Task {
WTF_MAKE_NONCOPYABLE(WorkerRunLoopTask); WTF_MAKE_FAST_ALLOCATED;
public:
static PassOwnPtr<WorkerRunLoopTask> create(const WorkerRunLoop& runLoop, PassOwnPtr<ExecutionContextTask> task)
{
return adoptPtr(new WorkerRunLoopTask(runLoop, task));
}
virtual ~WorkerRunLoopTask() { }
virtual void run() OVERRIDE
{
WorkerGlobalScope* workerGlobalScope = m_runLoop.context();
if ((!workerGlobalScope->isClosing() && !m_runLoop.terminated()) || m_task->isCleanupTask())
m_task->performTask(workerGlobalScope);
}
private:
WorkerRunLoopTask(const WorkerRunLoop& runLoop, PassOwnPtr<ExecutionContextTask> task)
: m_runLoop(runLoop)
, m_task(task)
{
}
const WorkerRunLoop& m_runLoop;
OwnPtr<ExecutionContextTask> m_task;
};
class TickleDebuggerQueueTask FINAL : public ExecutionContextTask {
public:
static PassOwnPtr<TickleDebuggerQueueTask> create(WorkerRunLoop* loop)
{
return adoptPtr(new TickleDebuggerQueueTask(loop));
}
virtual void performTask(ExecutionContext* context) OVERRIDE
{
ASSERT(context->isWorkerGlobalScope());
m_loop->runDebuggerTask(WorkerRunLoop::DontWaitForMessage);
}
private:
explicit TickleDebuggerQueueTask(WorkerRunLoop* loop) : m_loop(loop) { }
WorkerRunLoop* m_loop;
};
class WorkerSharedTimer : public SharedTimer {
public:
WorkerSharedTimer()
: m_sharedTimerFunction(0)
, m_nextFireTime(0)
{
}
virtual void setFiredFunction(void (*function)()) { m_sharedTimerFunction = function; }
virtual void setFireInterval(double interval) { m_nextFireTime = interval + currentTime(); }
virtual void stop() { m_nextFireTime = 0; }
bool isActive() { return m_sharedTimerFunction && m_nextFireTime; }
double fireTime() { return m_nextFireTime; }
void fire() { m_sharedTimerFunction(); }
private:
void (*m_sharedTimerFunction)();
double m_nextFireTime;
};
WorkerRunLoop::WorkerRunLoop()
: m_sharedTimer(adoptPtr(new WorkerSharedTimer))
, m_context(0)
, m_nestedCount(0)
{
}
WorkerRunLoop::~WorkerRunLoop()
{
ASSERT(!m_nestedCount);
}
class RunLoopSetup {
WTF_MAKE_NONCOPYABLE(RunLoopSetup);
public:
RunLoopSetup(WorkerRunLoop& runLoop, WorkerGlobalScope* context)
: m_runLoop(runLoop)
, m_context(context)
{
if (!m_runLoop.m_nestedCount)
PlatformThreadData::current().threadTimers().setSharedTimer(m_runLoop.m_sharedTimer.get());
m_runLoop.m_nestedCount++;
InspectorInstrumentation::willEnterNestedRunLoop(m_context);
}
~RunLoopSetup()
{
m_runLoop.m_nestedCount--;
if (!m_runLoop.m_nestedCount)
PlatformThreadData::current().threadTimers().setSharedTimer(0);
InspectorInstrumentation::didLeaveNestedRunLoop(m_context);
}
private:
WorkerRunLoop& m_runLoop;
WorkerGlobalScope* m_context;
};
void WorkerRunLoop::setWorkerGlobalScope(WorkerGlobalScope* context)
{
ASSERT(!m_context);
ASSERT(context);
m_context = context;
}
void WorkerRunLoop::run()
{
ASSERT(m_context);
RunLoopSetup setup(*this, m_context);
MessageQueueWaitResult result;
do {
ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack);
result = run(m_messageQueue, WaitForMessage);
} while (result != MessageQueueTerminated);
runCleanupTasks();
}
MessageQueueWaitResult WorkerRunLoop::runDebuggerTask(WaitMode waitMode)
{
ASSERT(m_context);
RunLoopSetup setup(*this, m_context);
return run(m_debuggerMessageQueue, waitMode);
}
MessageQueueWaitResult WorkerRunLoop::run(MessageQueue<blink::WebThread::Task>& queue, WaitMode waitMode)
{
ASSERT(m_context);
ASSERT(m_context->thread());
ASSERT(m_context->thread()->isCurrentThread());
bool nextTimeoutEventIsIdleWatchdog;
MessageQueueWaitResult result;
OwnPtr<blink::WebThread::Task> task;
do {
double absoluteTime = 0.0;
nextTimeoutEventIsIdleWatchdog = false;
if (waitMode == WaitForMessage) {
absoluteTime = m_sharedTimer->isActive() ? m_sharedTimer->fireTime() : MessageQueue<blink::WebThread::Task>::infiniteTime();
const double kMinIdleTimespan = 0.3;
if (queue.isEmpty() && absoluteTime > currentTime() + kMinIdleTimespan) {
bool hasMoreWork = !m_context->idleNotification();
if (hasMoreWork) {
const double kWatchdogInterval = 3;
double nextWatchdogTime = currentTime() + kWatchdogInterval;
if (absoluteTime > nextWatchdogTime) {
absoluteTime = nextWatchdogTime;
nextTimeoutEventIsIdleWatchdog = true;
}
}
}
}
{
ThreadState::SafePointScope safePointScope(ThreadState::NoHeapPointersOnStack);
task = queue.waitForMessageWithTimeout(result, absoluteTime);
}
} while (result == MessageQueueTimeout && nextTimeoutEventIsIdleWatchdog);
switch (result) {
case MessageQueueTerminated:
break;
case MessageQueueMessageReceived:
InspectorInstrumentation::willProcessTask(m_context);
task->run();
InspectorInstrumentation::didProcessTask(m_context);
break;
case MessageQueueTimeout:
if (!m_context->isClosing())
m_sharedTimer->fire();
break;
}
return result;
}
void WorkerRunLoop::runCleanupTasks()
{
ASSERT(m_context);
ASSERT(m_context->thread());
ASSERT(m_context->thread()->isCurrentThread());
ASSERT(m_messageQueue.killed());
ASSERT(m_debuggerMessageQueue.killed());
while (true) {
OwnPtr<blink::WebThread::Task> task = m_debuggerMessageQueue.tryGetMessageIgnoringKilled();
if (!task)
task = m_messageQueue.tryGetMessageIgnoringKilled();
if (!task)
return;
task->run();
}
}
void WorkerRunLoop::terminate()
{
m_messageQueue.kill();
m_debuggerMessageQueue.kill();
}
bool WorkerRunLoop::postTask(PassOwnPtr<ExecutionContextTask> task)
{
return m_messageQueue.append(WorkerRunLoopTask::create(*this, task));
}
void WorkerRunLoop::postTaskAndTerminate(PassOwnPtr<ExecutionContextTask> task)
{
m_debuggerMessageQueue.kill();
m_messageQueue.appendAndKill(WorkerRunLoopTask::create(*this, task));
}
bool WorkerRunLoop::postDebuggerTask(PassOwnPtr<ExecutionContextTask> task)
{
bool posted = m_debuggerMessageQueue.append(WorkerRunLoopTask::create(*this, task));
if (posted)
postTask(TickleDebuggerQueueTask::create(this));
return posted;
}
}