diff options
author | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-28 12:44:49 +0000 |
---|---|---|
committer | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-28 12:44:49 +0000 |
commit | c38831a108f9f905ce9e68503ee67274939cc950 (patch) | |
tree | 7c93c8afd386fdc11a0f03855cee62c2d3449d63 /content/browser/browser_thread_impl.cc | |
parent | 75c753a51b150912055d7a8305cf77134d24816a (diff) | |
download | chromium_src-c38831a108f9f905ce9e68503ee67274939cc950.zip chromium_src-c38831a108f9f905ce9e68503ee67274939cc950.tar.gz chromium_src-c38831a108f9f905ce9e68503ee67274939cc950.tar.bz2 |
Split BrowserThread into public API and private implementation, step 1.
Only content/ now has the ability to create BrowserThread objects,
with the exception that tests can create the
content::TestBrowserThread subclass, and (temporarily) code in chrome/
can create the DeprecatedBrowserThread subclass.
A follow-up change will make content/ take care of its own thread
creation, remove DeprecatedBrowserThread, and move all state and
non-trivial constructors from BrowserThread down to BrowserThreadImpl.
Also moved BrowserProcessSubThread into content/ namespace. As part
of follow-up cleanup, chrome/ will stop using this class.
BUG=98716
TEST=existing
Review URL: http://codereview.chromium.org/8392042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107718 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/browser_thread_impl.cc')
-rw-r--r-- | content/browser/browser_thread_impl.cc | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc new file mode 100644 index 0000000..39fa636 --- /dev/null +++ b/content/browser/browser_thread_impl.cc @@ -0,0 +1,383 @@ +// Copyright (c) 2011 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/browser_thread_impl.h" + +#include "base/bind.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/threading/thread_restrictions.h" + +namespace { + +// Friendly names for the well-known threads. +static const char* browser_thread_names[BrowserThread::ID_COUNT] = { + "", // UI (name assembled in browser_main.cc). + "Chrome_DBThread", // DB + "Chrome_WebKitThread", // WEBKIT + "Chrome_FileThread", // FILE + "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER + "Chrome_CacheThread", // CACHE + "Chrome_IOThread", // IO +#if defined(OS_CHROMEOS) + "Chrome_WebSocketproxyThread", // WEB_SOCKET_PROXY +#endif +}; + +} // namespace + +namespace content { + +base::Lock BrowserThreadImpl::lock_; + +BrowserThread* BrowserThreadImpl::browser_threads_[ID_COUNT]; + +BrowserThreadImpl::BrowserThreadImpl(BrowserThread::ID identifier) + : BrowserThread(identifier) { +} + +BrowserThreadImpl::BrowserThreadImpl(BrowserThread::ID identifier, + MessageLoop* message_loop) + : BrowserThread(identifier, message_loop) { +} + +BrowserThreadImpl::~BrowserThreadImpl() { +} + +// static +bool BrowserThreadImpl::PostTaskHelper( + BrowserThread::ID identifier, + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms, + bool nestable) { + DCHECK(identifier >= 0 && identifier < ID_COUNT); + // Optimization: to avoid unnecessary locks, we listed the ID enumeration in + // order of lifetime. So no need to lock if we know that the other thread + // outlives this one. + // Note: since the array is so small, ok to loop instead of creating a map, + // which would require a lock because std::map isn't thread safe, defeating + // the whole purpose of this optimization. + BrowserThread::ID current_thread; + bool guaranteed_to_outlive_target_thread = + GetCurrentThreadIdentifier(¤t_thread) && + current_thread >= identifier; + + if (!guaranteed_to_outlive_target_thread) + BrowserThreadImpl::lock_.Acquire(); + + MessageLoop* message_loop = BrowserThreadImpl::browser_threads_[identifier] ? + BrowserThreadImpl::browser_threads_[identifier]->message_loop() : NULL; + if (message_loop) { + if (nestable) { + message_loop->PostDelayedTask(from_here, task, delay_ms); + } else { + message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); + } + } + + if (!guaranteed_to_outlive_target_thread) + BrowserThreadImpl::lock_.Release(); + + if (!message_loop) + delete task; + + return !!message_loop; +} + +// static +bool BrowserThreadImpl::PostTaskHelper( + BrowserThread::ID identifier, + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms, + bool nestable) { + DCHECK(identifier >= 0 && identifier < ID_COUNT); + // Optimization: to avoid unnecessary locks, we listed the ID enumeration in + // order of lifetime. So no need to lock if we know that the other thread + // outlives this one. + // Note: since the array is so small, ok to loop instead of creating a map, + // which would require a lock because std::map isn't thread safe, defeating + // the whole purpose of this optimization. + BrowserThread::ID current_thread; + bool guaranteed_to_outlive_target_thread = + GetCurrentThreadIdentifier(¤t_thread) && + current_thread >= identifier; + + if (!guaranteed_to_outlive_target_thread) + lock_.Acquire(); + + MessageLoop* message_loop = browser_threads_[identifier] ? + browser_threads_[identifier]->message_loop() : NULL; + if (message_loop) { + if (nestable) { + message_loop->PostDelayedTask(from_here, task, delay_ms); + } else { + message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); + } + } + + if (!guaranteed_to_outlive_target_thread) + lock_.Release(); + + return !!message_loop; +} + +} // namespace content + +using content::BrowserThreadImpl; + +// TODO(joi): Remove +DeprecatedBrowserThread::DeprecatedBrowserThread(BrowserThread::ID identifier) + : BrowserThread(identifier) { +} +DeprecatedBrowserThread::DeprecatedBrowserThread(BrowserThread::ID identifier, + MessageLoop* message_loop) + : BrowserThread(identifier, message_loop) { +} +DeprecatedBrowserThread::~DeprecatedBrowserThread() { +} + +// An implementation of MessageLoopProxy to be used in conjunction +// with BrowserThread. +class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy { + public: + explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier) + : id_(identifier) { + } + + // MessageLoopProxy implementation. + virtual bool PostTask(const tracked_objects::Location& from_here, + Task* task) { + return BrowserThread::PostTask(id_, from_here, task); + } + + virtual bool PostDelayedTask(const tracked_objects::Location& from_here, + Task* task, int64 delay_ms) { + return BrowserThread::PostDelayedTask(id_, from_here, task, delay_ms); + } + + virtual bool PostNonNestableTask(const tracked_objects::Location& from_here, + Task* task) { + return BrowserThread::PostNonNestableTask(id_, from_here, task); + } + + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms) { + return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task, + delay_ms); + } + + virtual bool PostTask(const tracked_objects::Location& from_here, + const base::Closure& task) { + return BrowserThread::PostTask(id_, from_here, task); + } + + virtual bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, int64 delay_ms) { + return BrowserThread::PostDelayedTask(id_, from_here, task, delay_ms); + } + + virtual bool PostNonNestableTask(const tracked_objects::Location& from_here, + const base::Closure& task) { + return BrowserThread::PostNonNestableTask(id_, from_here, task); + } + + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms) { + return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task, + delay_ms); + } + + virtual bool BelongsToCurrentThread() { + return BrowserThread::CurrentlyOn(id_); + } + + private: + BrowserThread::ID id_; + DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy); +}; + +BrowserThread::BrowserThread(ID identifier) + : Thread(browser_thread_names[identifier]), + identifier_(identifier) { + Initialize(); +} + +BrowserThread::BrowserThread(ID identifier, + MessageLoop* message_loop) + : Thread(message_loop->thread_name().c_str()), + identifier_(identifier) { + set_message_loop(message_loop); + Initialize(); +} + +void BrowserThread::Initialize() { + base::AutoLock lock(BrowserThreadImpl::lock_); + DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); + DCHECK(BrowserThreadImpl::browser_threads_[identifier_] == NULL); + BrowserThreadImpl::browser_threads_[identifier_] = this; +} + +BrowserThread::~BrowserThread() { + // Stop the thread here, instead of the parent's class destructor. This is so + // that if there are pending tasks that run, code that checks that it's on the + // correct BrowserThread succeeds. + Stop(); + + base::AutoLock lock(BrowserThreadImpl::lock_); + BrowserThreadImpl::browser_threads_[identifier_] = NULL; +#ifndef NDEBUG + // Double check that the threads are ordered correctly in the enumeration. + for (int i = identifier_ + 1; i < ID_COUNT; ++i) { + DCHECK(!BrowserThreadImpl::browser_threads_[i]) << + "Threads must be listed in the reverse order that they die"; + } +#endif +} + +// static +bool BrowserThread::IsWellKnownThread(ID identifier) { + base::AutoLock lock(BrowserThreadImpl::lock_); + return (identifier >= 0 && identifier < ID_COUNT && + BrowserThreadImpl::browser_threads_[identifier]); +} + +// static +bool BrowserThread::CurrentlyOn(ID identifier) { + // We shouldn't use MessageLoop::current() since it uses LazyInstance which + // may be deleted by ~AtExitManager when a WorkerPool thread calls this + // function. + // http://crbug.com/63678 + base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; + base::AutoLock lock(BrowserThreadImpl::lock_); + DCHECK(identifier >= 0 && identifier < ID_COUNT); + return BrowserThreadImpl::browser_threads_[identifier] && + BrowserThreadImpl::browser_threads_[identifier]->message_loop() == + MessageLoop::current(); +} + +// static +bool BrowserThread::IsMessageLoopValid(ID identifier) { + base::AutoLock lock(BrowserThreadImpl::lock_); + DCHECK(identifier >= 0 && identifier < ID_COUNT); + return BrowserThreadImpl::browser_threads_[identifier] && + BrowserThreadImpl::browser_threads_[identifier]->message_loop(); +} + +// static +bool BrowserThread::PostTask(ID identifier, + const tracked_objects::Location& from_here, + const base::Closure& task) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, 0, true); +} + +// static +bool BrowserThread::PostDelayedTask(ID identifier, + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, delay_ms, true); +} + +// static +bool BrowserThread::PostNonNestableTask( + ID identifier, + const tracked_objects::Location& from_here, + const base::Closure& task) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, 0, false); +} + +// static +bool BrowserThread::PostNonNestableDelayedTask( + ID identifier, + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, delay_ms, false); +} + +// static +bool BrowserThread::PostTask(ID identifier, + const tracked_objects::Location& from_here, + Task* task) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, 0, true); +} + +// static +bool BrowserThread::PostDelayedTask(ID identifier, + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, delay_ms, true); +} + +// static +bool BrowserThread::PostNonNestableTask( + ID identifier, + const tracked_objects::Location& from_here, + Task* task) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, 0, false); +} + +// static +bool BrowserThread::PostNonNestableDelayedTask( + ID identifier, + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms) { + return BrowserThreadImpl::PostTaskHelper( + identifier, from_here, task, delay_ms, false); +} + +// static +bool BrowserThread::PostTaskAndReply( + ID identifier, + const tracked_objects::Location& from_here, + const base::Closure& task, + const base::Closure& reply) { + return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, + task, + reply); +} + +// static +bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { + // We shouldn't use MessageLoop::current() since it uses LazyInstance which + // may be deleted by ~AtExitManager when a WorkerPool thread calls this + // function. + // http://crbug.com/63678 + base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; + MessageLoop* cur_message_loop = MessageLoop::current(); + for (int i = 0; i < ID_COUNT; ++i) { + if (BrowserThreadImpl::browser_threads_[i] && + BrowserThreadImpl::browser_threads_[i]->message_loop() == + cur_message_loop) { + *identifier = BrowserThreadImpl::browser_threads_[i]->identifier_; + return true; + } + } + + return false; +} + +// static +scoped_refptr<base::MessageLoopProxy> +BrowserThread::GetMessageLoopProxyForThread( + ID identifier) { + scoped_refptr<base::MessageLoopProxy> proxy( + new BrowserThreadMessageLoopProxy(identifier)); + return proxy; +} |