blob: 87d8b54910445098e19c46148c2eb7359d88232a [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 "base/synchronization/waitable_event.h"
#include "bindings/core/v8/SourceLocation.h"
#include "core/dom/Document.h"
#include "core/frame/Deprecation.h"
#include "core/frame/WebLocalFrameImpl.h"
#include "core/loader/DocumentLoader.h"
#include "core/loader/ThreadableLoadingContext.h"
#include "core/loader/WorkerFetchContext.h"
#include "core/workers/GlobalScopeCreationParams.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerInspectorProxy.h"
#include "platform/loader/fetch/ResourceFetcher.h"
#include "platform/wtf/Time.h"
#include "public/platform/TaskType.h"
#include "public/platform/WebWorkerFetchContext.h"
#include "public/web/WebFrameClient.h"
namespace blink {
namespace {
static int g_live_messaging_proxy_count = 0;
} // namespace
ThreadedMessagingProxyBase::ThreadedMessagingProxyBase(
ExecutionContext* execution_context)
: execution_context_(execution_context),
worker_inspector_proxy_(WorkerInspectorProxy::Create()),
parent_frame_task_runners_(
ParentFrameTaskRunners::Create(execution_context_.Get())),
terminate_sync_load_event_(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
keep_alive_(this) {
DCHECK(IsParentContextThread());
g_live_messaging_proxy_count++;
}
ThreadedMessagingProxyBase::~ThreadedMessagingProxyBase() {
g_live_messaging_proxy_count--;
}
int ThreadedMessagingProxyBase::ProxyCount() {
DCHECK(IsMainThread());
return g_live_messaging_proxy_count;
}
void ThreadedMessagingProxyBase::Trace(blink::Visitor* visitor) {
visitor->Trace(execution_context_);
visitor->Trace(worker_inspector_proxy_);
}
void ThreadedMessagingProxyBase::InitializeWorkerThread(
std::unique_ptr<GlobalScopeCreationParams> global_scope_creation_params,
const WTF::Optional<WorkerBackingThreadStartupData>& thread_startup_data) {
DCHECK(IsParentContextThread());
KURL script_url = global_scope_creation_params->script_url.Copy();
std::unique_ptr<WebWorkerFetchContext> web_worker_fetch_context;
if (execution_context_->IsDocument()) {
// |web_frame| is null in some unit tests.
if (WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(
ToDocument(GetExecutionContext())->GetFrame())) {
web_worker_fetch_context =
web_frame->Client()->CreateWorkerFetchContext();
DCHECK(web_worker_fetch_context);
web_worker_fetch_context->SetApplicationCacheHostID(
GetExecutionContext()->Fetcher()->Context().ApplicationCacheHostID());
web_worker_fetch_context->SetIsOnSubframe(web_frame != web_frame->Top());
}
}
// TODO(japhet): Add a way to clone a WebWorkerFetchContext between worker
// threads for nested workers.
if (web_worker_fetch_context) {
web_worker_fetch_context->SetTerminateSyncLoadEvent(
&terminate_sync_load_event_);
ProvideWorkerFetchContextToWorker(
global_scope_creation_params->worker_clients,
std::move(web_worker_fetch_context));
}
worker_thread_ = CreateWorkerThread();
worker_thread_->Start(
std::move(global_scope_creation_params), thread_startup_data,
GetWorkerInspectorProxy()->ShouldPauseOnWorkerStart(execution_context_),
GetParentFrameTaskRunners());
GetWorkerInspectorProxy()->WorkerThreadCreated(execution_context_,
GetWorkerThread(), script_url);
}
void ThreadedMessagingProxyBase::CountFeature(WebFeature feature) {
DCHECK(IsParentContextThread());
UseCounter::Count(execution_context_, feature);
}
void ThreadedMessagingProxyBase::CountDeprecation(WebFeature feature) {
DCHECK(IsParentContextThread());
Deprecation::CountDeprecation(execution_context_, feature);
}
void ThreadedMessagingProxyBase::ReportConsoleMessage(
MessageSource source,
MessageLevel level,
const String& message,
std::unique_ptr<SourceLocation> location) {
DCHECK(IsParentContextThread());
if (asked_to_terminate_)
return;
execution_context_->AddConsoleMessage(ConsoleMessage::CreateFromWorker(
level, message, std::move(location), worker_thread_.get()));
}
void ThreadedMessagingProxyBase::ParentObjectDestroyed() {
DCHECK(IsParentContextThread());
if (worker_thread_) {
// Request to terminate the global scope. This will eventually call
// WorkerThreadTerminated().
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 parent
// Worker/Worklet object may still exist, and it assumes that the proxy
// exists, too.
asked_to_terminate_ = true;
worker_thread_ = nullptr;
worker_inspector_proxy_->WorkerThreadTerminated();
// If the parent Worker/Worklet object was already destroyed, this will
// destroy |this|.
keep_alive_.Clear();
}
void ThreadedMessagingProxyBase::TerminateGlobalScope() {
DCHECK(IsParentContextThread());
if (asked_to_terminate_)
return;
asked_to_terminate_ = true;
terminate_sync_load_event_.Signal();
if (worker_thread_)
worker_thread_->Terminate();
worker_inspector_proxy_->WorkerThreadTerminated();
}
void ThreadedMessagingProxyBase::PostMessageToPageInspector(
int session_id,
const String& message) {
DCHECK(IsParentContextThread());
if (worker_inspector_proxy_)
worker_inspector_proxy_->DispatchMessageFromWorker(session_id, message);
}
ThreadableLoadingContext*
ThreadedMessagingProxyBase::CreateThreadableLoadingContext() const {
DCHECK(IsParentContextThread());
return ThreadableLoadingContext::Create(*execution_context_);
}
ExecutionContext* ThreadedMessagingProxyBase::GetExecutionContext() const {
DCHECK(IsParentContextThread());
return execution_context_;
}
ParentFrameTaskRunners* ThreadedMessagingProxyBase::GetParentFrameTaskRunners()
const {
DCHECK(IsParentContextThread());
return parent_frame_task_runners_;
}
WorkerInspectorProxy* ThreadedMessagingProxyBase::GetWorkerInspectorProxy()
const {
DCHECK(IsParentContextThread());
return worker_inspector_proxy_;
}
WorkerThread* ThreadedMessagingProxyBase::GetWorkerThread() const {
DCHECK(IsParentContextThread());
return worker_thread_.get();
}
bool ThreadedMessagingProxyBase::IsParentContextThread() const {
return execution_context_->IsContextThread();
}
} // namespace blink