diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/chrome_thread.cc | 12 | ||||
-rw-r--r-- | chrome/browser/chrome_thread.h | 14 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc | 36 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h | 22 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/webkit_thread.cc | 58 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/webkit_thread.h | 55 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/webkit_thread_unittest.cc | 11 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_dispatcher_host.h | 5 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 11 |
9 files changed, 91 insertions, 133 deletions
diff --git a/chrome/browser/chrome_thread.cc b/chrome/browser/chrome_thread.cc index 762ae76..4ef8480 100644 --- a/chrome/browser/chrome_thread.cc +++ b/chrome/browser/chrome_thread.cc @@ -9,6 +9,7 @@ static const char* chrome_thread_names[ChromeThread::ID_COUNT] = { "Chrome_IOThread", // IO "Chrome_FileThread", // FILE "Chrome_DBThread", // DB + "Chrome_WebKitThread", // WEBKIT "Chrome_HistoryThread", // HISTORY #if defined(OS_LINUX) "Chrome_Background_X11Thread", // BACKGROUND_X11 @@ -21,6 +22,7 @@ ChromeThread* ChromeThread::chrome_threads_[ID_COUNT] = { NULL, // IO NULL, // FILE NULL, // DB + NULL, // WEBKIT NULL, // HISTORY #if defined(OS_LINUX) NULL, // BACKGROUND_X11 @@ -51,3 +53,13 @@ MessageLoop* ChromeThread::GetMessageLoop(ID identifier) { return NULL; } + +// static +bool ChromeThread::CurrentlyOn(ID identifier) { + // MessageLoop::current() will return NULL if none is running. This is often + // true when running under unit tests. This behavior actually works out + // pretty convienently (as is mentioned in the header file comment), but it's + // worth noting here. + MessageLoop* message_loop = GetMessageLoop(identifier); + return MessageLoop::current() == message_loop; +} diff --git a/chrome/browser/chrome_thread.h b/chrome/browser/chrome_thread.h index 1fd1901..4978214 100644 --- a/chrome/browser/chrome_thread.h +++ b/chrome/browser/chrome_thread.h @@ -38,6 +38,10 @@ class ChromeThread : public base::Thread { // This is the thread that interacts with the database. DB, + // This is the "main" thread for WebKit within the browser process when + // NOT in --single-process mode. + WEBKIT, + // This is the thread that interacts with the history database. HISTORY, @@ -68,6 +72,16 @@ class ChromeThread : public base::Thread { // static MessageLoop* GetMessageLoop(ID identifier); + // Callable on any thread. Returns whether you're currently on a particular + // thread. + // + // WARNING: + // When running under unit-tests, this will return true if you're on the + // main thread and the thread ID you pass in isn't running. This is + // normally the correct behavior because you want to ignore these asserts + // unless you've specifically spun up the threads, but be mindful of it. + static bool CurrentlyOn(ID identifier); + private: // The identifier of this thread. Only one thread can exist with a given // identifier at a given time. 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 cbbf9ff..1ea105c 100644 --- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc +++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc @@ -16,17 +16,12 @@ DOMStorageDispatcherHost::DOMStorageDispatcherHost( webkit_thread_(webkit_thread), message_sender_(message_sender) { DCHECK(webkit_context_.get()); - DCHECK(webkit_thread_.get()); + DCHECK(webkit_thread_); DCHECK(message_sender_); } DOMStorageDispatcherHost::~DOMStorageDispatcherHost() { - DCHECK(!message_sender_); -} - -void DOMStorageDispatcherHost::Shutdown() { - DCHECK(IsOnIOThread()); - AutoLock lock(message_sender_lock_); + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); message_sender_ = NULL; } @@ -37,34 +32,21 @@ bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& msg) { } void DOMStorageDispatcherHost::Send(IPC::Message* message) { - if (IsOnIOThread()) { - if (message_sender_) - message_sender_->Send(message); - else - delete message; - } - - // If message_sender_ is NULL, the IO thread has either gone away - // or will do so soon. By holding this lock until we finish posting to the - // thread, we block the IO thread from completely shutting down benieth us. - AutoLock lock(message_sender_lock_); if (!message_sender_) { delete message; return; } + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + message_sender_->Send(message); + return; + } + + // The IO thread can't dissapear while the WebKit thread is still running. + 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); } - -bool DOMStorageDispatcherHost::IsOnIOThread() const { - MessageLoop* io_loop = ChromeThread::GetMessageLoop(ChromeThread::IO); - return MessageLoop::current() == io_loop; -} - -bool DOMStorageDispatcherHost::IsOnWebKitThread() const { - return MessageLoop::current() == webkit_thread_->GetMessageLoop(); -} 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 a7b815f..a495d97 100644 --- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h +++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h @@ -6,7 +6,6 @@ #define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_ #include "base/ref_counted.h" -#include "base/thread.h" #include "chrome/common/ipc_message.h" class WebKitContext; @@ -15,7 +14,7 @@ class WebKitThread; // 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 (for now). +// THIS CLASS MUST NOT BE DESTROYED ON THE WEBKIT THREAD. class DOMStorageDispatcherHost : public base::RefCountedThreadSafe<DOMStorageDispatcherHost> { public: @@ -23,10 +22,6 @@ class DOMStorageDispatcherHost : DOMStorageDispatcherHost(IPC::Message::Sender* message_sender, WebKitContext*, WebKitThread*); - // Only call Shutdown from the IO thread. Shutdown warns us that we're going - // to go away soon and tells us not to send anything else to the IO thread. - void Shutdown(); - // Only call from IO thread. bool OnMessageReceived(const IPC::Message& message); @@ -38,18 +33,13 @@ class DOMStorageDispatcherHost : friend class base::RefCountedThreadSafe<DOMStorageDispatcherHost>; ~DOMStorageDispatcherHost(); - // Obviously can be called from any thread. - bool IsOnIOThread() const; - bool IsOnWebKitThread() const; - - // Are immutable and are always valid throughout the lifetime of the object. + // Data shared between renderer processes with the same profile. scoped_refptr<WebKitContext> webkit_context_; - scoped_refptr<WebKitThread> webkit_thread_; - // We keep the message_sender_ pointer for sending messages. All access - // to the message_sender_ (and the IO thread in general) should be done under - // this lock and only if message_sender_ is non-NULL. - Lock message_sender_lock_; + // ResourceDispatcherHost takes care of destruction. Immutable. + WebKitThread* webkit_thread_; + + // Only set on the IO thread. IPC::Message::Sender* message_sender_; 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 55772c6..19cf65b 100644 --- a/chrome/browser/in_process_webkit/webkit_thread.cc +++ b/chrome/browser/in_process_webkit/webkit_thread.cc @@ -4,21 +4,23 @@ #include "chrome/browser/in_process_webkit/webkit_thread.h" +#include "base/command_line.h" #include "chrome/browser/in_process_webkit/browser_webkitclient_impl.h" +#include "chrome/common/chrome_switches.h" #include "webkit/api/public/WebKit.h" -base::LazyInstance<Lock> WebKitThread::global_webkit_lock_( - base::LINKER_INITIALIZED); -int WebKitThread::global_webkit_ref_count_ = 0; -WebKitThread::InternalWebKitThread* WebKitThread::global_webkit_thread_ = NULL; +// This happens on the UI thread before the IO thread has been shut down. +WebKitThread::WebKitThread() { + // The thread is started lazily by InitializeThread() on the IO thread. +} -WebKitThread::WebKitThread() - : cached_webkit_thread_(NULL) { - // The thread is started lazily by InitializeThread(). +// This happens on the UI thread after the IO thread has been shut down. +WebKitThread::~WebKitThread() { + DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); } WebKitThread::InternalWebKitThread::InternalWebKitThread() - : base::Thread("WebKit"), + : ChromeThread(ChromeThread::WEBKIT), webkit_client_(NULL) { } @@ -28,42 +30,24 @@ void WebKitThread::InternalWebKitThread::Init() { 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 often called on the IO thread). + // executing (since InitializeThread() is called on the IO thread). } 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). DCHECK(webkit_client_); WebKit::shutdown(); delete webkit_client_; - webkit_client_ = NULL; } -WebKitThread::~WebKitThread() { - AutoLock lock(global_webkit_lock_.Get()); - if (cached_webkit_thread_) { - DCHECK(global_webkit_ref_count_ > 0); - if (--global_webkit_ref_count_ == 0) { - // TODO(jorlow): Make this safe. - DCHECK(MessageLoop::current() != global_webkit_thread_->message_loop()); - global_webkit_thread_->Stop(); - delete global_webkit_thread_; - global_webkit_thread_ = NULL; - } - } -} +MessageLoop* WebKitThread::InitializeThread() { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) + return NULL; -void WebKitThread::InitializeThread() { - AutoLock lock(global_webkit_lock_.Get()); - if (!cached_webkit_thread_) { - if (!global_webkit_thread_) { - global_webkit_thread_ = new InternalWebKitThread; - DCHECK(global_webkit_thread_); - bool started = global_webkit_thread_->Start(); - DCHECK(started); - } - ++global_webkit_ref_count_; - // The cached version can be accessed outside of global_webkit_lock_. - cached_webkit_thread_ = global_webkit_thread_; - } - DCHECK(cached_webkit_thread_->IsRunning()); + DCHECK(!webkit_thread_.get()); + webkit_thread_.reset(new InternalWebKitThread); + bool started = webkit_thread_->Start(); + DCHECK(started); + return webkit_thread_->message_loop(); } diff --git a/chrome/browser/in_process_webkit/webkit_thread.h b/chrome/browser/in_process_webkit/webkit_thread.h index 518fa66..49ad7ac 100644 --- a/chrome/browser/in_process_webkit/webkit_thread.h +++ b/chrome/browser/in_process_webkit/webkit_thread.h @@ -10,36 +10,34 @@ #include "base/logging.h" #include "base/ref_counted.h" #include "base/thread.h" +#include "chrome/browser/chrome_thread.h" class BrowserWebKitClientImpl; // This is an object that represents WebKit's "main" thread within the browser -// process. You can create as many instances of this class as you'd like; -// they'll all point to the same thread and you're guaranteed they'll -// initialize in a thread-safe way, though WebKitThread instances should -// probably be shared when it's easy to do so. The first time you call -// GetMessageLoop() or EnsureWebKitInitialized() the thread will be created -// and WebKit initialized. When the last instance of WebKitThread is -// destroyed, WebKit is shut down and the thread is stopped. -// THIS CLASS MUST NOT BE DEREFED TO 0 ON THE WEBKIT THREAD (for now). -class WebKitThread : public base::RefCountedThreadSafe<WebKitThread> { +// process. It should be instantiated and destroyed on the UI thread +// before/after the IO thread is created/destroyed. All other usage should be +// on the IO thread. If the browser is being run in --single-process mode, a +// thread will never be spun up, and GetMessageLoop() will always return NULL. +class WebKitThread { public: + // Called from the UI thread. WebKitThread(); + ~WebKitThread(); + // Returns the message loop for the WebKit thread unless we're in + // --single-processuntil mode, in which case it'll return NULL. Only call + // from the IO thread. Only do fast-path work here. MessageLoop* GetMessageLoop() { - if (!cached_webkit_thread_) - InitializeThread(); - return cached_webkit_thread_->message_loop(); - } - - void EnsureWebKitInitialized() { - if (!cached_webkit_thread_) - InitializeThread(); + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!webkit_thread_.get()) + return InitializeThread(); + return webkit_thread_->message_loop(); } private: // Must be private so that we can carefully control its lifetime. - class InternalWebKitThread : public base::Thread { + class InternalWebKitThread : public ChromeThread { public: InternalWebKitThread(); virtual ~InternalWebKitThread() { } @@ -52,22 +50,13 @@ class WebKitThread : public base::RefCountedThreadSafe<WebKitThread> { BrowserWebKitClientImpl* webkit_client_; }; - friend class base::RefCountedThreadSafe<WebKitThread>; - ~WebKitThread(); - - void InitializeThread(); - - // If this is set, then this object has incremented the global WebKit ref - // count and will shutdown the thread if it sees the ref count go to 0. - // It's assumed that once this is non-NULL, the pointer will be valid until - // destruction. - InternalWebKitThread* cached_webkit_thread_; + // Returns the WebKit thread's message loop or NULL if we're in + // --single-process mode. Do slow-path initialization work here. + MessageLoop* InitializeThread(); - // If there are multiple WebKitThread object (should only be possible in - // unittests at the moment), make sure they all share one real thread. - static base::LazyInstance<Lock> global_webkit_lock_; - static int global_webkit_ref_count_; - static InternalWebKitThread* global_webkit_thread_; + // Pointer to the actual WebKitThread. NULL if not yet started. Only modify + // from the IO thread while the WebKit thread is not running. + scoped_ptr<InternalWebKitThread> webkit_thread_; DISALLOW_COPY_AND_ASSIGN(WebKitThread); }; diff --git a/chrome/browser/in_process_webkit/webkit_thread_unittest.cc b/chrome/browser/in_process_webkit/webkit_thread_unittest.cc index f66a26c..1f19963 100644 --- a/chrome/browser/in_process_webkit/webkit_thread_unittest.cc +++ b/chrome/browser/in_process_webkit/webkit_thread_unittest.cc @@ -5,13 +5,4 @@ #include "chrome/browser/in_process_webkit/webkit_thread.h" #include "testing/gtest/include/gtest/gtest.h" -// This is important because if there are 2 different message loops, we must -// have 2 different WebKit threads which would be very bad. -TEST(WebKitThreadTest, TwoThreadsShareMessageLoopTest) { - scoped_refptr<WebKitThread> thread_a = new WebKitThread; - scoped_refptr<WebKitThread> thread_b = new WebKitThread; - MessageLoop* loop_a = thread_a->GetMessageLoop(); - MessageLoop* loop_b = thread_b->GetMessageLoop(); - ASSERT_FALSE(loop_a == NULL); - ASSERT_EQ(loop_a, loop_b); -} +// TODO(jorlow): Write some tests. http://crbug.com/16155 diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h index 333791e..9a19249 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.h +++ b/chrome/browser/renderer_host/resource_dispatcher_host.h @@ -292,7 +292,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate { } WebKitThread* webkit_thread() const { - return webkit_thread_; + return webkit_thread_.get(); } MessageLoop* ui_loop() const { return ui_loop_; } @@ -529,7 +529,8 @@ class ResourceDispatcherHost : public URLRequest::Delegate { scoped_refptr<SafeBrowsingService> safe_browsing_; - scoped_refptr<WebKitThread> webkit_thread_; + // We own the WebKit thread and see to its destruction. + scoped_ptr<WebKitThread> webkit_thread_; // Request ID for browser initiated requests. request_ids generated by // child processes are counted up from 0, while browser created requests diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index f4168da..f9b535e 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -175,10 +175,7 @@ ResourceMessageFilter::ResourceMessageFilter( ResourceMessageFilter::~ResourceMessageFilter() { // This function should be called on the IO thread. - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); - - dom_storage_dispatcher_host_->Shutdown(); + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); // Let interested observers know we are being deleted. NotificationService::current()->Notify( @@ -452,8 +449,7 @@ void ResourceMessageFilter::OnGetDataDir(std::wstring* data_dir) { void ResourceMessageFilter::OnPluginMessage(const FilePath& plugin_path, const std::vector<uint8>& data) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); ChromePluginLib *chrome_plugin = ChromePluginLib::Find(plugin_path); if (chrome_plugin) { @@ -466,8 +462,7 @@ void ResourceMessageFilter::OnPluginMessage(const FilePath& plugin_path, void ResourceMessageFilter::OnPluginSyncMessage(const FilePath& plugin_path, const std::vector<uint8>& data, std::vector<uint8> *retval) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); ChromePluginLib *chrome_plugin = ChromePluginLib::Find(plugin_path); if (chrome_plugin) { |