Chromium Code Reviews| Index: content/browser/browser_thread_impl.cc |
| diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc |
| index b86643970e599c88c4bb044765f5e5d15ed0a160..4417e3042455b5d549cb602be1220c0ac10e5771 100644 |
| --- a/content/browser/browser_thread_impl.cc |
| +++ b/content/browser/browser_thread_impl.cc |
| @@ -15,7 +15,7 @@ |
| #include "base/macros.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| -#include "base/threading/thread_restrictions.h" |
| +#include "base/threading/thread_local.h" |
| #include "build/build_config.h" |
| #include "content/public/browser/browser_thread_delegate.h" |
| #include "content/public/browser/content_browser_client.h" |
| @@ -117,6 +117,9 @@ struct BrowserThreadGlobals { |
| base::LazyInstance<BrowserThreadGlobals>::Leaky |
| g_globals = LAZY_INSTANCE_INITIALIZER; |
| +base::LazyInstance<base::ThreadLocalPointer<BrowserThreadImpl>>::Leaky |
| + g_browser_thread = LAZY_INSTANCE_INITIALIZER; |
| + |
| } // namespace |
| BrowserThreadImpl::BrowserThreadImpl(ID identifier) |
| @@ -130,6 +133,13 @@ BrowserThreadImpl::BrowserThreadImpl(ID identifier, |
| : Thread(message_loop->thread_name()), identifier_(identifier) { |
| set_message_loop(message_loop); |
| Initialize(); |
| + |
| + if (message_loop == base::MessageLoop::current()) { |
| + // In tests, it's possible for the same current MessageLoop to be assigned |
| + // to multiple BrowserThreadImpls. |
| + if (!g_browser_thread.Get().Get()) |
| + g_browser_thread.Get().Set(this); |
| + } |
| } |
| // static |
| @@ -229,11 +239,11 @@ void BrowserThreadImpl::Run(base::MessageLoop* message_loop) { |
| } |
| #endif |
| - BrowserThread::ID thread_id = ID_COUNT; |
| - if (!GetCurrentThreadIdentifier(&thread_id)) |
| - return Thread::Run(message_loop); |
| + DCHECK(!g_browser_thread.Get().Get()); |
| + g_browser_thread.Get().Set(this); |
| + CHECK_EQ(Thread::message_loop(), message_loop); |
| - switch (thread_id) { |
| + switch (identifier_) { |
| case BrowserThread::UI: |
| return UIThreadRun(message_loop); |
| case BrowserThread::DB: |
| @@ -252,7 +262,10 @@ void BrowserThreadImpl::Run(base::MessageLoop* message_loop) { |
| CHECK(false); // This shouldn't actually be reached! |
| break; |
| } |
| - Thread::Run(message_loop); |
| + |
| + // |identifier_| must be set to a valid enum value in the constructor, so it |
| + // should be impossible to reach here. |
| + CHECK(false); |
| } |
| void BrowserThreadImpl::CleanUp() { |
| @@ -267,6 +280,13 @@ void BrowserThreadImpl::CleanUp() { |
| if (delegate) |
| delegate->CleanUp(); |
| + |
| + // PostTaskHelper() accesses the message loop while holding this lock. |
| + // However, the message loop will soon be destructed without any locking. So |
| + // to prevent a race with accessing the message loop in PostTaskHelper(), |
| + // remove this thread from the global array now. |
| + base::AutoLock lock(globals.lock); |
| + globals.threads[identifier_] = NULL; |
| } |
| void BrowserThreadImpl::Initialize() { |
| @@ -294,6 +314,13 @@ BrowserThreadImpl::~BrowserThreadImpl() { |
| "Threads must be listed in the reverse order that they die"; |
| } |
| #endif |
| + |
| + // For the UI thread, a BrowserThreadImpl is created and attached to the |
| + // current thread instead of spawning a new thread. Because of this, the |
| + // BrowserThreadImpl pointer needs to be reset here if |this| is for the |
| + // current thread. |
| + if (g_browser_thread.Get().Get() == this) |
| + g_browser_thread.Get().Set(nullptr); |
| } |
| bool BrowserThreadImpl::StartWithOptions(const Options& options) { |
| @@ -398,17 +425,29 @@ bool BrowserThread::IsThreadInitialized(ID 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; |
| - BrowserThreadGlobals& globals = g_globals.Get(); |
| - base::AutoLock lock(globals.lock); |
| DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| - return globals.threads[identifier] && |
| - globals.threads[identifier]->message_loop() == |
| - base::MessageLoop::current(); |
| + |
| + { |
| + BrowserThreadGlobals& globals = g_globals.Get(); |
| + base::AutoLock lock(globals.lock); |
| + // On shutdown, the global thread array could have been set to null, even |
|
kinuko
2016/01/19 14:27:20
nit: The expression 'on shutdown' feels a bit ambi
Anand Mistry (off Chromium)
2016/01/20 02:49:48
This whole section is gone.
|
| + // though we're running on the target thread. This would happen for message |
| + // loop destruction observers and any object bound to a callback that is |
| + // destroyed when the message loop is destroyed. In this case, fall back to |
| + // using the thread local. Ideally, only the thread local would be used, but |
| + // unit tests have multiple BrowserThreadImpl objects bound to the same |
| + // thread. |
| + if (globals.threads[identifier]) { |
| + return globals.threads[identifier]->message_loop() == |
| + base::MessageLoop::current(); |
| + } |
|
kinuko
2016/01/19 14:27:20
Hmm I see. But if that's the case it starts to so
Anand Mistry (off Chromium)
2016/01/20 02:49:48
So, with even more staring at code, I've determine
|
| + } |
| + |
| + BrowserThreadImpl* browser_thread = g_browser_thread.Get().Get(); |
| + if (!browser_thread) |
| + return false; |
| + |
| + return identifier == browser_thread->identifier_; |
| } |
| static const char* GetThreadName(BrowserThread::ID thread) { |
| @@ -498,25 +537,12 @@ bool BrowserThread::PostTaskAndReply( |
| // static |
| bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { |
| - if (g_globals == NULL) |
| + BrowserThreadImpl* browser_thread = g_browser_thread.Get().Get(); |
| + if (!browser_thread) |
| return false; |
| - // 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::MessageLoop* cur_message_loop = base::MessageLoop::current(); |
| - BrowserThreadGlobals& globals = g_globals.Get(); |
| - for (int i = 0; i < ID_COUNT; ++i) { |
| - if (globals.threads[i] && |
| - globals.threads[i]->message_loop() == cur_message_loop) { |
| - *identifier = globals.threads[i]->identifier_; |
| - return true; |
| - } |
| - } |
| - |
| - return false; |
| + *identifier = browser_thread->identifier_; |
| + return true; |
| } |
| // static |