| Index: content/browser/browser_thread_impl.cc
|
| ===================================================================
|
| --- content/browser/browser_thread_impl.cc (revision 116282)
|
| +++ content/browser/browser_thread_impl.cc (working copy)
|
| @@ -9,6 +9,7 @@
|
| #include "base/lazy_instance.h"
|
| #include "base/message_loop.h"
|
| #include "base/message_loop_proxy.h"
|
| +#include "base/threading/sequenced_worker_pool.h"
|
| #include "base/threading/thread_restrictions.h"
|
|
|
| namespace content {
|
| @@ -30,25 +31,38 @@
|
| #endif
|
| };
|
|
|
| -// This lock protects |g_browser_threads|. Do not read or modify that
|
| -// array without holding this lock. Do not block while holding this
|
| -// lock.
|
| -base::LazyInstance<base::Lock,
|
| - base::LeakyLazyInstanceTraits<base::Lock> >
|
| - g_lock = LAZY_INSTANCE_INITIALIZER;
|
| +struct BrowserThreadGlobals {
|
| + BrowserThreadGlobals()
|
| + : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
|
| + memset(threads, 0,
|
| + BrowserThread::ID_COUNT * sizeof(BrowserThreadImpl*));
|
| + memset(thread_delegates, 0,
|
| + BrowserThread::ID_COUNT * sizeof(BrowserThreadDelegate*));
|
| + }
|
|
|
| -// This array is protected by |g_lock|. The threads are not owned by this
|
| -// array. Typically, the threads are owned on the UI thread by
|
| -// content::BrowserMainLoop. BrowserThreadImpl objects remove
|
| -// themselves from this array upon destruction.
|
| -static BrowserThreadImpl* g_browser_threads[BrowserThread::ID_COUNT];
|
| + // This lock protects |threads|. Do not read or modify that array
|
| + // without holding this lock. Do not block while holding this lock.
|
| + base::Lock lock;
|
|
|
| -// Only atomic operations are used on this array. The delegates are
|
| -// not owned by this array, rather by whoever calls
|
| -// BrowserThread::SetDelegate.
|
| -static BrowserThreadDelegate* g_browser_thread_delegates[
|
| - BrowserThread::ID_COUNT];
|
| + // This array is protected by |lock|. The threads are not owned by this
|
| + // array. Typically, the threads are owned on the UI thread by
|
| + // content::BrowserMainLoop. BrowserThreadImpl objects remove themselves from
|
| + // this array upon destruction.
|
| + BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
|
|
|
| + // Only atomic operations are used on this array. The delegates are not owned
|
| + // by this array, rather by whoever calls BrowserThread::SetDelegate.
|
| + BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
|
| +
|
| + // This pointer is deliberately leaked on shutdown. This allows the pool to
|
| + // implement "continue on shutdown" semantics.
|
| + base::SequencedWorkerPool* blocking_pool;
|
| +};
|
| +
|
| +base::LazyInstance<BrowserThreadGlobals,
|
| + base::LeakyLazyInstanceTraits<BrowserThreadGlobals> >
|
| + g_globals = LAZY_INSTANCE_INITIALIZER;
|
| +
|
| } // namespace
|
|
|
| BrowserThreadImpl::BrowserThreadImpl(ID identifier)
|
| @@ -65,10 +79,18 @@
|
| Initialize();
|
| }
|
|
|
| +// static
|
| +void BrowserThreadImpl::ShutdownThreadPool() {
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| + globals.blocking_pool->Shutdown();
|
| +}
|
| +
|
| void BrowserThreadImpl::Init() {
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| +
|
| using base::subtle::AtomicWord;
|
| AtomicWord* storage =
|
| - reinterpret_cast<AtomicWord*>(&g_browser_thread_delegates[identifier_]);
|
| + reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
|
| AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
|
| BrowserThreadDelegate* delegate =
|
| reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
|
| @@ -77,9 +99,11 @@
|
| }
|
|
|
| void BrowserThreadImpl::CleanUp() {
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| +
|
| using base::subtle::AtomicWord;
|
| AtomicWord* storage =
|
| - reinterpret_cast<AtomicWord*>(&g_browser_thread_delegates[identifier_]);
|
| + reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
|
| AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
|
| BrowserThreadDelegate* delegate =
|
| reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
|
| @@ -89,10 +113,12 @@
|
| }
|
|
|
| void BrowserThreadImpl::Initialize() {
|
| - base::AutoLock lock(g_lock.Get());
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| +
|
| + base::AutoLock lock(globals.lock);
|
| DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
|
| - DCHECK(g_browser_threads[identifier_] == NULL);
|
| - g_browser_threads[identifier_] = this;
|
| + DCHECK(globals.threads[identifier_] == NULL);
|
| + globals.threads[identifier_] = this;
|
| }
|
|
|
| BrowserThreadImpl::~BrowserThreadImpl() {
|
| @@ -101,12 +127,13 @@
|
| // the right BrowserThread.
|
| Stop();
|
|
|
| - base::AutoLock lock(g_lock.Get());
|
| - g_browser_threads[identifier_] = NULL;
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| + base::AutoLock lock(globals.lock);
|
| + globals.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(!g_browser_threads[i]) <<
|
| + DCHECK(!globals.threads[i]) <<
|
| "Threads must be listed in the reverse order that they die";
|
| }
|
| #endif
|
| @@ -131,11 +158,12 @@
|
| GetCurrentThreadIdentifier(¤t_thread) &&
|
| current_thread <= identifier;
|
|
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| if (!guaranteed_to_outlive_target_thread)
|
| - g_lock.Get().Acquire();
|
| + globals.lock.Acquire();
|
|
|
| - MessageLoop* message_loop = g_browser_threads[identifier] ?
|
| - g_browser_threads[identifier]->message_loop() : NULL;
|
| + MessageLoop* message_loop = globals.threads[identifier] ?
|
| + globals.threads[identifier]->message_loop() : NULL;
|
| if (message_loop) {
|
| if (nestable) {
|
| message_loop->PostDelayedTask(from_here, task, delay_ms);
|
| @@ -145,7 +173,7 @@
|
| }
|
|
|
| if (!guaranteed_to_outlive_target_thread)
|
| - g_lock.Get().Release();
|
| + globals.lock.Release();
|
|
|
| if (!message_loop)
|
| delete task;
|
| @@ -172,11 +200,12 @@
|
| GetCurrentThreadIdentifier(¤t_thread) &&
|
| current_thread <= identifier;
|
|
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| if (!guaranteed_to_outlive_target_thread)
|
| - g_lock.Get().Acquire();
|
| + globals.lock.Acquire();
|
|
|
| - MessageLoop* message_loop = g_browser_threads[identifier] ?
|
| - g_browser_threads[identifier]->message_loop() : NULL;
|
| + MessageLoop* message_loop = globals.threads[identifier] ?
|
| + globals.threads[identifier]->message_loop() : NULL;
|
| if (message_loop) {
|
| if (nestable) {
|
| message_loop->PostDelayedTask(from_here, task, delay_ms);
|
| @@ -186,7 +215,7 @@
|
| }
|
|
|
| if (!guaranteed_to_outlive_target_thread)
|
| - g_lock.Get().Release();
|
| + globals.lock.Release();
|
|
|
| return !!message_loop;
|
| }
|
| @@ -256,10 +285,32 @@
|
| };
|
|
|
| // static
|
| +bool BrowserThread::PostBlockingPoolTask(
|
| + const tracked_objects::Location& from_here,
|
| + const base::Closure& task) {
|
| + return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
|
| +}
|
| +
|
| +// static
|
| +bool BrowserThread::PostBlockingPoolSequencedTask(
|
| + const std::string& sequence_token_name,
|
| + const tracked_objects::Location& from_here,
|
| + const base::Closure& task) {
|
| + return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
|
| + sequence_token_name, from_here, task);
|
| +}
|
| +
|
| +// static
|
| +base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
|
| + return g_globals.Get().blocking_pool;
|
| +}
|
| +
|
| +// static
|
| bool BrowserThread::IsWellKnownThread(ID identifier) {
|
| - base::AutoLock lock(g_lock.Get());
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| + base::AutoLock lock(globals.lock);
|
| return (identifier >= 0 && identifier < ID_COUNT &&
|
| - g_browser_threads[identifier]);
|
| + globals.threads[identifier]);
|
| }
|
|
|
| // static
|
| @@ -269,19 +320,21 @@
|
| // function.
|
| // http://crbug.com/63678
|
| base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
|
| - base::AutoLock lock(g_lock.Get());
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| + base::AutoLock lock(globals.lock);
|
| DCHECK(identifier >= 0 && identifier < ID_COUNT);
|
| - return g_browser_threads[identifier] &&
|
| - g_browser_threads[identifier]->message_loop() ==
|
| + return globals.threads[identifier] &&
|
| + globals.threads[identifier]->message_loop() ==
|
| MessageLoop::current();
|
| }
|
|
|
| // static
|
| bool BrowserThread::IsMessageLoopValid(ID identifier) {
|
| - base::AutoLock lock(g_lock.Get());
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| + base::AutoLock lock(globals.lock);
|
| DCHECK(identifier >= 0 && identifier < ID_COUNT);
|
| - return g_browser_threads[identifier] &&
|
| - g_browser_threads[identifier]->message_loop();
|
| + return globals.threads[identifier] &&
|
| + globals.threads[identifier]->message_loop();
|
| }
|
|
|
| // static
|
| @@ -375,10 +428,11 @@
|
| // http://crbug.com/63678
|
| base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
|
| MessageLoop* cur_message_loop = MessageLoop::current();
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| for (int i = 0; i < ID_COUNT; ++i) {
|
| - if (g_browser_threads[i] &&
|
| - g_browser_threads[i]->message_loop() == cur_message_loop) {
|
| - *identifier = g_browser_threads[i]->identifier_;
|
| + if (globals.threads[i] &&
|
| + globals.threads[i]->message_loop() == cur_message_loop) {
|
| + *identifier = globals.threads[i]->identifier_;
|
| return true;
|
| }
|
| }
|
| @@ -388,8 +442,7 @@
|
|
|
| // static
|
| scoped_refptr<base::MessageLoopProxy>
|
| -BrowserThread::GetMessageLoopProxyForThread(
|
| - ID identifier) {
|
| +BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
|
| scoped_refptr<base::MessageLoopProxy> proxy(
|
| new BrowserThreadMessageLoopProxy(identifier));
|
| return proxy;
|
| @@ -397,8 +450,9 @@
|
|
|
| // static
|
| MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
|
| - base::AutoLock lock(g_lock.Get());
|
| - base::Thread* thread = g_browser_threads[identifier];
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| + base::AutoLock lock(globals.lock);
|
| + base::Thread* thread = globals.threads[identifier];
|
| DCHECK(thread);
|
| MessageLoop* loop = thread->message_loop();
|
| return loop;
|
| @@ -408,8 +462,9 @@
|
| void BrowserThread::SetDelegate(ID identifier,
|
| BrowserThreadDelegate* delegate) {
|
| using base::subtle::AtomicWord;
|
| + BrowserThreadGlobals& globals = g_globals.Get();
|
| AtomicWord* storage = reinterpret_cast<AtomicWord*>(
|
| - &g_browser_thread_delegates[identifier]);
|
| + &globals.thread_delegates[identifier]);
|
| AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
|
| storage, reinterpret_cast<AtomicWord>(delegate));
|
|
|
|
|