Commit 0b705112 authored by nhiroki's avatar nhiroki Committed by Commit bot

ServiceWorker: Get registration info and its version attributes in one lock operation

Registration info and its version attributes owned by SWProviderContext can be
accessed from both the main thread and the worker thread, so they are protected
by a lock operation. However, getter functions for those info and attributes are
separated and returned values could be in an invalid state due to interleaved
operations.

This CL merges getter functions (registration() and GetVersionAttributes()) into
GetRegistrationInfoAndVersionAttributes() and avoids such an unexpected state.

BUG=437677
TEST=should pass all existing tests

Review URL: https://codereview.chromium.org/885443006

Cr-Commit-Position: refs/heads/master@{#313470}
parent 487f74d7
...@@ -585,14 +585,16 @@ void ServiceWorkerDispatcher::SetReadyRegistration( ...@@ -585,14 +585,16 @@ void ServiceWorkerDispatcher::SetReadyRegistration(
if (client == provider_clients_.end()) if (client == provider_clients_.end())
return; return;
ServiceWorkerRegistrationObjectInfo info = ServiceWorkerRegistrationObjectInfo info;
provider->second->registration()->info(); ServiceWorkerVersionAttributes attrs;
bool found =
provider->second->GetRegistrationInfoAndVersionAttributes(&info, &attrs);
DCHECK(found);
WebServiceWorkerRegistrationImpl* registration = WebServiceWorkerRegistrationImpl* registration =
FindServiceWorkerRegistration(info, false); FindServiceWorkerRegistration(info, false);
if (!registration) { if (!registration) {
registration = CreateServiceWorkerRegistration(info, false); registration = CreateServiceWorkerRegistration(info, false);
ServiceWorkerVersionAttributes attrs =
provider->second->GetVersionAttributes();
registration->SetInstalling(GetServiceWorker(attrs.installing, false)); registration->SetInstalling(GetServiceWorker(attrs.installing, false));
registration->SetWaiting(GetServiceWorker(attrs.waiting, false)); registration->SetWaiting(GetServiceWorker(attrs.waiting, false));
registration->SetActive(GetServiceWorker(attrs.active, false)); registration->SetActive(GetServiceWorker(attrs.active, false));
......
...@@ -43,25 +43,21 @@ ServiceWorkerHandleReference* ServiceWorkerProviderContext::controller() { ...@@ -43,25 +43,21 @@ ServiceWorkerHandleReference* ServiceWorkerProviderContext::controller() {
return controller_.get(); return controller_.get();
} }
ServiceWorkerRegistrationHandleReference* bool ServiceWorkerProviderContext::GetRegistrationInfoAndVersionAttributes(
ServiceWorkerProviderContext::registration() { ServiceWorkerRegistrationObjectInfo* info,
ServiceWorkerVersionAttributes* attrs) {
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
return registration_.get(); if (!registration_)
} return false;
ServiceWorkerVersionAttributes
ServiceWorkerProviderContext::GetVersionAttributes() {
base::AutoLock lock(lock_);
DCHECK(registration_);
ServiceWorkerVersionAttributes attrs; *info = registration_->info();
if (installing_) if (installing_)
attrs.installing = installing_->info(); attrs->installing = installing_->info();
if (waiting_) if (waiting_)
attrs.waiting = waiting_->info(); attrs->waiting = waiting_->info();
if (active_) if (active_)
attrs.active = active_->info(); attrs->active = active_->info();
return attrs; return true;
} }
void ServiceWorkerProviderContext::SetVersionAttributes( void ServiceWorkerProviderContext::SetVersionAttributes(
......
...@@ -48,9 +48,10 @@ class ServiceWorkerProviderContext ...@@ -48,9 +48,10 @@ class ServiceWorkerProviderContext
int provider_id() const { return provider_id_; } int provider_id() const { return provider_id_; }
ServiceWorkerHandleReference* controller(); ServiceWorkerHandleReference* controller();
ServiceWorkerRegistrationHandleReference* registration();
ServiceWorkerVersionAttributes GetVersionAttributes(); bool GetRegistrationInfoAndVersionAttributes(
ServiceWorkerRegistrationObjectInfo* info,
ServiceWorkerVersionAttributes* attrs);
void SetVersionAttributes(ChangedVersionAttributesMask mask, void SetVersionAttributes(ChangedVersionAttributesMask mask,
const ServiceWorkerVersionAttributes& attrs); const ServiceWorkerVersionAttributes& attrs);
......
...@@ -49,7 +49,9 @@ void WebServiceWorkerProviderImpl::setClient( ...@@ -49,7 +49,9 @@ void WebServiceWorkerProviderImpl::setClient(
// for more context) // for more context)
GetDispatcher()->AddProviderClient(provider_id_, client); GetDispatcher()->AddProviderClient(provider_id_, client);
if (!context_->registration()) { ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
if (!context_->GetRegistrationInfoAndVersionAttributes(&info, &attrs)) {
// This provider is not associated with any registration. // This provider is not associated with any registration.
return; return;
} }
...@@ -57,12 +59,10 @@ void WebServiceWorkerProviderImpl::setClient( ...@@ -57,12 +59,10 @@ void WebServiceWorkerProviderImpl::setClient(
// Set .ready if the associated registration has the active service worker. // Set .ready if the associated registration has the active service worker.
if (context_->active_handle_id() != kInvalidServiceWorkerHandleId) { if (context_->active_handle_id() != kInvalidServiceWorkerHandleId) {
WebServiceWorkerRegistrationImpl* registration = WebServiceWorkerRegistrationImpl* registration =
GetDispatcher()->FindServiceWorkerRegistration( GetDispatcher()->FindServiceWorkerRegistration(info, false);
context_->registration()->info(), false);
if (!registration) { if (!registration) {
registration = GetDispatcher()->CreateServiceWorkerRegistration( registration =
context_->registration()->info(), false); GetDispatcher()->CreateServiceWorkerRegistration(info, false);
ServiceWorkerVersionAttributes attrs = context_->GetVersionAttributes();
registration->SetInstalling( registration->SetInstalling(
GetDispatcher()->GetServiceWorker(attrs.installing, false)); GetDispatcher()->GetServiceWorker(attrs.installing, false));
registration->SetWaiting( registration->SetWaiting(
......
...@@ -180,12 +180,7 @@ void EmbeddedWorkerContextClient::workerContextStarted( ...@@ -180,12 +180,7 @@ void EmbeddedWorkerContextClient::workerContextStarted(
g_worker_client_tls.Pointer()->Set(this); g_worker_client_tls.Pointer()->Set(this);
script_context_.reset(new ServiceWorkerScriptContext(this, proxy)); script_context_.reset(new ServiceWorkerScriptContext(this, proxy));
// This can be nullptr on EmbeddedWorkerBrowserTests. SetRegistrationInServiceWorkerGlobalScope();
// TODO(nhiroki): Remove this workaround. |registration()| should always be
// valid other than the test because the registration association message
// arrives before starting the worker context.
if (provider_context_->registration())
SetRegistrationInServiceWorkerGlobalScope();
Send(new EmbeddedWorkerHostMsg_WorkerScriptLoaded( Send(new EmbeddedWorkerHostMsg_WorkerScriptLoaded(
embedded_worker_id_, embedded_worker_id_,
...@@ -419,19 +414,21 @@ void EmbeddedWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope() { ...@@ -419,19 +414,21 @@ void EmbeddedWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope() {
DCHECK(provider_context_); DCHECK(provider_context_);
DCHECK(script_context_); DCHECK(script_context_);
ServiceWorkerRegistrationObjectInfo info;
ServiceWorkerVersionAttributes attrs;
bool found =
provider_context_->GetRegistrationInfoAndVersionAttributes(&info, &attrs);
if (!found)
return; // Cannot be associated with a registration in some tests.
ServiceWorkerDispatcher* dispatcher = ServiceWorkerDispatcher* dispatcher =
ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance( ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
thread_safe_sender()); thread_safe_sender());
// Register a registration with the dispatcher living on the worker thread. // Register a registration and its version attributes with the dispatcher
DCHECK(provider_context_->registration()); // living on the worker thread.
scoped_ptr<WebServiceWorkerRegistrationImpl> registration( scoped_ptr<WebServiceWorkerRegistrationImpl> registration(
dispatcher->CreateServiceWorkerRegistration( dispatcher->CreateServiceWorkerRegistration(info, false));
provider_context_->registration()->info(), false));
// Register workers with the dispatcher living on the worker thread.
ServiceWorkerVersionAttributes attrs =
provider_context_->GetVersionAttributes();
registration->SetInstalling( registration->SetInstalling(
dispatcher->GetServiceWorker(attrs.installing, false)); dispatcher->GetServiceWorker(attrs.installing, false));
registration->SetWaiting( registration->SetWaiting(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment