diff options
Diffstat (limited to 'content/browser')
-rw-r--r-- | content/browser/browser_main_loop.cc | 8 | ||||
-rw-r--r-- | content/browser/browser_thread_impl.cc | 146 | ||||
-rw-r--r-- | content/browser/browser_thread_impl.h | 2 |
3 files changed, 110 insertions, 46 deletions
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 4c307b1..8203333 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -513,6 +513,14 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() { } } + // Close the blocking I/O pool after the other threads. Other threads such + // as the I/O thread may need to schedule work like closing files or flushing + // data during shutdown, so the blocking pool needs to be available. There + // may also be slow operations pending that will blcok shutdown, so closing + // it here (which will block until required operations are complete) gives + // more head start for those operations to finish. + BrowserThreadImpl::ShutdownThreadPool(); + if (parts_.get()) parts_->PostDestroyThreads(); } diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc index f7cca04..bd6aff9 100644 --- a/content/browser/browser_thread_impl.cc +++ b/content/browser/browser_thread_impl.cc @@ -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 { @@ -27,24 +28,37 @@ static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = { "Chrome_IOThread", // IO }; -// 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; - -// 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]; - -// 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]; +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 lock protects |threads|. Do not read or modify that array + // without holding this lock. Do not block while holding this lock. + base::Lock lock; + + // 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 @@ -62,10 +76,18 @@ BrowserThreadImpl::BrowserThreadImpl(ID identifier, 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); @@ -74,9 +96,11 @@ void BrowserThreadImpl::Init() { } 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); @@ -86,10 +110,12 @@ void BrowserThreadImpl::CleanUp() { } 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() { @@ -98,12 +124,13 @@ BrowserThreadImpl::~BrowserThreadImpl() { // 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 @@ -128,11 +155,12 @@ bool BrowserThreadImpl::PostTaskHelper( 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); @@ -142,7 +170,7 @@ bool BrowserThreadImpl::PostTaskHelper( } if (!guaranteed_to_outlive_target_thread) - g_lock.Get().Release(); + globals.lock.Release(); return !!message_loop; } @@ -189,10 +217,32 @@ class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy { }; // 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 @@ -202,19 +252,21 @@ bool BrowserThread::CurrentlyOn(ID identifier) { // 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 @@ -272,10 +324,11 @@ bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { // 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; } } @@ -285,8 +338,7 @@ bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { // static scoped_refptr<base::MessageLoopProxy> -BrowserThread::GetMessageLoopProxyForThread( - ID identifier) { +BrowserThread::GetMessageLoopProxyForThread(ID identifier) { scoped_refptr<base::MessageLoopProxy> proxy( new BrowserThreadMessageLoopProxy(identifier)); return proxy; @@ -294,8 +346,9 @@ BrowserThread::GetMessageLoopProxyForThread( // 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; @@ -305,8 +358,9 @@ MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 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)); diff --git a/content/browser/browser_thread_impl.h b/content/browser/browser_thread_impl.h index feea986..4488f85 100644 --- a/content/browser/browser_thread_impl.h +++ b/content/browser/browser_thread_impl.h @@ -25,6 +25,8 @@ class CONTENT_EXPORT BrowserThreadImpl BrowserThreadImpl(BrowserThread::ID identifier, MessageLoop* message_loop); virtual ~BrowserThreadImpl(); + static void ShutdownThreadPool(); + protected: virtual void Init() OVERRIDE; virtual void CleanUp() OVERRIDE; |