| Index: Source/core/workers/WorkerThread.cpp
|
| diff --git a/Source/core/workers/WorkerThread.cpp b/Source/core/workers/WorkerThread.cpp
|
| index d8f75cc105c1285c6f3df3d80327ff396782a07a..b1f58f335c209535550a5a2787a06855b1bb2282 100644
|
| --- a/Source/core/workers/WorkerThread.cpp
|
| +++ b/Source/core/workers/WorkerThread.cpp
|
| @@ -58,20 +58,32 @@ namespace {
|
| const int64_t kShortIdleHandlerDelayMs = 1000;
|
| const int64_t kLongIdleHandlerDelayMs = 10*1000;
|
|
|
| -class MicrotaskRunner : public WebThread::TaskObserver {
|
| +} // namespace
|
| +
|
| +class WorkerMicrotaskRunner : public WebThread::TaskObserver {
|
| public:
|
| - explicit MicrotaskRunner(WorkerThread* workerThread)
|
| + explicit WorkerMicrotaskRunner(WorkerThread* workerThread)
|
| : m_workerThread(workerThread)
|
| {
|
| }
|
|
|
| - virtual void willProcessTask() override { }
|
| + virtual void willProcessTask() override
|
| + {
|
| + // No tasks should get executed after we have closed.
|
| + WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope();
|
| + ASSERT_UNUSED(globalScope, !globalScope || !globalScope->isClosing());
|
| + }
|
| +
|
| virtual void didProcessTask() override
|
| {
|
| Microtask::performCheckpoint();
|
| if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope()) {
|
| if (WorkerScriptController* scriptController = globalScope->script())
|
| scriptController->rejectedPromises()->processQueue();
|
| + if (globalScope->isClosing()) {
|
| + m_workerThread->workerReportingProxy().workerGlobalScopeClosed();
|
| + m_workerThread->shutdown();
|
| + }
|
| }
|
| }
|
|
|
| @@ -81,8 +93,6 @@ private:
|
| WorkerThread* m_workerThread;
|
| };
|
|
|
| -} // namespace
|
| -
|
| static Mutex& threadSetMutex()
|
| {
|
| AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex);
|
| @@ -208,15 +218,16 @@ public:
|
| virtual void run() override
|
| {
|
| WorkerGlobalScope* workerGlobalScope = m_workerThread.workerGlobalScope();
|
| - // Tasks could be put on the message loop after the cleanup task,
|
| - // ensure none of those are ran.
|
| - if (!workerGlobalScope)
|
| + // If the thread is terminated before it had a chance initialize (see
|
| + // WorkerThread::Initialize()), we mustn't run any of the posted tasks.
|
| + if (!workerGlobalScope) {
|
| + ASSERT(m_workerThread.terminated());
|
| return;
|
| + }
|
|
|
| if (m_isInstrumented)
|
| InspectorInstrumentation::willPerformExecutionContextTask(workerGlobalScope, m_task.get());
|
| - if ((!workerGlobalScope->isClosing() && !m_workerThread.terminated()) || m_task->isCleanupTask())
|
| - m_task->performTask(workerGlobalScope);
|
| + m_task->performTask(workerGlobalScope);
|
| if (m_isInstrumented)
|
| InspectorInstrumentation::didPerformExecutionContextTask(workerGlobalScope);
|
| }
|
| @@ -309,7 +320,7 @@ void WorkerThread::initialize()
|
| V8CacheOptions v8CacheOptions = m_startupData->m_v8CacheOptions;
|
|
|
| {
|
| - MutexLocker lock(m_threadCreationMutex);
|
| + MutexLocker lock(m_threadStateMutex);
|
|
|
| // The worker was terminated before the thread had a chance to run.
|
| if (m_terminated) {
|
| @@ -319,9 +330,9 @@ void WorkerThread::initialize()
|
| return;
|
| }
|
|
|
| - m_microtaskRunner = adoptPtr(new MicrotaskRunner(this));
|
| + m_microtaskRunner = adoptPtr(new WorkerMicrotaskRunner(this));
|
| backingThread().addTaskObserver(m_microtaskRunner.get());
|
| - backingThread().attachGC();
|
| + backingThread().initialize();
|
|
|
| m_isolate = initializeIsolate();
|
| m_workerGlobalScope = createWorkerGlobalScope(m_startupData.release());
|
| @@ -352,8 +363,15 @@ void WorkerThread::initialize()
|
| postDelayedTask(FROM_HERE, createSameThreadTask(&WorkerThread::idleHandler, this), kShortIdleHandlerDelayMs);
|
| }
|
|
|
| -void WorkerThread::cleanup()
|
| +void WorkerThread::shutdown()
|
| {
|
| + MutexLocker lock(m_threadStateMutex);
|
| + ASSERT(isCurrentThread());
|
| +
|
| + PlatformThreadData::current().threadTimers().setSharedTimer(nullptr);
|
| + workerGlobalScope()->dispose();
|
| + willDestroyIsolate();
|
| +
|
| // This should be called before we start the shutdown procedure.
|
| workerReportingProxy().willDestroyWorkerGlobalScope();
|
|
|
| @@ -366,10 +384,10 @@ void WorkerThread::cleanup()
|
| m_workerGlobalScope->notifyContextDestroyed();
|
| m_workerGlobalScope = nullptr;
|
|
|
| - backingThread().detachGC();
|
| + backingThread().removeTaskObserver(m_microtaskRunner.get());
|
| + backingThread().shutdown();
|
| destroyIsolate();
|
|
|
| - backingThread().removeTaskObserver(m_microtaskRunner.get());
|
| m_microtaskRunner = nullptr;
|
|
|
| // Notify the proxy that the WorkerGlobalScope has been disposed of.
|
| @@ -382,50 +400,6 @@ void WorkerThread::cleanup()
|
| PlatformThreadData::current().destroy();
|
| }
|
|
|
| -class WorkerThreadShutdownFinishTask : public ExecutionContextTask {
|
| -public:
|
| - static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
|
| - {
|
| - return adoptPtr(new WorkerThreadShutdownFinishTask());
|
| - }
|
| -
|
| - virtual void performTask(ExecutionContext *context)
|
| - {
|
| - WorkerGlobalScope* workerGlobalScope = toWorkerGlobalScope(context);
|
| - workerGlobalScope->dispose();
|
| -
|
| - WorkerThread* workerThread = workerGlobalScope->thread();
|
| - workerThread->willDestroyIsolate();
|
| - workerThread->backingThread().postTask(FROM_HERE, new Task(WTF::bind(&WorkerThread::cleanup, workerThread)));
|
| - }
|
| -
|
| - virtual bool isCleanupTask() const { return true; }
|
| -};
|
| -
|
| -class WorkerThreadShutdownStartTask : public ExecutionContextTask {
|
| -public:
|
| - static PassOwnPtr<WorkerThreadShutdownStartTask> create()
|
| - {
|
| - return adoptPtr(new WorkerThreadShutdownStartTask());
|
| - }
|
| -
|
| - virtual void performTask(ExecutionContext *context)
|
| - {
|
| - 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.
|
| - workerGlobalScope->removeAllEventListeners();
|
| -
|
| - // Stick a shutdown command at the end of the queue, so that we deal
|
| - // with all the cleanup tasks the databases post first.
|
| - workerGlobalScope->postTask(FROM_HERE, WorkerThreadShutdownFinishTask::create());
|
| - }
|
| -
|
| - virtual bool isCleanupTask() const { return true; }
|
| -};
|
|
|
| void WorkerThread::stop()
|
| {
|
| @@ -447,14 +421,14 @@ void WorkerThread::terminateAndWait()
|
|
|
| bool WorkerThread::terminated()
|
| {
|
| - MutexLocker lock(m_threadCreationMutex);
|
| + MutexLocker lock(m_threadStateMutex);
|
| return m_terminated;
|
| }
|
|
|
| void WorkerThread::stopInternal()
|
| {
|
| - // Protect against this method and initialize() racing each other.
|
| - MutexLocker lock(m_threadCreationMutex);
|
| + // Protect against this method, initialize() or termination via the global scope racing each other.
|
| + MutexLocker lock(m_threadStateMutex);
|
|
|
| // If stop has already been called, just return.
|
| if (m_terminated)
|
| @@ -473,7 +447,7 @@ void WorkerThread::stopInternal()
|
|
|
| InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScope.get());
|
| m_debuggerMessageQueue.kill();
|
| - postTask(FROM_HERE, WorkerThreadShutdownStartTask::create());
|
| + backingThread().postTask(FROM_HERE, new Task(threadSafeBind(&WorkerThread::shutdown, AllowCrossThreadAccess(this))));
|
| }
|
|
|
| void WorkerThread::didStartRunLoop()
|
|
|