// Copyright 2013 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 "content/browser/service_worker/embedded_worker_instance.h" #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/common/service_worker/embedded_worker_messages.h" #include "ipc/ipc_message.h" #include "url/gurl.h" namespace content { EmbeddedWorkerInstance::~EmbeddedWorkerInstance() { registry_->RemoveWorker(process_id_, embedded_worker_id_); } ServiceWorkerStatusCode EmbeddedWorkerInstance::Start( int64 service_worker_version_id, const GURL& script_url) { DCHECK(status_ == STOPPED); if (!ChooseProcess()) return SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND; status_ = STARTING; ServiceWorkerStatusCode status = registry_->StartWorker( process_id_, embedded_worker_id_, service_worker_version_id, script_url); if (status != SERVICE_WORKER_OK) { status_ = STOPPED; process_id_ = -1; } return status; } ServiceWorkerStatusCode EmbeddedWorkerInstance::Stop() { DCHECK(status_ == STARTING || status_ == RUNNING); ServiceWorkerStatusCode status = registry_->StopWorker(process_id_, embedded_worker_id_); if (status == SERVICE_WORKER_OK) status_ = STOPPING; return status; } ServiceWorkerStatusCode EmbeddedWorkerInstance::SendMessage( int request_id, const IPC::Message& message) { DCHECK(status_ == RUNNING); return registry_->Send(process_id_, new EmbeddedWorkerContextMsg_SendMessageToWorker( thread_id_, embedded_worker_id_, request_id, message)); } void EmbeddedWorkerInstance::AddProcessReference(int process_id) { ProcessRefMap::iterator found = process_refs_.find(process_id); if (found == process_refs_.end()) found = process_refs_.insert(std::make_pair(process_id, 0)).first; ++found->second; } void EmbeddedWorkerInstance::ReleaseProcessReference(int process_id) { ProcessRefMap::iterator found = process_refs_.find(process_id); if (found == process_refs_.end()) { NOTREACHED() << "Releasing unknown process ref " << process_id; return; } if (--found->second == 0) process_refs_.erase(found); } EmbeddedWorkerInstance::EmbeddedWorkerInstance( EmbeddedWorkerRegistry* registry, int embedded_worker_id) : registry_(registry), embedded_worker_id_(embedded_worker_id), status_(STOPPED), process_id_(-1), thread_id_(-1) { } void EmbeddedWorkerInstance::OnStarted(int thread_id) { // Stop is requested before OnStarted is sent back from the worker. if (status_ == STOPPING) return; DCHECK(status_ == STARTING); status_ = RUNNING; thread_id_ = thread_id; FOR_EACH_OBSERVER(Observer, observer_list_, OnStarted()); } void EmbeddedWorkerInstance::OnStopped() { status_ = STOPPED; process_id_ = -1; thread_id_ = -1; FOR_EACH_OBSERVER(Observer, observer_list_, OnStopped()); } void EmbeddedWorkerInstance::OnMessageReceived(int request_id, const IPC::Message& message) { FOR_EACH_OBSERVER(Observer, observer_list_, OnMessageReceived(request_id, message)); } void EmbeddedWorkerInstance::AddObserver(Observer* observer) { observer_list_.AddObserver(observer); } void EmbeddedWorkerInstance::RemoveObserver(Observer* observer) { observer_list_.RemoveObserver(observer); } bool EmbeddedWorkerInstance::ChooseProcess() { DCHECK_EQ(-1, process_id_); // Naive implementation; chooses a process which has the biggest number of // associated providers (so that hopefully likely live longer). ProcessRefMap::iterator max_ref_iter = process_refs_.end(); for (ProcessRefMap::iterator iter = process_refs_.begin(); iter != process_refs_.end(); ++iter) { if (max_ref_iter == process_refs_.end() || max_ref_iter->second < iter->second) max_ref_iter = iter; } if (max_ref_iter == process_refs_.end()) return false; process_id_ = max_ref_iter->first; return true; } } // namespace content