summaryrefslogtreecommitdiffstats
path: root/content/browser/browser_thread_impl.cc
diff options
context:
space:
mode:
authorjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-28 12:44:49 +0000
committerjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-28 12:44:49 +0000
commitc38831a108f9f905ce9e68503ee67274939cc950 (patch)
tree7c93c8afd386fdc11a0f03855cee62c2d3449d63 /content/browser/browser_thread_impl.cc
parent75c753a51b150912055d7a8305cf77134d24816a (diff)
downloadchromium_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.cc383
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(&current_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(&current_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;
+}