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 |