Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(626)

Side by Side Diff: content/browser/browser_thread_impl.cc

Issue 1564193002: Fix race in BrowserThread::GetCurrentThreadIdentifier. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix tests failures. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/sanitizers/tsan_suppressions.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/browser_thread_impl.h" 5 #include "content/browser/browser_thread_impl.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include <string> 9 #include <string>
10 10
11 #include "base/atomicops.h" 11 #include "base/atomicops.h"
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
14 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
15 #include "base/macros.h" 15 #include "base/macros.h"
16 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
17 #include "base/threading/sequenced_worker_pool.h" 17 #include "base/threading/sequenced_worker_pool.h"
18 #include "base/threading/thread_restrictions.h" 18 #include "base/threading/thread_local.h"
19 #include "build/build_config.h" 19 #include "build/build_config.h"
20 #include "content/public/browser/browser_thread_delegate.h" 20 #include "content/public/browser/browser_thread_delegate.h"
21 #include "content/public/browser/content_browser_client.h" 21 #include "content/public/browser/content_browser_client.h"
22 #include "net/disk_cache/simple/simple_backend_impl.h" 22 #include "net/disk_cache/simple/simple_backend_impl.h"
23 23
24 #if defined(OS_ANDROID) 24 #if defined(OS_ANDROID)
25 #include "base/android/jni_android.h" 25 #include "base/android/jni_android.h"
26 #endif 26 #endif
27 27
28 namespace content { 28 namespace content {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 // Only atomic operations are used on this array. The delegates are not owned 110 // Only atomic operations are used on this array. The delegates are not owned
111 // by this array, rather by whoever calls BrowserThread::SetDelegate. 111 // by this array, rather by whoever calls BrowserThread::SetDelegate.
112 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; 112 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
113 113
114 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; 114 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
115 }; 115 };
116 116
117 base::LazyInstance<BrowserThreadGlobals>::Leaky 117 base::LazyInstance<BrowserThreadGlobals>::Leaky
118 g_globals = LAZY_INSTANCE_INITIALIZER; 118 g_globals = LAZY_INSTANCE_INITIALIZER;
119 119
120 base::LazyInstance<base::ThreadLocalPointer<BrowserThreadImpl>>::Leaky
121 g_browser_thread = LAZY_INSTANCE_INITIALIZER;
122
120 } // namespace 123 } // namespace
121 124
122 BrowserThreadImpl::BrowserThreadImpl(ID identifier) 125 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
123 : Thread(g_browser_thread_names[identifier]), 126 : Thread(g_browser_thread_names[identifier]),
124 identifier_(identifier) { 127 identifier_(identifier) {
125 Initialize(); 128 Initialize();
126 } 129 }
127 130
128 BrowserThreadImpl::BrowserThreadImpl(ID identifier, 131 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
129 base::MessageLoop* message_loop) 132 base::MessageLoop* message_loop)
130 : Thread(message_loop->thread_name()), identifier_(identifier) { 133 : Thread(message_loop->thread_name()), identifier_(identifier) {
131 set_message_loop(message_loop); 134 set_message_loop(message_loop);
132 Initialize(); 135 Initialize();
136
137 if (message_loop == base::MessageLoop::current()) {
138 // In tests, it's possible for the same current MessageLoop to be assigned
139 // to multiple BrowserThreadImpls.
140 if (!g_browser_thread.Get().Get())
141 g_browser_thread.Get().Set(this);
142 }
133 } 143 }
134 144
135 // static 145 // static
136 void BrowserThreadImpl::ShutdownThreadPool() { 146 void BrowserThreadImpl::ShutdownThreadPool() {
137 // The goal is to make it impossible for chrome to 'infinite loop' during 147 // The goal is to make it impossible for chrome to 'infinite loop' during
138 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued 148 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
139 // during shutdown get run. There's nothing particularly scientific about the 149 // during shutdown get run. There's nothing particularly scientific about the
140 // number chosen. 150 // number chosen.
141 const int kMaxNewShutdownBlockingTasks = 1000; 151 const int kMaxNewShutdownBlockingTasks = 1000;
142 BrowserThreadGlobals& globals = g_globals.Get(); 152 BrowserThreadGlobals& globals = g_globals.Get();
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 void BrowserThreadImpl::Run(base::MessageLoop* message_loop) { 232 void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
223 #if defined(OS_ANDROID) 233 #if defined(OS_ANDROID)
224 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name. 234 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
225 // Though it may create unnecessary VM thread objects, keeping thread name 235 // Though it may create unnecessary VM thread objects, keeping thread name
226 // gives more benefit in debugging in the platform. 236 // gives more benefit in debugging in the platform.
227 if (!thread_name().empty()) { 237 if (!thread_name().empty()) {
228 base::android::AttachCurrentThreadWithName(thread_name()); 238 base::android::AttachCurrentThreadWithName(thread_name());
229 } 239 }
230 #endif 240 #endif
231 241
232 BrowserThread::ID thread_id = ID_COUNT; 242 DCHECK(!g_browser_thread.Get().Get());
233 if (!GetCurrentThreadIdentifier(&thread_id)) 243 g_browser_thread.Get().Set(this);
234 return Thread::Run(message_loop); 244 CHECK_EQ(Thread::message_loop(), message_loop);
235 245
236 switch (thread_id) { 246 switch (identifier_) {
237 case BrowserThread::UI: 247 case BrowserThread::UI:
238 return UIThreadRun(message_loop); 248 return UIThreadRun(message_loop);
239 case BrowserThread::DB: 249 case BrowserThread::DB:
240 return DBThreadRun(message_loop); 250 return DBThreadRun(message_loop);
241 case BrowserThread::FILE: 251 case BrowserThread::FILE:
242 return FileThreadRun(message_loop); 252 return FileThreadRun(message_loop);
243 case BrowserThread::FILE_USER_BLOCKING: 253 case BrowserThread::FILE_USER_BLOCKING:
244 return FileUserBlockingThreadRun(message_loop); 254 return FileUserBlockingThreadRun(message_loop);
245 case BrowserThread::PROCESS_LAUNCHER: 255 case BrowserThread::PROCESS_LAUNCHER:
246 return ProcessLauncherThreadRun(message_loop); 256 return ProcessLauncherThreadRun(message_loop);
247 case BrowserThread::CACHE: 257 case BrowserThread::CACHE:
248 return CacheThreadRun(message_loop); 258 return CacheThreadRun(message_loop);
249 case BrowserThread::IO: 259 case BrowserThread::IO:
250 return IOThreadRun(message_loop); 260 return IOThreadRun(message_loop);
251 case BrowserThread::ID_COUNT: 261 case BrowserThread::ID_COUNT:
252 CHECK(false); // This shouldn't actually be reached! 262 CHECK(false); // This shouldn't actually be reached!
253 break; 263 break;
254 } 264 }
255 Thread::Run(message_loop); 265
266 // |identifier_| must be set to a valid enum value in the constructor, so it
267 // should be impossible to reach here.
268 CHECK(false);
256 } 269 }
257 270
258 void BrowserThreadImpl::CleanUp() { 271 void BrowserThreadImpl::CleanUp() {
259 BrowserThreadGlobals& globals = g_globals.Get(); 272 BrowserThreadGlobals& globals = g_globals.Get();
260 273
261 using base::subtle::AtomicWord; 274 using base::subtle::AtomicWord;
262 AtomicWord* storage = 275 AtomicWord* storage =
263 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 276 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
264 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 277 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
265 BrowserThreadDelegate* delegate = 278 BrowserThreadDelegate* delegate =
266 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 279 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
267 280
268 if (delegate) 281 if (delegate)
269 delegate->CleanUp(); 282 delegate->CleanUp();
283
284 // PostTaskHelper() accesses the message loop while holding this lock.
285 // However, the message loop will soon be destructed without any locking. So
286 // to prevent a race with accessing the message loop in PostTaskHelper(),
287 // remove this thread from the global array now.
288 base::AutoLock lock(globals.lock);
289 globals.threads[identifier_] = NULL;
270 } 290 }
271 291
272 void BrowserThreadImpl::Initialize() { 292 void BrowserThreadImpl::Initialize() {
273 BrowserThreadGlobals& globals = g_globals.Get(); 293 BrowserThreadGlobals& globals = g_globals.Get();
274 294
275 base::AutoLock lock(globals.lock); 295 base::AutoLock lock(globals.lock);
276 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); 296 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
277 DCHECK(globals.threads[identifier_] == NULL); 297 DCHECK(globals.threads[identifier_] == NULL);
278 globals.threads[identifier_] = this; 298 globals.threads[identifier_] = this;
279 } 299 }
280 300
281 BrowserThreadImpl::~BrowserThreadImpl() { 301 BrowserThreadImpl::~BrowserThreadImpl() {
282 // All Thread subclasses must call Stop() in the destructor. This is 302 // All Thread subclasses must call Stop() in the destructor. This is
283 // doubly important here as various bits of code check they are on 303 // doubly important here as various bits of code check they are on
284 // the right BrowserThread. 304 // the right BrowserThread.
285 Stop(); 305 Stop();
286 306
287 BrowserThreadGlobals& globals = g_globals.Get(); 307 BrowserThreadGlobals& globals = g_globals.Get();
288 base::AutoLock lock(globals.lock); 308 base::AutoLock lock(globals.lock);
289 globals.threads[identifier_] = NULL; 309 globals.threads[identifier_] = NULL;
290 #ifndef NDEBUG 310 #ifndef NDEBUG
291 // Double check that the threads are ordered correctly in the enumeration. 311 // Double check that the threads are ordered correctly in the enumeration.
292 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 312 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
293 DCHECK(!globals.threads[i]) << 313 DCHECK(!globals.threads[i]) <<
294 "Threads must be listed in the reverse order that they die"; 314 "Threads must be listed in the reverse order that they die";
295 } 315 }
296 #endif 316 #endif
317
318 // For the UI thread, a BrowserThreadImpl is created and attached to the
319 // current thread instead of spawning a new thread. Because of this, the
320 // BrowserThreadImpl pointer needs to be reset here if |this| is for the
321 // current thread.
322 if (g_browser_thread.Get().Get() == this)
323 g_browser_thread.Get().Set(nullptr);
297 } 324 }
298 325
299 bool BrowserThreadImpl::StartWithOptions(const Options& options) { 326 bool BrowserThreadImpl::StartWithOptions(const Options& options) {
300 // The global thread table needs to be locked while a new thread is 327 // The global thread table needs to be locked while a new thread is
301 // starting, as the new thread can asynchronously start touching the 328 // starting, as the new thread can asynchronously start touching the
302 // table (and other thread's message_loop). 329 // table (and other thread's message_loop).
303 BrowserThreadGlobals& globals = g_globals.Get(); 330 BrowserThreadGlobals& globals = g_globals.Get();
304 base::AutoLock lock(globals.lock); 331 base::AutoLock lock(globals.lock);
305 return Thread::StartWithOptions(options); 332 return Thread::StartWithOptions(options);
306 } 333 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 return false; 418 return false;
392 419
393 BrowserThreadGlobals& globals = g_globals.Get(); 420 BrowserThreadGlobals& globals = g_globals.Get();
394 base::AutoLock lock(globals.lock); 421 base::AutoLock lock(globals.lock);
395 DCHECK(identifier >= 0 && identifier < ID_COUNT); 422 DCHECK(identifier >= 0 && identifier < ID_COUNT);
396 return globals.threads[identifier] != NULL; 423 return globals.threads[identifier] != NULL;
397 } 424 }
398 425
399 // static 426 // static
400 bool BrowserThread::CurrentlyOn(ID identifier) { 427 bool BrowserThread::CurrentlyOn(ID identifier) {
401 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
402 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
403 // function.
404 // http://crbug.com/63678
405 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
406 BrowserThreadGlobals& globals = g_globals.Get();
407 base::AutoLock lock(globals.lock);
408 DCHECK(identifier >= 0 && identifier < ID_COUNT); 428 DCHECK(identifier >= 0 && identifier < ID_COUNT);
409 return globals.threads[identifier] && 429
410 globals.threads[identifier]->message_loop() == 430 {
411 base::MessageLoop::current(); 431 BrowserThreadGlobals& globals = g_globals.Get();
432 base::AutoLock lock(globals.lock);
433 // 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.
434 // though we're running on the target thread. This would happen for message
435 // loop destruction observers and any object bound to a callback that is
436 // destroyed when the message loop is destroyed. In this case, fall back to
437 // using the thread local. Ideally, only the thread local would be used, but
438 // unit tests have multiple BrowserThreadImpl objects bound to the same
439 // thread.
440 if (globals.threads[identifier]) {
441 return globals.threads[identifier]->message_loop() ==
442 base::MessageLoop::current();
443 }
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
444 }
445
446 BrowserThreadImpl* browser_thread = g_browser_thread.Get().Get();
447 if (!browser_thread)
448 return false;
449
450 return identifier == browser_thread->identifier_;
412 } 451 }
413 452
414 static const char* GetThreadName(BrowserThread::ID thread) { 453 static const char* GetThreadName(BrowserThread::ID thread) {
415 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) 454 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
416 return g_browser_thread_names[thread]; 455 return g_browser_thread_names[thread];
417 if (thread == BrowserThread::UI) 456 if (thread == BrowserThread::UI)
418 return "Chrome_UIThread"; 457 return "Chrome_UIThread";
419 return "Unknown Thread"; 458 return "Unknown Thread";
420 } 459 }
421 460
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 const tracked_objects::Location& from_here, 530 const tracked_objects::Location& from_here,
492 const base::Closure& task, 531 const base::Closure& task,
493 const base::Closure& reply) { 532 const base::Closure& reply) {
494 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, 533 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
495 task, 534 task,
496 reply); 535 reply);
497 } 536 }
498 537
499 // static 538 // static
500 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 539 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
501 if (g_globals == NULL) 540 BrowserThreadImpl* browser_thread = g_browser_thread.Get().Get();
541 if (!browser_thread)
502 return false; 542 return false;
503 543
504 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 544 *identifier = browser_thread->identifier_;
505 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 545 return true;
506 // function.
507 // http://crbug.com/63678
508 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
509 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
510 BrowserThreadGlobals& globals = g_globals.Get();
511 for (int i = 0; i < ID_COUNT; ++i) {
512 if (globals.threads[i] &&
513 globals.threads[i]->message_loop() == cur_message_loop) {
514 *identifier = globals.threads[i]->identifier_;
515 return true;
516 }
517 }
518
519 return false;
520 } 546 }
521 547
522 // static 548 // static
523 scoped_refptr<base::SingleThreadTaskRunner> 549 scoped_refptr<base::SingleThreadTaskRunner>
524 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { 550 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
525 return g_task_runners.Get().proxies[identifier]; 551 return g_task_runners.Get().proxies[identifier];
526 } 552 }
527 553
528 // static 554 // static
529 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 555 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
(...skipping 16 matching lines...) Expand all
546 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 572 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
547 &globals.thread_delegates[identifier]); 573 &globals.thread_delegates[identifier]);
548 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 574 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
549 storage, reinterpret_cast<AtomicWord>(delegate)); 575 storage, reinterpret_cast<AtomicWord>(delegate));
550 576
551 // This catches registration when previously registered. 577 // This catches registration when previously registered.
552 DCHECK(!delegate || !old_pointer); 578 DCHECK(!delegate || !old_pointer);
553 } 579 }
554 580
555 } // namespace content 581 } // namespace content
OLDNEW
« no previous file with comments | « build/sanitizers/tsan_suppressions.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698