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

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: For review 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:
262 default:
kinuko 2016/01/08 08:43:32 Let's avoid having default here, which makes it ha
Anand Mistry (off Chromium) 2016/01/08 09:52:46 Done.
252 CHECK(false); // This shouldn't actually be reached! 263 CHECK(false); // This shouldn't actually be reached!
253 break; 264 break;
254 } 265 }
255 Thread::Run(message_loop);
256 } 266 }
257 267
258 void BrowserThreadImpl::CleanUp() { 268 void BrowserThreadImpl::CleanUp() {
259 BrowserThreadGlobals& globals = g_globals.Get(); 269 BrowserThreadGlobals& globals = g_globals.Get();
260 270
261 using base::subtle::AtomicWord; 271 using base::subtle::AtomicWord;
262 AtomicWord* storage = 272 AtomicWord* storage =
263 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 273 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
264 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 274 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
265 BrowserThreadDelegate* delegate = 275 BrowserThreadDelegate* delegate =
(...skipping 21 matching lines...) Expand all
287 BrowserThreadGlobals& globals = g_globals.Get(); 297 BrowserThreadGlobals& globals = g_globals.Get();
288 base::AutoLock lock(globals.lock); 298 base::AutoLock lock(globals.lock);
289 globals.threads[identifier_] = NULL; 299 globals.threads[identifier_] = NULL;
290 #ifndef NDEBUG 300 #ifndef NDEBUG
291 // Double check that the threads are ordered correctly in the enumeration. 301 // Double check that the threads are ordered correctly in the enumeration.
292 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 302 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
293 DCHECK(!globals.threads[i]) << 303 DCHECK(!globals.threads[i]) <<
294 "Threads must be listed in the reverse order that they die"; 304 "Threads must be listed in the reverse order that they die";
295 } 305 }
296 #endif 306 #endif
307
308 if (g_browser_thread.Get().Get() == this)
309 g_browser_thread.Get().Set(nullptr);
297 } 310 }
298 311
299 bool BrowserThreadImpl::StartWithOptions(const Options& options) { 312 bool BrowserThreadImpl::StartWithOptions(const Options& options) {
300 // The global thread table needs to be locked while a new thread is 313 // The global thread table needs to be locked while a new thread is
301 // starting, as the new thread can asynchronously start touching the 314 // starting, as the new thread can asynchronously start touching the
302 // table (and other thread's message_loop). 315 // table (and other thread's message_loop).
303 BrowserThreadGlobals& globals = g_globals.Get(); 316 BrowserThreadGlobals& globals = g_globals.Get();
304 base::AutoLock lock(globals.lock); 317 base::AutoLock lock(globals.lock);
305 return Thread::StartWithOptions(options); 318 return Thread::StartWithOptions(options);
306 } 319 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 return false; 404 return false;
392 405
393 BrowserThreadGlobals& globals = g_globals.Get(); 406 BrowserThreadGlobals& globals = g_globals.Get();
394 base::AutoLock lock(globals.lock); 407 base::AutoLock lock(globals.lock);
395 DCHECK(identifier >= 0 && identifier < ID_COUNT); 408 DCHECK(identifier >= 0 && identifier < ID_COUNT);
396 return globals.threads[identifier] != NULL; 409 return globals.threads[identifier] != NULL;
397 } 410 }
398 411
399 // static 412 // static
400 bool BrowserThread::CurrentlyOn(ID identifier) { 413 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(); 414 BrowserThreadGlobals& globals = g_globals.Get();
407 base::AutoLock lock(globals.lock); 415 base::AutoLock lock(globals.lock);
408 DCHECK(identifier >= 0 && identifier < ID_COUNT); 416 DCHECK(identifier >= 0 && identifier < ID_COUNT);
409 return globals.threads[identifier] && 417 return globals.threads[identifier] &&
410 globals.threads[identifier]->message_loop() == 418 globals.threads[identifier]->message_loop() ==
411 base::MessageLoop::current(); 419 base::MessageLoop::current();
412 } 420 }
413 421
414 static const char* GetThreadName(BrowserThread::ID thread) { 422 static const char* GetThreadName(BrowserThread::ID thread) {
415 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) 423 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, 502 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
495 task, 503 task,
496 reply); 504 reply);
497 } 505 }
498 506
499 // static 507 // static
500 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 508 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
501 if (g_globals == NULL) 509 if (g_globals == NULL)
502 return false; 510 return false;
503 511
504 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 512 BrowserThreadImpl* browser_thread = g_browser_thread.Get().Get();
505 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 513 if (!browser_thread)
506 // function. 514 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 515
519 return false; 516 *identifier = browser_thread->identifier_;
517 return true;
520 } 518 }
521 519
522 // static 520 // static
523 scoped_refptr<base::SingleThreadTaskRunner> 521 scoped_refptr<base::SingleThreadTaskRunner>
524 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { 522 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
525 return g_task_runners.Get().proxies[identifier]; 523 return g_task_runners.Get().proxies[identifier];
526 } 524 }
527 525
528 // static 526 // static
529 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 527 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
(...skipping 16 matching lines...) Expand all
546 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 544 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
547 &globals.thread_delegates[identifier]); 545 &globals.thread_delegates[identifier]);
548 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 546 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
549 storage, reinterpret_cast<AtomicWord>(delegate)); 547 storage, reinterpret_cast<AtomicWord>(delegate));
550 548
551 // This catches registration when previously registered. 549 // This catches registration when previously registered.
552 DCHECK(!delegate || !old_pointer); 550 DCHECK(!delegate || !old_pointer);
553 } 551 }
554 552
555 } // namespace content 553 } // 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