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

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

Issue 956333002: Refactor TimeBase to post tasks. Workers to use real Idle tasks. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebase Created 5 years, 8 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/core/workers/WorkerThreadTest.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 f59a49182a66ff3dcd4b57653f081d209767d181..292b10a626e8a442a8a9c1515a71c8b095555c95 100644
--- a/Source/core/workers/WorkerThread.cpp
+++ b/Source/core/workers/WorkerThread.cpp
@@ -38,14 +38,13 @@
#include "core/workers/WorkerClients.h"
#include "core/workers/WorkerReportingProxy.h"
#include "core/workers/WorkerThreadStartupData.h"
-#include "platform/PlatformThreadData.h"
#include "platform/Task.h"
#include "platform/ThreadSafeFunctional.h"
-#include "platform/ThreadTimers.h"
#include "platform/heap/SafePoint.h"
#include "platform/heap/ThreadState.h"
#include "platform/weborigin/KURL.h"
#include "public/platform/Platform.h"
+#include "public/platform/WebScheduler.h"
#include "public/platform/WebThread.h"
#include "public/platform/WebWaitableEvent.h"
#include "wtf/Noncopyable.h"
@@ -55,8 +54,7 @@
namespace blink {
namespace {
-const int64_t kShortIdleHandlerDelayMs = 1000;
-const int64_t kLongIdleHandlerDelayMs = 10*1000;
+const double kLongIdleHandlerDelaySecs = 1.0;
class MicrotaskRunner : public WebThread::TaskObserver {
public:
@@ -101,100 +99,6 @@ unsigned WorkerThread::workerThreadCount()
return workerThreads().size();
}
-class WorkerThreadCancelableTask final : public ExecutionContextTask {
- WTF_MAKE_NONCOPYABLE(WorkerThreadCancelableTask); WTF_MAKE_FAST_ALLOCATED(WorkerThreadCancelableTask);
-public:
- static PassOwnPtr<WorkerThreadCancelableTask> create(PassOwnPtr<Closure> closure)
- {
- return adoptPtr(new WorkerThreadCancelableTask(closure));
- }
-
- virtual ~WorkerThreadCancelableTask() { }
-
- virtual void performTask(ExecutionContext*) override
- {
- if (!m_taskCanceled)
- (*m_closure)();
- }
-
- WeakPtr<WorkerThreadCancelableTask> createWeakPtr() { return m_weakFactory.createWeakPtr(); }
- void cancelTask() { m_taskCanceled = true; }
-
-private:
- explicit WorkerThreadCancelableTask(PassOwnPtr<Closure> closure)
- : m_closure(closure)
- , m_weakFactory(this)
- , m_taskCanceled(false)
- { }
-
- OwnPtr<Closure> m_closure;
- WeakPtrFactory<WorkerThreadCancelableTask> m_weakFactory;
- bool m_taskCanceled;
-};
-
-class WorkerSharedTimer : public SharedTimer {
-public:
- explicit WorkerSharedTimer(WorkerThread* workerThread)
- : m_workerThread(workerThread)
- , m_running(false)
- { }
-
- typedef void (*SharedTimerFunction)();
- virtual void setFiredFunction(SharedTimerFunction func)
- {
- m_sharedTimerFunction = func;
- }
-
- virtual void setFireInterval(double interval)
- {
- ASSERT(m_sharedTimerFunction);
-
- // See BlinkPlatformImpl::setSharedTimerFireInterval for explanation of
- // why ceil is used in the interval calculation.
- int64_t delay = static_cast<int64_t>(ceil(interval * 1000));
-
- if (delay < 0) {
- delay = 0;
- }
-
- m_running = true;
-
- if (m_lastQueuedTask.get())
- m_lastQueuedTask->cancelTask();
-
- // Now queue the task as a cancellable one.
- OwnPtr<WorkerThreadCancelableTask> task = WorkerThreadCancelableTask::create(bind(&WorkerSharedTimer::OnTimeout, this));
- m_lastQueuedTask = task->createWeakPtr();
- m_workerThread->postDelayedTask(FROM_HERE, task.release(), delay);
- }
-
- virtual void stop()
- {
- m_running = false;
- m_lastQueuedTask = nullptr;
- }
-
-private:
- void OnTimeout()
- {
- ASSERT(m_workerThread->workerGlobalScope());
-
- m_lastQueuedTask = nullptr;
-
- if (m_sharedTimerFunction && m_running && !m_workerThread->workerGlobalScope()->isClosing())
- m_sharedTimerFunction();
- }
-
- WorkerThread* m_workerThread;
- SharedTimerFunction m_sharedTimerFunction;
- bool m_running;
-
- // The task to run OnTimeout, if any. While OnTimeout resets
- // m_lastQueuedTask, this must be a weak pointer because the
- // worker runloop may delete the task as it is shutting down.
- WeakPtr<WorkerThreadCancelableTask> m_lastQueuedTask;
-};
-
class WorkerThreadTask : public blink::WebThread::Task {
WTF_MAKE_NONCOPYABLE(WorkerThreadTask); WTF_MAKE_FAST_ALLOCATED(WorkerThreadTask);
public:
@@ -265,6 +169,8 @@ WorkerThread::WorkerThread(const char* threadName, PassRefPtr<WorkerLoaderProxy>
, m_isolate(nullptr)
, m_shutdownEvent(adoptPtr(blink::Platform::current()->createWaitableEvent()))
, m_terminationEvent(adoptPtr(blink::Platform::current()->createWaitableEvent()))
+ , m_webScheduler(nullptr)
+ , m_preShutdown(false)
{
MutexLocker lock(threadSetMutex());
workerThreads().add(this);
@@ -283,6 +189,7 @@ void WorkerThread::start()
return;
m_thread = createWebThreadSupportingGC();
+ m_webScheduler = m_thread->platformThread().scheduler();
m_thread->postTask(FROM_HERE, new Task(threadSafeBind(&WorkerThread::initialize, AllowCrossThreadAccess(this))));
}
@@ -300,6 +207,24 @@ PlatformThreadId WorkerThread::platformThreadId() const
return m_thread->platformThread().threadId();
}
+// TODO(alexclarke): Use base::Bind instead of this class when the repo's merge. Unfortunately we
+// can't use WTF::bind because the type-erasure for member function pointers with parameters is broken.
+class WorkerThreadIdleTask : public WebThread::IdleTask {
+public:
+ explicit WorkerThreadIdleTask(WorkerThread* thread)
+ : m_thread(thread) { }
+
+ ~WorkerThreadIdleTask() override { }
+
+ void run(double deadlineSeconds) override
+ {
+ m_thread->idleTask(deadlineSeconds);
+ }
+
+private:
+ RawPtr<WorkerThread> m_thread; // NOT OWNED
+};
+
void WorkerThread::initialize()
{
KURL scriptURL = m_startupData->m_scriptURL;
@@ -326,8 +251,6 @@ void WorkerThread::initialize()
m_isolate = initializeIsolate();
m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release());
m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.get() ? cachedMetaData->size() : 0);
-
- PlatformThreadData::current().threadTimers().setSharedTimer(adoptPtr(new WorkerSharedTimer(this)));
}
// The corresponding call to stopRunLoop() is in ~WorkerScriptController().
@@ -349,7 +272,7 @@ void WorkerThread::initialize()
postInitialize();
- postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler, this), kShortIdleHandlerDelayMs);
+ m_webScheduler->postIdleTaskAfterWakeup(FROM_HERE, new WorkerThreadIdleTask(this));
}
PassOwnPtr<WebThreadSupportingGC> WorkerThread::createWebThreadSupportingGC()
@@ -382,9 +305,6 @@ void WorkerThread::cleanup()
workerReportingProxy().workerThreadTerminated();
m_terminationEvent->signal();
-
- // Clean up PlatformThreadData before WTF::WTFThreadData goes away!
- PlatformThreadData::current().destroy();
}
class WorkerThreadShutdownFinishTask : public ExecutionContextTask {
@@ -401,7 +321,7 @@ public:
WorkerThread* workerThread = workerGlobalScope->thread();
workerThread->willDestroyIsolate();
- workerThread->m_thread->postTask(FROM_HERE, new Task(WTF::bind(&WorkerThread::cleanup, workerThread)));
+ workerThread->m_webScheduler->postShutdownTask(FROM_HERE, new Task(WTF::bind(&WorkerThread::cleanup, workerThread)), 0);
}
virtual bool isCleanupTask() const { return true; }
@@ -418,7 +338,6 @@ public:
{
WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
workerGlobalScope->stopActiveDOMObjects();
- PlatformThreadData::current().threadTimers().setSharedTimer(nullptr);
// Event listeners would keep DOMWrapperWorld objects alive for too long. Also, they have references to JS objects,
// which become dangling once Heap is destroyed.
@@ -432,6 +351,41 @@ public:
virtual bool isCleanupTask() const { return true; }
};
+class PreShutDownTask : public WebThread::Task {
+public:
+ PreShutDownTask(WebWaitableEvent* completion, WebScheduler* webScheduler)
+ : m_completion(completion)
+ , m_webScheduler(webScheduler) { }
+
+ ~PreShutDownTask() override { }
+
+ void run()
+ {
+ m_webScheduler->preShutdown();
+ m_completion->signal();
+ }
+
+private:
+ RawPtr<WebWaitableEvent> m_completion; // NOT OWNED.
+ RawPtr<WebScheduler> m_webScheduler; // NOT OWNED.
+};
+
+void WorkerThread::preShutdown()
+{
+ MutexLocker lock(m_preShutdownMutex);
+ if (m_preShutdown || !m_webScheduler)
+ return;
+ m_preShutdown = true;
+
+ if (m_thread->isCurrentThread()) {
+ m_webScheduler->preShutdown();
+ } else {
+ OwnPtr<WebWaitableEvent> completion(adoptPtr(blink::Platform::current()->createWaitableEvent()));
+ m_thread->postTask(FROM_HERE, new PreShutDownTask(completion.get(), m_webScheduler.get()));
+ completion->wait();
+ }
+}
+
void WorkerThread::stop()
{
// Prevent the deadlock between GC and an attempt to stop a thread.
@@ -459,26 +413,30 @@ bool WorkerThread::terminated()
void WorkerThread::stopInternal()
{
// Protect against this method and initialize() racing each other.
- MutexLocker lock(m_threadCreationMutex);
+ {
+ MutexLocker lock(m_threadCreationMutex);
- // If stop has already been called, just return.
- if (m_terminated)
- return;
- m_terminated = true;
+ // If stop has already been called, just return.
+ if (m_terminated)
+ return;
+ m_terminated = true;
- // Signal the thread to notify that the thread's stopping.
- if (m_shutdownEvent)
- m_shutdownEvent->signal();
+ // Signal the thread to notify that the thread's stopping.
+ if (m_shutdownEvent)
+ m_shutdownEvent->signal();
- if (!m_workerGlobalScope)
- return;
+ if (!m_workerGlobalScope)
+ return;
- // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
- terminateV8Execution();
+ // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
+ terminateV8Execution();
- InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScope.get());
- m_debuggerMessageQueue.kill();
- postTask(FROM_HERE, WorkerThreadShutdownStartTask::create());
+ InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScope.get());
+ m_debuggerMessageQueue.kill();
+ postTask(FROM_HERE, WorkerThreadShutdownStartTask::create());
+ }
+ // Prevent further execution of non-shutdown tasks on the thread. Must happen after any v8 task has been terminated.
+ preShutdown();
}
void WorkerThread::didStartRunLoop()
@@ -510,31 +468,46 @@ bool WorkerThread::isCurrentThread() const
return m_thread && m_thread->isCurrentThread();
}
-void WorkerThread::idleHandler()
+void WorkerThread::idleTask(double deadlineSeconds)
{
- ASSERT(m_workerGlobalScope.get());
- int64_t delay = kLongIdleHandlerDelayMs;
+ if (terminated())
+ return;
- // Do a script engine idle notification if the next event is distant enough.
- const double kMinIdleTimespan = 0.3;
- const double nextFireTime = PlatformThreadData::current().threadTimers().nextFireTime();
- if (nextFireTime == 0.0 || nextFireTime > currentTime() + kMinIdleTimespan) {
- bool hasMoreWork = !isolate()->IdleNotificationDeadline(Platform::current()->monotonicallyIncreasingTime() + 1.0);
- if (hasMoreWork)
- delay = kShortIdleHandlerDelayMs;
- }
+ double gcDeadlineSeconds = deadlineSeconds;
- postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler, this), delay);
+ // The V8 GC does some GC steps (e.g. compaction) only when the idle notification is ~1s.
+ // TODO(rmcilroy): Refactor so extending the deadline like this this isn't needed.
+ if (m_webScheduler->canExceedIdleDeadlineIfRequired())
+ gcDeadlineSeconds = Platform::current()->monotonicallyIncreasingTime() + kLongIdleHandlerDelaySecs;
+
+ if (doIdleGc(gcDeadlineSeconds))
+ m_webScheduler->postIdleTaskAfterWakeup(FROM_HERE, new WorkerThreadIdleTask(this));
+ else
+ m_webScheduler->postIdleTask(FROM_HERE, new WorkerThreadIdleTask(this));
+}
+
+bool WorkerThread::doIdleGc(double deadlineSeconds)
+{
+ bool gcFinished = false;
+ if (deadlineSeconds > Platform::current()->monotonicallyIncreasingTime())
+ gcFinished = isolate()->IdleNotificationDeadline(deadlineSeconds);
+ return gcFinished;
}
void WorkerThread::postTask(const WebTraceLocation& location, PassOwnPtr<ExecutionContextTask> task)
{
- m_thread->postTask(location, WorkerThreadTask::create(*this, task, true).leakPtr());
+ if (task->isCleanupTask())
+ m_webScheduler->postShutdownTask(location, WorkerThreadTask::create(*this, task, true).leakPtr(), 0);
+ else
+ m_thread->postTask(location, WorkerThreadTask::create(*this, task, true).leakPtr());
}
void WorkerThread::postDelayedTask(const WebTraceLocation& location, PassOwnPtr<ExecutionContextTask> task, long long delayMs)
{
- m_thread->postDelayedTask(location, WorkerThreadTask::create(*this, task, true).leakPtr(), delayMs);
+ if (task->isCleanupTask())
+ m_webScheduler->postShutdownTask(location, WorkerThreadTask::create(*this, task, true).leakPtr(), delayMs);
+ else
+ m_thread->postDelayedTask(location, WorkerThreadTask::create(*this, task, true).leakPtr(), delayMs);
}
v8::Isolate* WorkerThread::initializeIsolate()
« no previous file with comments | « Source/core/workers/WorkerThread.h ('k') | Source/core/workers/WorkerThreadTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698