diff options
Diffstat (limited to 'chrome/browser')
6 files changed, 465 insertions, 22 deletions
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc index 1ea105c..8ef7ca4 100644 --- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc +++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc @@ -4,9 +4,19 @@ #include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h" +#include "base/stl_util-inl.h" +#include "base/string16.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/in_process_webkit/webkit_context.h" #include "chrome/browser/in_process_webkit/webkit_thread.h" +#include "chrome/common/render_messages.h" +#include "webkit/api/public/WebKit.h" +#include "webkit/api/public/WebStorageArea.h" +#include "webkit/api/public/WebStorageNamespace.h" +#include "webkit/api/public/WebString.h" + +using WebKit::WebStorageArea; +using WebKit::WebStorageNamespace; DOMStorageDispatcherHost::DOMStorageDispatcherHost( IPC::Message::Sender* message_sender, @@ -14,24 +24,78 @@ DOMStorageDispatcherHost::DOMStorageDispatcherHost( WebKitThread* webkit_thread) : webkit_context_(webkit_context), webkit_thread_(webkit_thread), - message_sender_(message_sender) { + message_sender_(message_sender), + last_storage_area_id_(0), + last_storage_namespace_id_(0), + ever_used_(false), + shutdown_(false) { DCHECK(webkit_context_.get()); DCHECK(webkit_thread_); DCHECK(message_sender_); } DOMStorageDispatcherHost::~DOMStorageDispatcherHost() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - message_sender_ = NULL; + DCHECK(!ever_used_ || ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + DCHECK(shutdown_); +} + +void DOMStorageDispatcherHost::Shutdown() { + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + message_sender_ = NULL; + if (!ever_used_) { + shutdown_ = true; + return; + } + + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::Shutdown)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + DCHECK(ever_used_); + DCHECK(!message_sender_); + DCHECK(!shutdown_); + + STLDeleteContainerPairSecondPointers(storage_area_map_.begin(), + storage_area_map_.end()); + STLDeleteContainerPairSecondPointers(storage_namespace_map_.begin(), + storage_namespace_map_.end()); + shutdown_ = true; } -bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& msg) { - // TODO(jorlow): Implement DOM Storage's message handler...and the rest - // of DOM Storage. :-) - return false; +bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& message, + bool *msg_is_ok) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(!shutdown_); + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageDispatcherHost, message, *msg_is_ok) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageNamespaceId, + OnNamespaceId) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageCloneNamespaceId, + OnCloneNamespaceId) + IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageDerefNamespaceId, + OnDerefNamespaceId) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageStorageAreaId, + OnStorageAreaId) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLock, OnLock) + IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageUnlock, OnUnlock) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLength, OnLength) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageKey, OnKey) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageGetItem, OnGetItem) + IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageSetItem, OnSetItem) + IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageRemoveItem, OnRemoveItem) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageClear, OnClear) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + if (handled) + ever_used_ = true; + return handled; } void DOMStorageDispatcherHost::Send(IPC::Message* message) { + DCHECK(!shutdown_); if (!message_sender_) { delete message; return; @@ -42,11 +106,277 @@ void DOMStorageDispatcherHost::Send(IPC::Message* message) { return; } - // The IO thread can't dissapear while the WebKit thread is still running. + // The IO thread can't go away while the WebKit thread is still running. + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + webkit_thread_->PostIOThreadTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::Send, message)); +} + +void DOMStorageDispatcherHost::OnNamespaceId(bool is_local_storage, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnNamespaceId, + is_local_storage, reply_msg)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + WebStorageNamespace* new_namespace; + if (is_local_storage) { + new_namespace = WebStorageNamespace::createLocalStorageNamespace( + GetLocalStoragePath()); + } else { + new_namespace = WebStorageNamespace::createSessionStorageNamespace(); + } + int64 new_namespace_id = AddStorageNamespace(new_namespace); + ViewHostMsg_DOMStorageNamespaceId::WriteReplyParams(reply_msg, + new_namespace_id); + Send(reply_msg); +} + +void DOMStorageDispatcherHost::OnCloneNamespaceId(int64 namespace_id, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnCloneNamespaceId, + namespace_id, reply_msg)); + return; + } + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); - MessageLoop* io_loop = ChromeThread::GetMessageLoop(ChromeThread::IO); - CancelableTask* task = NewRunnableMethod(this, - &DOMStorageDispatcherHost::Send, - message); - io_loop->PostTask(FROM_HERE, task); + WebStorageNamespace* existing_namespace = GetStorageNamespace(namespace_id); + CHECK(existing_namespace); // TODO(jorlow): Do better than this. + WebStorageNamespace* new_namespace = existing_namespace->copy(); + int64 new_namespace_id = AddStorageNamespace(new_namespace); + ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg, + new_namespace_id); + Send(reply_msg); +} + +void DOMStorageDispatcherHost::OnDerefNamespaceId(int64 namespace_id) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnDerefNamespaceId, namespace_id)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + // TODO(jorlow): We need to track resources so we can free them. +} + +void DOMStorageDispatcherHost::OnStorageAreaId(int64 namespace_id, + const string16& origin, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnStorageAreaId, + namespace_id, origin, reply_msg)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + WebStorageNamespace* storage_namespace = GetStorageNamespace(namespace_id); + CHECK(storage_namespace); // TODO(jorlow): Do better than this. + WebStorageArea* storage_area = storage_namespace->createStorageArea(origin); + int64 storage_area_id = AddStorageArea(storage_area); + ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg, + storage_area_id); + Send(reply_msg); +} + +void DOMStorageDispatcherHost::OnLock(int64 storage_area_id, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnLock, storage_area_id, reply_msg)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + bool invalidate_cache; + size_t bytes_left_in_quota; + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + storage_area->lock(invalidate_cache, bytes_left_in_quota); + ViewHostMsg_DOMStorageLock::WriteReplyParams(reply_msg, invalidate_cache, + bytes_left_in_quota); + Send(reply_msg); +} + +void DOMStorageDispatcherHost::OnUnlock(int64 storage_area_id) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnUnlock, storage_area_id)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + storage_area->unlock(); +} + +void DOMStorageDispatcherHost::OnLength(int64 storage_area_id, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnLength, storage_area_id, reply_msg)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + unsigned length = storage_area->length(); + ViewHostMsg_DOMStorageLength::WriteReplyParams(reply_msg, length); + Send(reply_msg); +} + +void DOMStorageDispatcherHost::OnKey(int64 storage_area_id, unsigned index, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnKey, storage_area_id, index, reply_msg)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + bool key_exception = false; + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + string16 key = storage_area->key(index, key_exception); + ViewHostMsg_DOMStorageKey::WriteReplyParams(reply_msg, key_exception, key); + Send(reply_msg); +} + +void DOMStorageDispatcherHost::OnGetItem(int64 storage_area_id, + const string16& key, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnGetItem, + storage_area_id, key, reply_msg)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + WebKit::WebString value = storage_area->getItem(key); + ViewHostMsg_DOMStorageGetItem::WriteReplyParams(reply_msg, (string16)value, + value.isNull()); + Send(reply_msg); +} + +void DOMStorageDispatcherHost::OnSetItem(int64 storage_area_id, + const string16& key, + const string16& value) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnSetItem, storage_area_id, key, value)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + bool quota_exception = false; + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + storage_area->setItem(key, value, quota_exception); + DCHECK(!quota_exception); // This is tracked by the renderer. +} + +void DOMStorageDispatcherHost::OnRemoveItem(int64 storage_area_id, + const string16& key) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnRemoveItem, storage_area_id, key)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + storage_area->removeItem(key); +} + +void DOMStorageDispatcherHost::OnClear(int64 storage_area_id, + IPC::Message* reply_msg) { + DCHECK(!shutdown_); + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); + webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, + &DOMStorageDispatcherHost::OnClear, storage_area_id, reply_msg)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + // TODO(jorlow): Return the total quota for this domain. + size_t bytes_left_in_quota = 0; + WebStorageArea* storage_area = GetStorageArea(storage_area_id); + CHECK(storage_area); // TODO(jorlow): Do better than this. + storage_area->clear(); + ViewHostMsg_DOMStorageClear::WriteReplyParams(reply_msg, + bytes_left_in_quota); + Send(reply_msg); +} + +WebStorageArea* DOMStorageDispatcherHost::GetStorageArea(int64 id) { + StorageAreaMap::iterator iterator = storage_area_map_.find(id); + if (iterator == storage_area_map_.end()) + return NULL; + return iterator->second; +} + +WebStorageNamespace* DOMStorageDispatcherHost::GetStorageNamespace(int64 id) { + StorageNamespaceMap::iterator iterator = storage_namespace_map_.find(id); + if (iterator == storage_namespace_map_.end()) + return NULL; + return iterator->second; +} + +int64 DOMStorageDispatcherHost::AddStorageArea( + WebStorageArea* new_storage_area) { + // Create a new ID and insert it into our map. + int64 new_storage_area_id = ++last_storage_area_id_; + DCHECK(!GetStorageArea(new_storage_area_id)); + storage_area_map_[new_storage_area_id] = new_storage_area; + return new_storage_area_id; +} + +int64 DOMStorageDispatcherHost::AddStorageNamespace( + WebStorageNamespace* new_namespace) { + // Create a new ID and insert it into our map. + int64 new_namespace_id = ++last_storage_namespace_id_; + DCHECK(!GetStorageNamespace(new_namespace_id)); + storage_namespace_map_[new_namespace_id] = new_namespace; + return new_namespace_id; +} + +string16 DOMStorageDispatcherHost::GetLocalStoragePath() { + // TODO(jorlow): Create a path based on the WebKitContext. + string16 path; + return path; } diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h index edc8822..8e7e12f 100644 --- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h +++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h @@ -5,16 +5,22 @@ #ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_ #define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_ +#include "base/hash_tables.h" +#include "base/scoped_ptr.h" #include "base/ref_counted.h" #include "ipc/ipc_message.h" class WebKitContext; class WebKitThread; +namespace WebKit { +class WebStorageArea; +class WebStorageNamespace; +} + // This class handles the logistics of DOM Storage within the browser process. // It mostly ferries information between IPCs and the WebKit implementations, // but it also handles some special cases like when renderer processes die. -// THIS CLASS MUST NOT BE DESTROYED ON THE WEBKIT THREAD. class DOMStorageDispatcherHost : public base::RefCountedThreadSafe<DOMStorageDispatcherHost> { public: @@ -22,8 +28,9 @@ class DOMStorageDispatcherHost : DOMStorageDispatcherHost(IPC::Message::Sender* message_sender, WebKitContext*, WebKitThread*); - // Only call from IO thread. - bool OnMessageReceived(const IPC::Message& message); + // Only call from ResourceMessageFilter on the IO thread. + void Shutdown(); + bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok); // Send a message to the renderer process associated with our // message_sender_ via the IO thread. May be called from any thread. @@ -33,6 +40,37 @@ class DOMStorageDispatcherHost : friend class base::RefCountedThreadSafe<DOMStorageDispatcherHost>; ~DOMStorageDispatcherHost(); + // Message Handlers. + void OnNamespaceId(bool is_local_storage, IPC::Message* reply_msg); + void OnCloneNamespaceId(int64 namespace_id, IPC::Message* reply_msg); + void OnDerefNamespaceId(int64 namespace_id); + void OnStorageAreaId(int64 namespace_id, const string16& origin, + IPC::Message* reply_msg); + void OnLock(int64 storage_area_id, IPC::Message* reply_msg); + void OnUnlock(int64 storage_area_id); + void OnLength(int64 storage_area_id, IPC::Message* reply_msg); + void OnKey(int64 storage_area_id, unsigned index, IPC::Message* reply_msg); + void OnGetItem(int64 storage_area_id, const string16& key, + IPC::Message* reply_msg); + void OnSetItem(int64 storage_area_id, const string16& key, + const string16& value); + void OnRemoveItem(int64 storage_area_id, const string16& key); + void OnClear(int64 storage_area_id, IPC::Message* reply_msg); + + // Get a WebStorageNamespace or WebStorageArea based from its ID. Only call + // on the WebKit thread. + WebKit::WebStorageArea* GetStorageArea(int64 id); + WebKit::WebStorageNamespace* GetStorageNamespace(int64 id); + + // Add a WebStorageNamespace or WebStorageArea and get a new unique ID for + // it. Only call on the WebKit thread. + int64 AddStorageArea(WebKit::WebStorageArea* new_storage_area); + int64 AddStorageNamespace(WebKit::WebStorageNamespace* new_namespace); + + // Get the path to the LocalStorage directory. Calculate it if we haven't + // already. Only call on the WebKit thread. + string16 GetLocalStoragePath(); + // Data shared between renderer processes with the same profile. scoped_refptr<WebKitContext> webkit_context_; @@ -42,6 +80,32 @@ class DOMStorageDispatcherHost : // Only set on the IO thread. IPC::Message::Sender* message_sender_; + // The last used storage_area_id and storage_namespace_id's. Only use on the + // WebKit thread. + int64 last_storage_area_id_; + int64 last_storage_namespace_id_; + + // Used to maintain a mapping between storage_area_id's used in IPC messages + // and the actual WebStorageArea instances. Only use on the WebKit thread. + typedef base::hash_map<int64, WebKit::WebStorageArea*> StorageAreaMap; + StorageAreaMap storage_area_map_; + + // Mapping between storage_namespace_id's used in IPC messages and the + // WebStorageNamespace instances. Only use on the WebKit thread. + typedef base::hash_map<int64, WebKit::WebStorageNamespace*> + StorageNamespaceMap; + StorageNamespaceMap storage_namespace_map_; + + // Has this dispatcher ever handled a message. If not, then we can skip + // the entire shutdown procedure. This is only set to true on the IO thread + // and must be true if we're reading it on the WebKit thread. + bool ever_used_; + + // This is set once the Shutdown routine runs on the WebKit thread. Once + // set, we should not process any more messages because storage_area_map_ + // and storage_namespace_map_ contain pointers to deleted objects. + bool shutdown_; + DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageDispatcherHost); }; diff --git a/chrome/browser/in_process_webkit/webkit_thread.cc b/chrome/browser/in_process_webkit/webkit_thread.cc index 19cf65b..96384e9 100644 --- a/chrome/browser/in_process_webkit/webkit_thread.cc +++ b/chrome/browser/in_process_webkit/webkit_thread.cc @@ -10,13 +10,41 @@ #include "webkit/api/public/WebKit.h" // This happens on the UI thread before the IO thread has been shut down. -WebKitThread::WebKitThread() { +WebKitThread::WebKitThread() + : io_message_loop_(ChromeThread::GetMessageLoop(ChromeThread::IO)) { // The thread is started lazily by InitializeThread() on the IO thread. } // This happens on the UI thread after the IO thread has been shut down. WebKitThread::~WebKitThread() { + // There's no good way to see if we're on the UI thread. DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(!io_message_loop_); +} + +void WebKitThread::Shutdown() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(io_message_loop_); + + // TODO(jorlow): Start flushing LocalStorage? + + AutoLock lock(io_message_loop_lock_); + io_message_loop_ = NULL; +} + +bool WebKitThread::PostIOThreadTask( + const tracked_objects::Location& from_here, Task* task) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + { + AutoLock lock(io_message_loop_lock_); + if (io_message_loop_) { + io_message_loop_->PostTask(from_here, task); + return true; + } + } + delete task; + return false; } WebKitThread::InternalWebKitThread::InternalWebKitThread() @@ -29,13 +57,12 @@ void WebKitThread::InternalWebKitThread::Init() { webkit_client_ = new BrowserWebKitClientImpl; DCHECK(webkit_client_); WebKit::initialize(webkit_client_); - // Don't do anything heavyweight here since this can block the IO thread from - // executing (since InitializeThread() is called on the IO thread). + // If possible, post initialization tasks to this thread (rather than doing + // them now) so we don't block the IO thread any longer than we have to. } void WebKitThread::InternalWebKitThread::CleanUp() { - // Don't do anything heavyweight here since this can block the IO thread from - // executing (since the thread is shutdown from the IO thread). + // TODO(jorlow): Block on LocalStorage being 100% shut down. DCHECK(webkit_client_); WebKit::shutdown(); delete webkit_client_; @@ -45,6 +72,7 @@ MessageLoop* WebKitThread::InitializeThread() { if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) return NULL; + DCHECK(io_message_loop_); DCHECK(!webkit_thread_.get()); webkit_thread_.reset(new InternalWebKitThread); bool started = webkit_thread_->Start(); diff --git a/chrome/browser/in_process_webkit/webkit_thread.h b/chrome/browser/in_process_webkit/webkit_thread.h index 49ad7ac..8ab1113 100644 --- a/chrome/browser/in_process_webkit/webkit_thread.h +++ b/chrome/browser/in_process_webkit/webkit_thread.h @@ -35,6 +35,15 @@ class WebKitThread { return webkit_thread_->message_loop(); } + // Called from the IO thread. Notifies us that it's no longer safe to post + // tasks to the IO thread. + void Shutdown(); + + // Post a task to the IO thread if we haven't yet been told to shut down. + // Only call from the WebKit thread. + bool PostIOThreadTask(const tracked_objects::Location& from_here, + Task* task); + private: // Must be private so that we can carefully control its lifetime. class InternalWebKitThread : public ChromeThread { @@ -58,6 +67,11 @@ class WebKitThread { // from the IO thread while the WebKit thread is not running. scoped_ptr<InternalWebKitThread> webkit_thread_; + // A pointer to the IO message loop. This is nulled out when Shutdown() is + // called. Only access under the io_message_loop_lock_. + MessageLoop* io_message_loop_; + Lock io_message_loop_lock_; + DISALLOW_COPY_AND_ASSIGN(WebKitThread); }; diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc index 35a47f0..9ac5b7f 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.cc +++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc @@ -259,6 +259,9 @@ void ResourceDispatcherHost::OnShutdown() { // runs if the timer is still running the Task is deleted twice (once by // the MessageLoop and the second time by RepeatingTimer). update_load_states_timer_.Stop(); + // Let the WebKit thread know the IO thread is going away soon and that it + // should prepare for its own shutdown soon after. + webkit_thread_->Shutdown(); } bool ResourceDispatcherHost::HandleExternalProtocol(int request_id, diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 41b0b35..f369191 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -169,6 +169,9 @@ ResourceMessageFilter::~ResourceMessageFilter() { // This function should be called on the IO thread. DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + // Tell the DOM Storage dispatcher host to stop sending messages via us. + dom_storage_dispatcher_host_->Shutdown(); + // Let interested observers know we are being deleted. NotificationService::current()->Notify( NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN, @@ -244,7 +247,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { message, this, &msg_is_ok) || app_cache_dispatcher_host_->OnMessageReceived( message, &msg_is_ok) || - dom_storage_dispatcher_host_->OnMessageReceived(message) || + dom_storage_dispatcher_host_->OnMessageReceived( + message, &msg_is_ok) || audio_renderer_host_->OnMessageReceived(message, &msg_is_ok); if (!handled) { |