diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-19 04:11:57 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-19 04:11:57 +0000 |
commit | 3189013eebc55ea5493186b29f2cee2bc7c0dafc (patch) | |
tree | f9c867f92c5fd9325a7d7e6ea9fed638103c4f4b | |
parent | 1946e0c4351fbdfd5b012d3c2aeac2c9218ad027 (diff) | |
download | chromium_src-3189013eebc55ea5493186b29f2cee2bc7c0dafc.zip chromium_src-3189013eebc55ea5493186b29f2cee2bc7c0dafc.tar.gz chromium_src-3189013eebc55ea5493186b29f2cee2bc7c0dafc.tar.bz2 |
Hook up the SequencedWorkerPool to the browser thread.
[re-land of 116816 http://codereview.chromium.org/9065009]
This does some refactoring of the static data in the browser thread so we only have one global object instead of a bunch fo separate arrays.
It also hooks up the visited link master's I/O to use this new system as a proof of concept.
Review URL: https://chromiumcodereview.appspot.com/9124033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118236 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/threading/sequenced_worker_pool.cc | 79 | ||||
-rw-r--r-- | base/threading/sequenced_worker_pool.h | 16 | ||||
-rw-r--r-- | chrome/browser/crash_upload_list.cc | 4 | ||||
-rw-r--r-- | chrome/browser/visitedlink/visitedlink_master.cc | 22 | ||||
-rw-r--r-- | chrome/browser/visitedlink/visitedlink_master.h | 8 | ||||
-rw-r--r-- | chrome/browser/visitedlink/visitedlink_unittest.cc | 3 | ||||
-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 | ||||
-rw-r--r-- | content/public/browser/browser_thread.h | 29 |
10 files changed, 241 insertions, 76 deletions
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc index 05ccff1..6d47068 100644 --- a/base/threading/sequenced_worker_pool.cc +++ b/base/threading/sequenced_worker_pool.cc @@ -57,20 +57,33 @@ class SequencedWorkerPool::Inner Inner(size_t max_threads, const std::string& thread_name_prefix); virtual ~Inner(); - // Backends for SequenceWorkerPool. SequenceToken GetSequenceToken(); + SequenceToken GetNamedSequenceToken(const std::string& name); - bool PostTask(int sequence_token_id, + + // This function accepts a name and an ID. If the name is null, the + // token ID is used. This allows us to implement the optional name lookup + // from a single function without having to enter the lock a separate time. + bool PostTask(const std::string* optional_token_name, + int sequence_token_id, SequencedWorkerPool::WorkerShutdown shutdown_behavior, const tracked_objects::Location& from_here, const base::Closure& task); + + void Flush(); + void Shutdown(); + void SetTestingObserver(SequencedWorkerPool::TestingObserver* observer); // Runs the worker loop on the background thread. void ThreadLoop(Worker* this_worker); private: + // Called from within the lock, this converts the given token name into a + // token ID, creating a new one if necessary. + int LockedGetNamedTokenID(const std::string& name); + // The calling code should clear the given delete_these_oustide_lock // vector the next time the lock is released. See the implementation for // a more detailed description. @@ -235,18 +248,11 @@ SequencedWorkerPool::SequenceToken SequencedWorkerPool::Inner::GetNamedSequenceToken( const std::string& name) { base::AutoLock lock(lock_); - std::map<std::string, int>::const_iterator found = - named_sequence_tokens_.find(name); - if (found != named_sequence_tokens_.end()) - return SequenceToken(found->second); // Got an existing one. - - // Create a new one for this name. - SequenceToken result = GetSequenceToken(); - named_sequence_tokens_.insert(std::make_pair(name, result.id_)); - return result; + return SequenceToken(LockedGetNamedTokenID(name)); } bool SequencedWorkerPool::Inner::PostTask( + const std::string* optional_token_name, int sequence_token_id, SequencedWorkerPool::WorkerShutdown shutdown_behavior, const tracked_objects::Location& from_here, @@ -263,6 +269,10 @@ bool SequencedWorkerPool::Inner::PostTask( if (terminating_) return false; + // Now that we have the lock, apply the named token rules. + if (optional_token_name) + sequenced.sequence_token_id = LockedGetNamedTokenID(*optional_token_name); + pending_tasks_.push_back(sequenced); pending_task_count_++; if (shutdown_behavior == BLOCK_SHUTDOWN) @@ -281,6 +291,15 @@ bool SequencedWorkerPool::Inner::PostTask( return true; } +void SequencedWorkerPool::Inner::Flush() { + { + base::AutoLock lock(lock_); + while (pending_task_count_ > 0 || waiting_thread_count_ < threads_.size()) + cond_var_.Wait(); + } + cond_var_.Signal(); +} + void SequencedWorkerPool::Inner::Shutdown() { if (shutdown_called_) return; @@ -366,6 +385,8 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { if (terminating_) break; waiting_thread_count_++; + cond_var_.Signal(); // For Flush() that may be waiting on the + // waiting thread count to go up. cond_var_.Wait(); waiting_thread_count_--; } @@ -377,6 +398,22 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { cond_var_.Signal(); } +int SequencedWorkerPool::Inner::LockedGetNamedTokenID( + const std::string& name) { + lock_.AssertAcquired(); + DCHECK(!name.empty()); + + std::map<std::string, int>::const_iterator found = + named_sequence_tokens_.find(name); + if (found != named_sequence_tokens_.end()) + return found->second; // Got an existing one. + + // Create a new one for this name. + SequenceToken result = GetSequenceToken(); + named_sequence_tokens_.insert(std::make_pair(name, result.id_)); + return result.id_; +} + bool SequencedWorkerPool::Inner::GetWork( SequencedTask* task, std::vector<base::Closure>* delete_these_outside_lock) { @@ -593,33 +630,45 @@ SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken( bool SequencedWorkerPool::PostWorkerTask( const tracked_objects::Location& from_here, const base::Closure& task) { - return inner_->PostTask(0, BLOCK_SHUTDOWN, from_here, task); + return inner_->PostTask(NULL, 0, BLOCK_SHUTDOWN, from_here, task); } bool SequencedWorkerPool::PostWorkerTaskWithShutdownBehavior( const tracked_objects::Location& from_here, const base::Closure& task, WorkerShutdown shutdown_behavior) { - return inner_->PostTask(0, shutdown_behavior, from_here, task); + return inner_->PostTask(NULL, 0, shutdown_behavior, from_here, task); } bool SequencedWorkerPool::PostSequencedWorkerTask( SequenceToken sequence_token, const tracked_objects::Location& from_here, const base::Closure& task) { - return inner_->PostTask(sequence_token.id_, BLOCK_SHUTDOWN, + return inner_->PostTask(NULL, sequence_token.id_, BLOCK_SHUTDOWN, from_here, task); } +bool SequencedWorkerPool::PostNamedSequencedWorkerTask( + const std::string& token_name, + const tracked_objects::Location& from_here, + const base::Closure& task) { + DCHECK(!token_name.empty()); + return inner_->PostTask(&token_name, 0, BLOCK_SHUTDOWN, from_here, task); +} + bool SequencedWorkerPool::PostSequencedWorkerTaskWithShutdownBehavior( SequenceToken sequence_token, const tracked_objects::Location& from_here, const base::Closure& task, WorkerShutdown shutdown_behavior) { - return inner_->PostTask(sequence_token.id_, shutdown_behavior, + return inner_->PostTask(NULL, sequence_token.id_, shutdown_behavior, from_here, task); } +void SequencedWorkerPool::FlushForTesting() { + inner_->Flush(); +} + void SequencedWorkerPool::Shutdown() { inner_->Shutdown(); } diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h index c6e0560..f5770a7 100644 --- a/base/threading/sequenced_worker_pool.h +++ b/base/threading/sequenced_worker_pool.h @@ -172,6 +172,12 @@ class BASE_EXPORT SequencedWorkerPool { const tracked_objects::Location& from_here, const base::Closure& task); + // Like PostSequencedWorkerTask above, but allows you to specify a named + // token, which saves an extra call to GetNamedSequenceToken. + bool PostNamedSequencedWorkerTask(const std::string& token_name, + const tracked_objects::Location& from_here, + const base::Closure& task); + // Same as PostSequencedWorkerTask but allows specification of the shutdown // behavior. bool PostSequencedWorkerTaskWithShutdownBehavior( @@ -180,6 +186,16 @@ class BASE_EXPORT SequencedWorkerPool { const base::Closure& task, WorkerShutdown shutdown_behavior); + // Blocks until all pending tasks are complete. This should only be called in + // unit tests when you want to validate something that should have happened. + // + // Note that calling this will not prevent other threads from posting work to + // the queue while the calling thread is waiting on Flush(). In this case, + // Flush will return only when there's no more work in the queue. Normally, + // this doesn't come up sine in a test, all the work is being posted from + // the main thread. + void FlushForTesting(); + // Implements the worker pool shutdown. This should be called during app // shutdown, and will discard/join with appropriate tasks before returning. // After this call, subsequent calls to post tasks will fail. diff --git a/chrome/browser/crash_upload_list.cc b/chrome/browser/crash_upload_list.cc index bc74d8e..30c04f8 100644 --- a/chrome/browser/crash_upload_list.cc +++ b/chrome/browser/crash_upload_list.cc @@ -39,8 +39,7 @@ CrashUploadList::CrashUploadList(Delegate* delegate) : delegate_(delegate) {} CrashUploadList::~CrashUploadList() {} void CrashUploadList::LoadCrashListAsynchronously() { - BrowserThread::PostTask( - BrowserThread::FILE, + BrowserThread::PostBlockingPoolTask( FROM_HERE, base::Bind(&CrashUploadList::LoadCrashListAndInformDelegateOfCompletion, this)); @@ -60,7 +59,6 @@ void CrashUploadList::LoadCrashListAndInformDelegateOfCompletion() { } void CrashUploadList::LoadCrashList() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); FilePath crash_dir_path; PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path); FilePath upload_log_path = crash_dir_path.AppendASCII("uploads.log"); diff --git a/chrome/browser/visitedlink/visitedlink_master.cc b/chrome/browser/visitedlink/visitedlink_master.cc index f3fbc85..38c87ca 100644 --- a/chrome/browser/visitedlink/visitedlink_master.cc +++ b/chrome/browser/visitedlink/visitedlink_master.cc @@ -191,6 +191,7 @@ void VisitedLinkMaster::InitMembers(Listener* listener, Profile* profile) { history_service_override_ = NULL; suppress_rebuild_ = false; profile_ = profile; + sequence_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken(); #ifndef NDEBUG posted_asynchronous_operation_ = false; @@ -242,6 +243,12 @@ VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) { return AddFingerprint(fingerprint, true); } +void VisitedLinkMaster::PostIOTask(const tracked_objects::Location& from_here, + const base::Closure& task) { + BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(sequence_token_, + from_here, task); +} + void VisitedLinkMaster::AddURL(const GURL& url) { Hash index = TryToAddURL(url); if (!table_builder_ && index != null_hash_) { @@ -480,10 +487,7 @@ bool VisitedLinkMaster::WriteFullTable() { hash_table_, table_length_ * sizeof(Fingerprint)); // The hash table may have shrunk, so make sure this is the end. - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - base::Bind(base::IgnoreResult(&TruncateFile), file_)); + PostIOTask(FROM_HERE, base::Bind(base::IgnoreResult(&TruncateFile), file_)); return true; } @@ -673,11 +677,7 @@ void VisitedLinkMaster::FreeURLTable() { } if (!file_) return; - - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - base::Bind(base::IgnoreResult(&fclose), file_)); + PostIOTask(FROM_HERE, base::Bind(base::IgnoreResult(&fclose), file_)); } bool VisitedLinkMaster::ResizeTableIfNecessary() { @@ -860,9 +860,7 @@ void VisitedLinkMaster::WriteToFile(FILE* file, #ifndef NDEBUG posted_asynchronous_operation_ = true; #endif - - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, + PostIOTask(FROM_HERE, base::Bind(&AsyncWrite, file, offset, std::string(static_cast<const char*>(data), data_size))); } diff --git a/chrome/browser/visitedlink/visitedlink_master.h b/chrome/browser/visitedlink/visitedlink_master.h index c84e809..1771afe 100644 --- a/chrome/browser/visitedlink/visitedlink_master.h +++ b/chrome/browser/visitedlink/visitedlink_master.h @@ -17,6 +17,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/shared_memory.h" +#include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/history/history.h" #include "chrome/common/visitedlink_common.h" @@ -163,6 +164,10 @@ class VisitedLinkMaster : public VisitedLinkCommon { // File I/O functions // ------------------ + // Posts the given task to the blocking worker pool with our options. + void PostIOTask(const tracked_objects::Location& from_here, + const base::Closure& task); + // Writes the entire table to disk, returning true on success. It will leave // the table file open and the handle to it in file_ bool WriteFullTable(); @@ -312,6 +317,9 @@ class VisitedLinkMaster : public VisitedLinkCommon { // (it knows the path to where the data is stored) Profile* profile_; + // Lazily initialized sequence token for posting file tasks. + base::SequencedWorkerPool::SequenceToken sequence_token_; + // When non-NULL, indicates we are in database rebuild mode and points to // the class collecting fingerprint information from the history system. // The pointer is owned by this class, but it must remain valid while the diff --git a/chrome/browser/visitedlink/visitedlink_unittest.cc b/chrome/browser/visitedlink/visitedlink_unittest.cc index 2d52cb0..536384f 100644 --- a/chrome/browser/visitedlink/visitedlink_unittest.cc +++ b/chrome/browser/visitedlink/visitedlink_unittest.cc @@ -116,6 +116,9 @@ class VisitedLinkTest : public testing::Test { // our destroy task. MessageLoop::current()->Run(); } + + // Wait for all pending file I/O to be completed. + BrowserThread::GetBlockingPool()->FlushForTesting(); } // Loads the database from disk and makes sure that the same URLs are present 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; diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h index d106929..f35ec00 100644 --- a/content/public/browser/browser_thread.h +++ b/content/public/browser/browser_thread.h @@ -20,6 +20,7 @@ class MessageLoop; namespace base { +class SequencedWorkerPool; class Thread; } @@ -137,6 +138,34 @@ class CONTENT_EXPORT BrowserThread { from_here, object); } + // Simplified wrappers for posting to the blocking thread pool. Use this + // for doing things like blocking I/O. + // + // The first variant will run the task in the pool with no sequencing + // semantics, so may get run in parallel with other posted tasks. The + // second variant provides sequencing between tasks with the same + // sequence token name. + // + // These tasks are guaranteed to run before shutdown. + // + // If you need to provide different shutdown semantics (like you have + // something slow and noncritical that doesn't need to block shutdown), + // or you want to manually provide a sequence token (which saves a map + // lookup and is guaranteed unique without you having to come up with a + // unique string), you can access the sequenced worker pool directly via + // GetBlockingPool(). + static bool PostBlockingPoolTask(const tracked_objects::Location& from_here, + const base::Closure& task); + static bool PostBlockingPoolSequencedTask( + const std::string& sequence_token_name, + const tracked_objects::Location& from_here, + const base::Closure& task); + + // Returns the thread pool used for blocking file I/O. Use this object to + // perform random blocking operations such as file writes or querying the + // Windows registry. + static base::SequencedWorkerPool* GetBlockingPool(); + // Callable on any thread. Returns whether the given ID corresponds to a well // known thread. static bool IsWellKnownThread(ID identifier); |