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

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

Issue 1992933002: Introduce WorkletGlobalScopeProxy interface. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix tests. Created 4 years, 6 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
Index: third_party/WebKit/Source/core/workers/WorkerThread.cpp
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
index 62c4fd888ac86f03869271c109be5607ccb159c8..38b458b6e1a7a9567f52f48b40ae76d464169e2c 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -53,111 +53,21 @@
namespace blink {
-// TODO(nhiroki): Adjust the delay based on UMA.
-const long long kForceTerminationDelayInMs = 2000; // 2 secs
-
-// ForceTerminationTask is used for posting a delayed task to terminate the
-// worker execution from the main thread. This task is expected to run when the
-// shutdown sequence does not start in a certain time period because of an
-// inifite loop in the JS execution context etc. When the shutdown sequence is
-// started before this task runs, the task is simply cancelled.
-class WorkerThread::ForceTerminationTask final {
+class WorkerGlobalScopeFactory final : public WorkerOrWorkletThread::GlobalScopeFactory {
public:
- static PassOwnPtr<ForceTerminationTask> create(WorkerThread* workerThread)
- {
- return adoptPtr(new ForceTerminationTask(workerThread));
- }
-
- void schedule()
+ WorkerOrWorkletGlobalScope* create() const final
{
- DCHECK(isMainThread());
- Platform::current()->mainThread()->getWebTaskRunner()->postDelayedTask(BLINK_FROM_HERE, m_cancellableTaskFactory->cancelAndCreate(), m_workerThread->m_forceTerminationDelayInMs);
+ return m_workerThread.createWorkerGlobalScope(m_startupData.get());
}
-private:
- explicit ForceTerminationTask(WorkerThread* workerThread)
+ WorkerGlobalScopeFactory(WorkerThread& workerThread, PassOwnPtr<WorkerThreadStartupData> startupData)
: m_workerThread(workerThread)
- {
- DCHECK(isMainThread());
- m_cancellableTaskFactory = CancellableTaskFactory::create(this, &ForceTerminationTask::run);
- }
-
- void run()
- {
- DCHECK(isMainThread());
- MutexLocker lock(m_workerThread->m_threadStateMutex);
- if (m_workerThread->m_readyToShutdown) {
- // Shutdown sequence is now running. Just return.
- return;
- }
-
- m_workerThread->forciblyTerminateExecution();
- DCHECK_EQ(WorkerThread::ExitCode::NotTerminated, m_workerThread->m_exitCode);
- m_workerThread->m_exitCode = WorkerThread::ExitCode::AsyncForciblyTerminated;
- }
-
- WorkerThread* m_workerThread;
- OwnPtr<CancellableTaskFactory> m_cancellableTaskFactory;
-};
-
-class WorkerThread::WorkerMicrotaskRunner final : public WebThread::TaskObserver {
-public:
- explicit WorkerMicrotaskRunner(WorkerThread* workerThread)
- : m_workerThread(workerThread)
- {
- }
-
- void willProcessTask() override
- {
- // No tasks should get executed after we have closed.
- DCHECK(!m_workerThread->workerGlobalScope() || !m_workerThread->workerGlobalScope()->isClosing());
- }
-
- void didProcessTask() override
- {
- Microtask::performCheckpoint(m_workerThread->isolate());
- if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope()) {
- if (WorkerOrWorkletScriptController* scriptController = globalScope->scriptController())
- scriptController->getRejectedPromises()->processQueue();
- if (globalScope->isClosing()) {
- // |m_workerThread| will eventually be requested to terminate.
- m_workerThread->workerReportingProxy().workerGlobalScopeClosed();
-
- // Stop further worker tasks to run after this point.
- m_workerThread->prepareForShutdownOnWorkerThread();
- }
- }
- }
-
+ , m_startupData(std::move(startupData)) { }
private:
- // Thread owns the microtask runner; reference remains
- // valid for the lifetime of this object.
- WorkerThread* m_workerThread;
-};
-
-static Mutex& threadSetMutex()
-{
- DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, new Mutex);
- return mutex;
-}
-
-static HashSet<WorkerThread*>& workerThreads()
-{
- DEFINE_STATIC_LOCAL(HashSet<WorkerThread*>, threads, ());
- return threads;
-}
-
-WorkerThread::~WorkerThread()
-{
- DCHECK(isMainThread());
- MutexLocker lock(threadSetMutex());
- DCHECK(workerThreads().contains(this));
- workerThreads().remove(this);
- // TODO(nhiroki): Record how this thread is terminated (i.e. m_exitCode)
- // in UMA.
- DCHECK_NE(ExitCode::NotTerminated, m_exitCode);
-}
+ WorkerThread& m_workerThread;
+ OwnPtr<WorkerThreadStartupData> m_startupData;
+};
void WorkerThread::start(PassOwnPtr<WorkerThreadStartupData> startupData)
{
@@ -170,229 +80,10 @@ void WorkerThread::start(PassOwnPtr<WorkerThreadStartupData> startupData)
workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::initializeOnWorkerThread, AllowCrossThreadAccess(this), passed(std::move(startupData))));
}
-void WorkerThread::terminate()
-{
- DCHECK(isMainThread());
- terminateInternal(TerminationMode::Graceful);
-}
-
-void WorkerThread::terminateAndWait()
-{
- DCHECK(isMainThread());
-
- // The main thread will be blocked, so asynchronous graceful shutdown does
- // not work.
- terminateInternal(TerminationMode::Forcible);
- m_shutdownEvent->wait();
-}
-
-void WorkerThread::terminateAndWaitForAllWorkers()
-{
- DCHECK(isMainThread());
-
- // Keep this lock to prevent WorkerThread instances from being destroyed.
- MutexLocker lock(threadSetMutex());
- HashSet<WorkerThread*> threads = workerThreads();
-
- // The main thread will be blocked, so asynchronous graceful shutdown does
- // not work.
- for (WorkerThread* thread : threads)
- thread->terminateInternal(TerminationMode::Forcible);
-
- for (WorkerThread* thread : threads)
- thread->m_shutdownEvent->wait();
-}
-
-v8::Isolate* WorkerThread::isolate()
-{
- return workerBackingThread().isolate();
-}
-
-bool WorkerThread::isCurrentThread()
-{
- return m_started && workerBackingThread().backingThread().isCurrentThread();
-}
-
-void WorkerThread::postTask(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
-{
- workerBackingThread().backingThread().postTask(location, createWorkerThreadTask(std::move(task), true));
-}
-
-void WorkerThread::appendDebuggerTask(std::unique_ptr<CrossThreadClosure> task)
-{
- {
- MutexLocker lock(m_threadStateMutex);
- if (m_readyToShutdown)
- return;
- }
- m_inspectorTaskRunner->appendTask(threadSafeBind(&WorkerThread::runDebuggerTaskOnWorkerThread, AllowCrossThreadAccess(this), passed(std::move(task))));
- {
- MutexLocker lock(m_threadStateMutex);
- if (isolate())
- m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate());
- }
- workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::runDebuggerTaskDontWaitOnWorkerThread, AllowCrossThreadAccess(this)));
-}
-
-void WorkerThread::startRunningDebuggerTasksOnPause()
-{
- m_pausedInDebugger = true;
- ThreadDebugger::idleStarted(isolate());
- std::unique_ptr<CrossThreadClosure> task;
- do {
- {
- SafePointScope safePointScope(BlinkGC::HeapPointersOnStack);
- task = m_inspectorTaskRunner->takeNextTask(InspectorTaskRunner::WaitForTask);
- }
- if (task)
- (*task)();
- // Keep waiting until execution is resumed.
- } while (task && m_pausedInDebugger);
- ThreadDebugger::idleFinished(isolate());
-}
-
-void WorkerThread::stopRunningDebuggerTasksOnPause()
-{
- m_pausedInDebugger = false;
-}
-
-WorkerGlobalScope* WorkerThread::workerGlobalScope()
-{
- DCHECK(isCurrentThread());
- return m_workerGlobalScope.get();
-}
-
-bool WorkerThread::terminated()
-{
- MutexLocker lock(m_threadStateMutex);
- return m_terminated;
-}
-
-unsigned WorkerThread::workerThreadCount()
-{
- MutexLocker lock(threadSetMutex());
- return workerThreads().size();
-}
-
-PlatformThreadId WorkerThread::platformThreadId()
-{
- if (!m_started)
- return 0;
- return workerBackingThread().backingThread().platformThread().threadId();
-}
-
WorkerThread::WorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerReportingProxy& workerReportingProxy)
- : m_forceTerminationDelayInMs(kForceTerminationDelayInMs)
- , m_inspectorTaskRunner(adoptPtr(new InspectorTaskRunner()))
+ : WorkerOrWorkletThread(workerReportingProxy)
, m_workerLoaderProxy(workerLoaderProxy)
- , m_workerReportingProxy(workerReportingProxy)
- , m_terminationEvent(adoptPtr(new WaitableEvent(
- WaitableEvent::ResetPolicy::Manual,
- WaitableEvent::InitialState::NonSignaled)))
- , m_shutdownEvent(adoptPtr(new WaitableEvent(
- WaitableEvent::ResetPolicy::Manual,
- WaitableEvent::InitialState::NonSignaled)))
{
- MutexLocker lock(threadSetMutex());
- workerThreads().add(this);
-}
-
-std::unique_ptr<CrossThreadClosure> WorkerThread::createWorkerThreadTask(std::unique_ptr<ExecutionContextTask> task, bool isInstrumented)
-{
- if (isInstrumented)
- isInstrumented = !task->taskNameForInstrumentation().isEmpty();
- if (isInstrumented) {
- DCHECK(isCurrentThread());
- InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worker task", task.get());
- }
- return threadSafeBind(&WorkerThread::performTaskOnWorkerThread, AllowCrossThreadAccess(this), passed(std::move(task)), isInstrumented);
-}
-
-void WorkerThread::terminateInternal(TerminationMode mode)
-{
- DCHECK(m_started);
-
- // Prevent the deadlock between GC and an attempt to terminate a thread.
- SafePointScope safePointScope(BlinkGC::HeapPointersOnStack);
-
- // Protect against this method, initializeOnWorkerThread() or termination
- // via the global scope racing each other.
- MutexLocker lock(m_threadStateMutex);
-
- // If terminate has already been called.
- if (m_terminated) {
- // The synchronous forcible termination request should overtake the
- // scheduled termination task because the request will block the main
- // thread and the scheduled termination task never runs.
- if (mode == TerminationMode::Forcible && m_exitCode == ExitCode::NotTerminated) {
- DCHECK(m_scheduledForceTerminationTask);
- m_scheduledForceTerminationTask.reset();
- forciblyTerminateExecution();
- DCHECK_EQ(ExitCode::NotTerminated, m_exitCode);
- m_exitCode = ExitCode::SyncForciblyTerminated;
- }
- return;
- }
- m_terminated = true;
-
- // Signal the thread to notify that the thread's stopping.
- if (m_terminationEvent)
- m_terminationEvent->signal();
-
- // If the worker thread was never initialized, don't start another
- // shutdown, but still wait for the thread to signal when shutdown has
- // completed on initializeOnWorkerThread().
- if (!m_workerGlobalScope) {
- DCHECK_EQ(ExitCode::NotTerminated, m_exitCode);
- m_exitCode = ExitCode::GracefullyTerminated;
- return;
- }
-
- // Determine if we should synchronously terminate or schedule to terminate
- // the worker execution so that the task can be handled by thread event
- // loop. If script execution weren't forbidden, a while(1) loop in JS could
- // keep the thread alive forever.
- //
- // (1) |m_readyToShutdown|: It this is set, the worker thread has already
- // noticed that the thread is about to be terminated and the worker global
- // scope is already disposed, so we don't have to explicitly terminate the
- // worker execution.
- //
- // (2) |workerScriptCount() == 1|: If other WorkerGlobalScopes are running
- // on the worker thread, we should not terminate the worker execution. This
- // condition is not entirely correct because other scripts can be being
- // initialized or terminated simuletaneously. Though this function itself is
- // protected by a mutex, it is possible that |workerScriptCount()| here is
- // not consistent with that in |initialize| and |shutdown|.
- //
- // (3) |m_runningDebuggerTask|: Terminating during debugger task may lead to
- // crash due to heavy use of v8 api in debugger. Any debugger task is
- // guaranteed to finish, so we can wait for the completion.
- bool shouldScheduleToTerminateExecution = !m_readyToShutdown && (workerBackingThread().workerScriptCount() == 1) && !m_runningDebuggerTask;
-
- if (shouldScheduleToTerminateExecution) {
- if (mode == TerminationMode::Forcible) {
- forciblyTerminateExecution();
- DCHECK_EQ(ExitCode::NotTerminated, m_exitCode);
- m_exitCode = ExitCode::SyncForciblyTerminated;
- } else {
- DCHECK_EQ(TerminationMode::Graceful, mode);
- DCHECK(!m_scheduledForceTerminationTask);
- m_scheduledForceTerminationTask = ForceTerminationTask::create(this);
- m_scheduledForceTerminationTask->schedule();
- }
- }
-
- m_inspectorTaskRunner->kill();
- workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::prepareForShutdownOnWorkerThread, AllowCrossThreadAccess(this)));
- workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::performShutdownOnWorkerThread, AllowCrossThreadAccess(this)));
-}
-
-void WorkerThread::forciblyTerminateExecution()
-{
- DCHECK(m_workerGlobalScope);
- m_workerGlobalScope->scriptController()->willScheduleExecutionTermination();
- isolate()->TerminateExecution();
}
void WorkerThread::initializeOnWorkerThread(PassOwnPtr<WorkerThreadStartupData> startupData)
@@ -403,177 +94,22 @@ void WorkerThread::initializeOnWorkerThread(PassOwnPtr<WorkerThreadStartupData>
OwnPtr<Vector<char>> cachedMetaData = std::move(startupData->m_cachedMetaData);
V8CacheOptions v8CacheOptions = startupData->m_v8CacheOptions;
- {
- MutexLocker lock(m_threadStateMutex);
-
- // The worker was terminated before the thread had a chance to run.
- if (m_terminated) {
- DCHECK_EQ(ExitCode::GracefullyTerminated, m_exitCode);
-
- // Notify the proxy that the WorkerGlobalScope has been disposed of.
- // This can free this thread object, hence it must not be touched
- // afterwards.
- m_workerReportingProxy.workerThreadTerminated();
-
- // Notify the main thread that it is safe to deallocate our
- // resources.
- m_shutdownEvent->signal();
- return;
- }
-
- workerBackingThread().attach();
-
- if (shouldAttachThreadDebugger())
- V8PerIsolateData::from(isolate())->setThreadDebugger(adoptPtr(new WorkerThreadDebugger(this, isolate())));
- m_microtaskRunner = adoptPtr(new WorkerMicrotaskRunner(this));
- workerBackingThread().backingThread().addTaskObserver(m_microtaskRunner.get());
-
- // Optimize for memory usage instead of latency for the worker isolate.
- isolate()->IsolateInBackgroundNotification();
- m_workerGlobalScope = createWorkerGlobalScope(std::move(startupData));
- m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.get() ? cachedMetaData->size() : 0);
-
- // Notify proxy that a new WorkerGlobalScope has been created and started.
- m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get());
+ WorkerGlobalScopeFactory factory(*this, std::move(startupData));
+ initializeGlobalScope(factory);
+ if (m_terminated)
+ return;
- WorkerOrWorkletScriptController* scriptController = m_workerGlobalScope->scriptController();
- if (!scriptController->isExecutionForbidden()) {
- scriptController->initializeContextIfNeeded();
-
- // If Origin Trials have been registered before the V8 context was ready,
- // then inject them into the context now
- ExecutionContext* executionContext = m_workerGlobalScope->getExecutionContext();
- if (executionContext) {
- OriginTrialContext* originTrialContext = OriginTrialContext::from(executionContext);
- if (originTrialContext)
- originTrialContext->initializePendingFeatures();
- }
- }
- }
+ toWorkerGlobalScope(globalScope())->scriptLoaded(sourceCode.length(), cachedMetaData.get() ? cachedMetaData->size() : 0);
if (startMode == PauseWorkerGlobalScopeOnStart)
startRunningDebuggerTasksOnPause();
- if (m_workerGlobalScope->scriptController()->isContextInitialized()) {
- m_workerReportingProxy.didInitializeWorkerContext();
- v8::HandleScope handleScope(isolate());
- Platform::current()->workerContextCreated(m_workerGlobalScope->scriptController()->context());
- }
-
- CachedMetadataHandler* handler = workerGlobalScope()->createWorkerScriptCachedMetadataHandler(scriptURL, cachedMetaData.get());
- bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourceCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions);
- m_workerGlobalScope->didEvaluateWorkerScript();
- m_workerReportingProxy.didEvaluateWorkerScript(success);
+ CachedMetadataHandler* handler = toWorkerGlobalScope(globalScope())->createWorkerScriptCachedMetadataHandler(scriptURL, cachedMetaData.get());
+ bool success = globalScope()->scriptController()->evaluate(ScriptSourceCode(sourceCode, scriptURL), nullptr, handler, v8CacheOptions);
+ toWorkerGlobalScope(globalScope())->didEvaluateWorkerScript();
+ workerReportingProxy().didEvaluateWorkerScript(success);
postInitialize();
}
-void WorkerThread::prepareForShutdownOnWorkerThread()
-{
- DCHECK(isCurrentThread());
- {
- MutexLocker lock(m_threadStateMutex);
- if (m_readyToShutdown)
- return;
- m_readyToShutdown = true;
- if (m_exitCode == ExitCode::NotTerminated)
- m_exitCode = ExitCode::GracefullyTerminated;
- }
-
- workerReportingProxy().willDestroyWorkerGlobalScope();
- InspectorInstrumentation::allAsyncTasksCanceled(workerGlobalScope());
- workerGlobalScope()->dispose();
- workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.get());
-}
-
-void WorkerThread::performShutdownOnWorkerThread()
-{
- DCHECK(isCurrentThread());
-#if DCHECK_IS_ON
- {
- MutexLocker lock(m_threadStateMutex);
- DCHECK(m_terminated);
- DCHECK(m_readyToShutdown);
- }
-#endif
-
- // 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.
- m_workerGlobalScope->notifyContextDestroyed();
- m_workerGlobalScope = nullptr;
-
- workerBackingThread().detach();
- // We must not touch workerBackingThread() from now on.
-
- m_microtaskRunner = nullptr;
-
- // Notify the proxy that the WorkerGlobalScope has been disposed of.
- // This can free this thread object, hence it must not be touched
- // afterwards.
- workerReportingProxy().workerThreadTerminated();
-
- m_shutdownEvent->signal();
-}
-
-void WorkerThread::performTaskOnWorkerThread(std::unique_ptr<ExecutionContextTask> task, bool isInstrumented)
-{
- DCHECK(isCurrentThread());
- {
- MutexLocker lock(m_threadStateMutex);
- if (m_readyToShutdown)
- return;
- }
-
- WorkerGlobalScope* globalScope = 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 (!globalScope) {
- DCHECK(terminated());
- return;
- }
-
- InspectorInstrumentation::AsyncTask asyncTask(globalScope, task.get(), isInstrumented);
- task->performTask(globalScope);
-}
-
-void WorkerThread::runDebuggerTaskOnWorkerThread(std::unique_ptr<CrossThreadClosure> task)
-{
- DCHECK(isCurrentThread());
- InspectorTaskRunner::IgnoreInterruptsScope scope(m_inspectorTaskRunner.get());
- {
- MutexLocker lock(m_threadStateMutex);
- m_runningDebuggerTask = true;
- }
- ThreadDebugger::idleFinished(isolate());
- (*task)();
- ThreadDebugger::idleStarted(isolate());
- {
- MutexLocker lock(m_threadStateMutex);
- m_runningDebuggerTask = false;
-
- if (!m_terminated)
- return;
- // terminate() was called. Shutdown sequence will start soon.
- }
- // Stop further worker tasks to run after this point.
- prepareForShutdownOnWorkerThread();
-}
-
-void WorkerThread::runDebuggerTaskDontWaitOnWorkerThread()
-{
- DCHECK(isCurrentThread());
- std::unique_ptr<CrossThreadClosure> task = m_inspectorTaskRunner->takeNextTask(InspectorTaskRunner::DontWaitForTask);
- if (task)
- (*task)();
-}
-
-WorkerThread::ExitCode WorkerThread::getExitCode()
-{
- MutexLocker lock(m_threadStateMutex);
- return m_exitCode;
-}
-
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/workers/WorkerThread.h ('k') | third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698