Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2013)

Unified Diff: Source/core/workers/WorkerThread.cpp

Issue 400153002: Change WokerThread to use a blink::WebThread. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fix issues from jochen's review. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/workers/WorkerThread.h ('k') | Source/platform/scheduler/SchedulerTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/workers/WorkerThread.cpp
diff --git a/Source/core/workers/WorkerThread.cpp b/Source/core/workers/WorkerThread.cpp
index e84fd393fc20ee4a0c4a64870fcef6137b2950a7..100e9ed94021f9d1c5a37d4d0d19d7123eb66769 100644
--- a/Source/core/workers/WorkerThread.cpp
+++ b/Source/core/workers/WorkerThread.cpp
@@ -35,9 +35,12 @@
#include "core/workers/WorkerReportingProxy.h"
#include "core/workers/WorkerThreadStartupData.h"
#include "platform/PlatformThreadData.h"
+#include "platform/Task.h"
+#include "platform/ThreadTimers.h"
#include "platform/heap/ThreadState.h"
#include "platform/weborigin/KURL.h"
#include "public/platform/Platform.h"
+#include "public/platform/WebThread.h"
#include "public/platform/WebWaitableEvent.h"
#include "public/platform/WebWorkerRunLoop.h"
#include "wtf/Noncopyable.h"
@@ -47,6 +50,11 @@
namespace blink {
+namespace {
+const int64 kShortIdleHandlerDelayMs = 1000;
+const int64 kLongIdleHandlerDelayMs = 10*1000;
+}
+
static Mutex& threadSetMutex()
{
AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
@@ -65,8 +73,94 @@ unsigned WorkerThread::workerThreadCount()
return workerThreads().size();
}
+class WorkerSharedTimer : public SharedTimer {
+public:
+ explicit WorkerSharedTimer(blink::WebThread* webThread)
+ : m_thread(webThread)
+ , m_nextFireTime(0.0)
+ { }
+
+ virtual void setFiredFunction(blink::WebThread::SharedTimerFunction func)
+ {
+ m_thread->setSharedTimerFiredFunction(func);
+ if (!func)
+ m_nextFireTime = 0.0;
+ }
+ virtual void setFireInterval(double interval)
+ {
+ m_thread->setSharedTimerFireInterval(interval);
+ m_nextFireTime = interval + currentTime();
+ }
+ virtual void stop()
+ {
+ m_thread->stopSharedTimer();
+ }
+
+ double nextFireTime() { return m_nextFireTime; }
+
+private:
+ blink::WebThread* m_thread;
+ double m_nextFireTime;
+};
+
+class WorkerThreadTask : public blink::WebThread::Task {
+ WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED;
+public:
+ static PassOwnPtr<WorkerThreadTask> create(const WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
+ {
+ return adoptPtr(new WorkerThreadTask(workerThread, task, isInstrumented));
+ }
+
+ virtual ~WorkerThreadTask() { }
+
+ virtual void run() OVERRIDE
+ {
+ WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope();
+ if (m_isInstrumented)
+ InspectorInstrumentation::willPerformExecutionContextTask(workerGlobalScope, m_task.get());
+ if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask())
+ m_task->performTask(workerGlobalScope);
+ if (m_isInstrumented)
+ InspectorInstrumentation::didPerformExecutionContextTask(workerGlobalScope);
+ }
+
+private:
+ WorkerThreadTask(const WorkerThread& workerThread, PassOwnPtr<ExecutionContextTask> task, bool isInstrumented)
+ : m_workerThread(workerThread)
+ , m_task(task)
+ , m_isInstrumented(isInstrumented)
+ {
+ if (m_isInstrumented)
+ m_isInstrumented = !m_task->taskNameForInstrumentation().isEmpty();
+ if (m_isInstrumented)
+ InspectorInstrumentation::didPostExecutionContextTask(m_workerThread.workerGlobalScope(), m_task.get());
+ }
+
+ const WorkerThread& m_workerThread;
+ OwnPtr<ExecutionContextTask> m_task;
+ bool m_isInstrumented;
+};
+
+class RunDebuggerQueueTask FINAL : public ExecutionContextTask {
+public:
+ static PassOwnPtr<RunDebuggerQueueTask> create(WorkerThread* thread)
+ {
+ return adoptPtr(new RunDebuggerQueueTask(thread));
+ }
+ virtual void performTask(ExecutionContext* context) OVERRIDE
+ {
+ ASSERT(context->isWorkerGlobalScope());
+ m_thread->runDebuggerTask(WorkerThread::DontWaitForMessage);
+ }
+
+private:
+ explicit RunDebuggerQueueTask(WorkerThread* thread) : m_thread(thread) { }
+
+ WorkerThread* m_thread;
+};
+
WorkerThread::WorkerThread(WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> startupData)
- : m_threadID(0)
+ : m_terminated(false)
, m_workerLoaderProxy(workerLoaderProxy)
, m_workerReportingProxy(workerReportingProxy)
, m_startupData(startupData)
@@ -83,25 +177,17 @@ WorkerThread::~WorkerThread()
workerThreads().remove(this);
}
-bool WorkerThread::start()
+void WorkerThread::start()
{
- // Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts.
- MutexLocker lock(m_threadCreationMutex);
-
- if (m_threadID)
- return true;
-
- m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker");
-
- return m_threadID;
-}
+ if (m_thread)
+ return;
-void WorkerThread::workerThreadStart(void* thread)
-{
- static_cast<WorkerThread*>(thread)->workerThread();
+ m_thread = adoptPtr(blink::Platform::current()->createThread("WebCore: Worker"));
+ m_sharedTimer = adoptPtr(new WorkerSharedTimer(m_thread.get()));
+ m_thread->postTask(new Task(WTF::bind(&WorkerThread::initialize, this)));
}
-void WorkerThread::workerThread()
+void WorkerThread::initialize()
{
KURL scriptURL = m_startupData->m_scriptURL;
String sourceCode = m_startupData->m_sourceCode;
@@ -109,19 +195,22 @@ void WorkerThread::workerThread()
{
MutexLocker lock(m_threadCreationMutex);
+
ThreadState::attach();
m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release());
- m_runLoop.setWorkerGlobalScope(workerGlobalScope());
- if (m_runLoop.terminated()) {
+ PlatformThreadData::current().threadTimers().setSharedTimer(m_sharedTimer.get());
+
+ if (m_terminated) {
// The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
// forbidExecution() couldn't be called from stop().
m_workerGlobalScope->script()->forbidExecution();
}
}
- // The corresponding call to didStopWorkerRunLoop is in
+
+ // The corresponding call to didStopWorkerThread is in
// ~WorkerScriptController.
- blink::Platform::current()->didStartWorkerRunLoop(blink::WebWorkerRunLoop(&m_runLoop));
+ blink::Platform::current()->didStartWorkerThread(m_thread.get());
// Notify proxy that a new WorkerGlobalScope has been created and started.
m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get());
@@ -132,13 +221,19 @@ void WorkerThread::workerThread()
InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), startMode);
script->evaluate(ScriptSourceCode(sourceCode, scriptURL));
- runEventLoop();
+ postInitialize();
+
+ m_weakFactory = adoptPtr(new WeakPtrFactory<WorkerThread>(this));
+ m_thread->postDelayedTask(new Task(WTF::bind(&WorkerThread::idleHandler, m_weakFactory->createWeakPtr())), kShortIdleHandlerDelayMs);
+}
+
+void WorkerThread::cleanup()
+{
+ m_weakFactory.release();
// This should be called before we start the shutdown procedure.
workerReportingProxy().willDestroyWorkerGlobalScope();
- ThreadIdentifier threadID = m_threadID;
-
// The below assignment will destroy the context, which will in turn notify messaging proxy.
// We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
// If Oilpan is enabled, we detach of the context/global scope, with the final heap cleanup below sweeping it out.
@@ -165,14 +260,10 @@ void WorkerThread::workerThread()
// Clean up PlatformThreadData before WTF::WTFThreadData goes away!
PlatformThreadData::current().destroy();
- // The thread object may be already destroyed from notification now, don't try to access "this".
- detachThread(threadID);
-}
-
-void WorkerThread::runEventLoop()
-{
- // Does not return until terminated.
- m_runLoop.run();
+ // Set the timer function to null, which will cause the shared timer in
+ // WebThread to be deleted. It is important to do it here, since it
+ // should be deleted on the same thread that it executes on.
+ m_sharedTimer->setFiredFunction(0);
}
class WorkerThreadShutdownFinishTask : public ExecutionContextTask {
@@ -188,6 +279,7 @@ public:
workerGlobalScope->clearInspector();
// It's not safe to call clearScript until all the cleanup tasks posted by functions initiated by WorkerThreadShutdownStartTask have completed.
workerGlobalScope->clearScript();
+ workerGlobalScope->thread()->webThread()->postTask(new Task(WTF::bind(&WorkerThread::cleanup, workerGlobalScope->thread())));
}
virtual bool isCleanupTask() const { return true; }
@@ -205,6 +297,7 @@ public:
WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
workerGlobalScope->stopFetch();
workerGlobalScope->stopActiveDOMObjects();
+ workerGlobalScope->thread()->webThread()->stopSharedTimer();
// Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
// which become dangling once Heap is destroyed.
@@ -223,9 +316,13 @@ void WorkerThread::stop()
// Prevent the deadlock between GC and an attempt to stop a thread.
ThreadState::SafePointScope safePointScope(ThreadState::HeapPointersOnStack);
- // Mutex protection is necessary because stop() can be called before the context is fully created.
+ // Protect against this method and initialize() racing each other.
MutexLocker lock(m_threadCreationMutex);
+ // If stop has already been called, just return.
+ if (m_terminated)
+ return;
+
// Signal the thread to notify that the thread's stopping.
if (m_shutdownEvent)
m_shutdownEvent->signal();
@@ -234,30 +331,77 @@ void WorkerThread::stop()
if (m_workerGlobalScope) {
m_workerGlobalScope->script()->scheduleExecutionTermination();
m_workerGlobalScope->wasRequestedToTerminate();
- m_runLoop.postTaskAndTerminate(WorkerThreadShutdownStartTask::create());
+ InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScope.get());
aandrey 2014/07/24 16:07:53 is it safe to access m_workerGlobalScope here? if
nasko 2014/07/25 06:30:14 It is safe. It is used further in the WorkerThread
yurys 2014/07/25 06:41:56 It is unsafe to access m_workerGlobalScope here as
+ postTask(WorkerThreadShutdownStartTask::create());
+ m_terminated = true;
return;
}
- m_runLoop.terminate();
}
bool WorkerThread::isCurrentThread() const
{
- return m_threadID == currentThread();
+ return m_thread && m_thread->isCurrentThread();
+}
+
+void WorkerThread::idleHandler()
+{
+ if (m_terminated)
+ return;
+
+ int64 delay = kLongIdleHandlerDelayMs;
+
+ // Do a script engine idle notification if the next event is distant enough.
+ const double kMinIdleTimespan = 0.3;
+ if (!m_sharedTimer->nextFireTime() || m_sharedTimer->nextFireTime() > currentTime() + kMinIdleTimespan) {
+ bool hasMoreWork = !m_workerGlobalScope->idleNotification();
+ if (hasMoreWork)
+ delay = kShortIdleHandlerDelayMs;
+ }
+
+ m_thread->postDelayedTask(new Task(WTF::bind(&WorkerThread::idleHandler, m_weakFactory->createWeakPtr())), delay);
}
void WorkerThread::postTask(PassOwnPtr<ExecutionContextTask> task)
{
- m_runLoop.postTask(task);
+ m_thread->postTask(WorkerThreadTask::create(*this, task, true).leakPtr());
}
void WorkerThread::postDebuggerTask(PassOwnPtr<ExecutionContextTask> task)
{
- m_runLoop.postDebuggerTask(task);
+ m_debuggerMessageQueue.append(WorkerThreadTask::create(*this, task, false));
+ postTask(RunDebuggerQueueTask::create(this));
+}
+
+MessageQueueWaitResult WorkerThread::runDebuggerTask(WaitMode waitMode)
+{
+ ASSERT(isCurrentThread());
+ MessageQueueWaitResult result;
+ double absoluteTime = MessageQueue<blink::WebThread::Task>::infiniteTime();
+ OwnPtr<blink::WebThread::Task> task;
+ {
+ if (waitMode == DontWaitForMessage)
+ absoluteTime = 0.0;
+ ThreadState::SafePointScope safePointScope(ThreadState::NoHeapPointersOnStack);
+ task = m_debuggerMessageQueue.waitForMessageWithTimeout(result, absoluteTime);
+ }
+
+ if (result == MessageQueueMessageReceived) {
+ InspectorInstrumentation::willProcessTask(workerGlobalScope());
+ task->run();
+ InspectorInstrumentation::didProcessTask(workerGlobalScope());
+ }
+
+ return result;
+}
+
+void WorkerThread::willEnterNestedLoop()
+{
+ InspectorInstrumentation::willEnterNestedRunLoop(m_workerGlobalScope.get());
}
-MessageQueueWaitResult WorkerThread::runDebuggerTask(WorkerRunLoop::WaitMode waitMode)
+void WorkerThread::didLeaveNestedLoop()
{
- return m_runLoop.runDebuggerTask(waitMode);
+ InspectorInstrumentation::didLeaveNestedRunLoop(m_workerGlobalScope.get());
}
} // namespace blink
« no previous file with comments | « Source/core/workers/WorkerThread.h ('k') | Source/platform/scheduler/SchedulerTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698