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

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: Review comment. 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 =
(...skipping 21 matching lines...) Expand all
287 BrowserThreadGlobals& globals = g_globals.Get(); 300 BrowserThreadGlobals& globals = g_globals.Get();
288 base::AutoLock lock(globals.lock); 301 base::AutoLock lock(globals.lock);
289 globals.threads[identifier_] = NULL; 302 globals.threads[identifier_] = NULL;
290 #ifndef NDEBUG 303 #ifndef NDEBUG
291 // Double check that the threads are ordered correctly in the enumeration. 304 // Double check that the threads are ordered correctly in the enumeration.
292 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 305 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
293 DCHECK(!globals.threads[i]) << 306 DCHECK(!globals.threads[i]) <<
294 "Threads must be listed in the reverse order that they die"; 307 "Threads must be listed in the reverse order that they die";
295 } 308 }
296 #endif 309 #endif
310
311 if (g_browser_thread.Get().Get() == this)
kinuko 2016/01/08 11:35:50 Is this condition for tests?
Anand Mistry (off Chromium) 2016/01/10 23:18:28 This is for the main/UI thread, where a BrowserThr
kinuko 2016/01/11 03:52:22 I see thanks, could we add a short comment about t
312 g_browser_thread.Get().Set(nullptr);
297 } 313 }
298 314
299 bool BrowserThreadImpl::StartWithOptions(const Options& options) { 315 bool BrowserThreadImpl::StartWithOptions(const Options& options) {
300 // The global thread table needs to be locked while a new thread is 316 // The global thread table needs to be locked while a new thread is
301 // starting, as the new thread can asynchronously start touching the 317 // starting, as the new thread can asynchronously start touching the
302 // table (and other thread's message_loop). 318 // table (and other thread's message_loop).
303 BrowserThreadGlobals& globals = g_globals.Get(); 319 BrowserThreadGlobals& globals = g_globals.Get();
304 base::AutoLock lock(globals.lock); 320 base::AutoLock lock(globals.lock);
305 return Thread::StartWithOptions(options); 321 return Thread::StartWithOptions(options);
306 } 322 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 return false; 407 return false;
392 408
393 BrowserThreadGlobals& globals = g_globals.Get(); 409 BrowserThreadGlobals& globals = g_globals.Get();
394 base::AutoLock lock(globals.lock); 410 base::AutoLock lock(globals.lock);
395 DCHECK(identifier >= 0 && identifier < ID_COUNT); 411 DCHECK(identifier >= 0 && identifier < ID_COUNT);
396 return globals.threads[identifier] != NULL; 412 return globals.threads[identifier] != NULL;
397 } 413 }
398 414
399 // static 415 // static
400 bool BrowserThread::CurrentlyOn(ID identifier) { 416 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(); 417 BrowserThreadGlobals& globals = g_globals.Get();
407 base::AutoLock lock(globals.lock); 418 base::AutoLock lock(globals.lock);
408 DCHECK(identifier >= 0 && identifier < ID_COUNT); 419 DCHECK(identifier >= 0 && identifier < ID_COUNT);
409 return globals.threads[identifier] && 420 return globals.threads[identifier] &&
410 globals.threads[identifier]->message_loop() == 421 globals.threads[identifier]->message_loop() ==
411 base::MessageLoop::current(); 422 base::MessageLoop::current();
412 } 423 }
413 424
414 static const char* GetThreadName(BrowserThread::ID thread) { 425 static const char* GetThreadName(BrowserThread::ID thread) {
415 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) 426 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 const base::Closure& task, 503 const base::Closure& task,
493 const base::Closure& reply) { 504 const base::Closure& reply) {
494 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, 505 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
495 task, 506 task,
496 reply); 507 reply);
497 } 508 }
498 509
499 // static 510 // static
500 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 511 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
501 if (g_globals == NULL) 512 if (g_globals == NULL)
502 return false; 513 return false;
kinuko 2016/01/08 11:35:50 Do we still need to check this?
Anand Mistry (off Chromium) 2016/01/10 23:18:28 Nope. Removed.
503 514
504 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 515 BrowserThreadImpl* browser_thread = g_browser_thread.Get().Get();
505 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 516 if (!browser_thread)
506 // function. 517 return false;
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 518
519 return false; 519 *identifier = browser_thread->identifier_;
520 return true;
520 } 521 }
521 522
522 // static 523 // static
523 scoped_refptr<base::SingleThreadTaskRunner> 524 scoped_refptr<base::SingleThreadTaskRunner>
524 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { 525 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
525 return g_task_runners.Get().proxies[identifier]; 526 return g_task_runners.Get().proxies[identifier];
526 } 527 }
527 528
528 // static 529 // static
529 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 530 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
(...skipping 16 matching lines...) Expand all
546 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 547 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
547 &globals.thread_delegates[identifier]); 548 &globals.thread_delegates[identifier]);
548 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 549 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
549 storage, reinterpret_cast<AtomicWord>(delegate)); 550 storage, reinterpret_cast<AtomicWord>(delegate));
550 551
551 // This catches registration when previously registered. 552 // This catches registration when previously registered.
552 DCHECK(!delegate || !old_pointer); 553 DCHECK(!delegate || !old_pointer);
553 } 554 }
554 555
555 } // namespace content 556 } // 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