blob: ffbb1db55579be4673ded150a46e9bcce12f75a9 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/workers/ThreadedMessagingProxyBase.h"
#include "bindings/core/v8/SourceLocation.h"
#include "core/dom/Document.h"
#include "core/loader/DocumentLoader.h"
#include "core/workers/ParentFrameTaskRunners.h"
#include "core/workers/WorkerInspectorProxy.h"
#include "core/workers/WorkerThreadStartupData.h"
#include "wtf/CurrentTime.h"
namespace blink {
namespace {
static int s_liveMessagingProxyCount = 0;
} // namespace
ThreadedMessagingProxyBase::ThreadedMessagingProxyBase(ExecutionContext* executionContext)
: m_executionContext(executionContext)
, m_workerInspectorProxy(WorkerInspectorProxy::create())
, m_parentFrameTaskRunners(ParentFrameTaskRunners::create(toDocument(m_executionContext.get())->frame()))
, m_mayBeDestroyed(false)
, m_askedToTerminate(false)
{
DCHECK(isParentContextThread());
s_liveMessagingProxyCount++;
}
ThreadedMessagingProxyBase::~ThreadedMessagingProxyBase()
{
DCHECK(isParentContextThread());
if (m_loaderProxy)
m_loaderProxy->detachProvider(this);
s_liveMessagingProxyCount--;
}
int ThreadedMessagingProxyBase::proxyCount()
{
DCHECK(isMainThread());
return s_liveMessagingProxyCount;
}
void ThreadedMessagingProxyBase::initializeWorkerThread(std::unique_ptr<WorkerThreadStartupData> startupData)
{
DCHECK(isParentContextThread());
Document* document = toDocument(getExecutionContext());
double originTime = document->loader() ? document->loader()->timing().referenceMonotonicTime() : monotonicallyIncreasingTime();
m_loaderProxy = WorkerLoaderProxy::create(this);
m_workerThread = createWorkerThread(originTime);
m_workerThread->start(std::move(startupData));
workerThreadCreated();
}
void ThreadedMessagingProxyBase::postTaskToWorkerGlobalScope(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
{
if (m_askedToTerminate)
return;
DCHECK(m_workerThread);
m_workerThread->postTask(location, std::move(task));
}
void ThreadedMessagingProxyBase::postTaskToLoader(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
{
DCHECK(getExecutionContext()->isDocument());
// TODO(hiroshige,yuryu): Make this not use ExecutionContextTask and use
// m_parentFrameTaskRunners->get(TaskType::Networking) instead.
getExecutionContext()->postTask(location, std::move(task));
}
void ThreadedMessagingProxyBase::reportConsoleMessage(MessageSource source, MessageLevel level, const String& message, std::unique_ptr<SourceLocation> location)
{
DCHECK(isParentContextThread());
if (m_askedToTerminate)
return;
if (m_workerInspectorProxy)
m_workerInspectorProxy->addConsoleMessageFromWorker(level, message, std::move(location));
}
void ThreadedMessagingProxyBase::workerThreadCreated()
{
DCHECK(isParentContextThread());
DCHECK(!m_askedToTerminate);
DCHECK(m_workerThread);
}
void ThreadedMessagingProxyBase::parentObjectDestroyed()
{
DCHECK(isParentContextThread());
m_parentFrameTaskRunners->get(TaskType::Internal)->postTask(BLINK_FROM_HERE, WTF::bind(&ThreadedMessagingProxyBase::parentObjectDestroyedInternal, unretained(this)));
}
void ThreadedMessagingProxyBase::parentObjectDestroyedInternal()
{
DCHECK(isParentContextThread());
m_mayBeDestroyed = true;
if (m_workerThread)
terminateGlobalScope();
else
workerThreadTerminated();
}
void ThreadedMessagingProxyBase::workerThreadTerminated()
{
DCHECK(isParentContextThread());
// This method is always the last to be performed, so the proxy is not
// needed for communication in either side any more. However, the Worker
// object may still exist, and it assumes that the proxy exists, too.
m_askedToTerminate = true;
m_workerThread = nullptr;
m_workerInspectorProxy->workerThreadTerminated();
if (m_mayBeDestroyed)
delete this;
}
void ThreadedMessagingProxyBase::terminateGlobalScope()
{
DCHECK(isParentContextThread());
if (m_askedToTerminate)
return;
m_askedToTerminate = true;
if (m_workerThread)
m_workerThread->terminate();
m_workerInspectorProxy->workerThreadTerminated();
}
void ThreadedMessagingProxyBase::postMessageToPageInspector(const String& message)
{
DCHECK(isParentContextThread());
if (m_workerInspectorProxy)
m_workerInspectorProxy->dispatchMessageFromWorker(message);
}
bool ThreadedMessagingProxyBase::isParentContextThread() const
{
// TODO(nhiroki): Nested worker is not supported yet, so the parent context
// thread should be equal to the main thread (http://crbug.com/31666).
DCHECK(getExecutionContext()->isDocument());
return isMainThread();
}
} // namespace blink