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

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: Rebase 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/profiler/scoped_tracker.h"
16 #include "base/single_thread_task_runner.h" 17 #include "base/single_thread_task_runner.h"
17 #include "base/threading/sequenced_worker_pool.h" 18 #include "base/threading/sequenced_worker_pool.h"
18 #include "base/threading/thread_restrictions.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 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 #if defined(OS_ANDROID) 223 #if defined(OS_ANDROID)
224 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name. 224 // 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 225 // Though it may create unnecessary VM thread objects, keeping thread name
226 // gives more benefit in debugging in the platform. 226 // gives more benefit in debugging in the platform.
227 if (!thread_name().empty()) { 227 if (!thread_name().empty()) {
228 base::android::AttachCurrentThreadWithName(thread_name()); 228 base::android::AttachCurrentThreadWithName(thread_name());
229 } 229 }
230 #endif 230 #endif
231 231
232 BrowserThread::ID thread_id = ID_COUNT; 232 BrowserThread::ID thread_id = ID_COUNT;
233 if (!GetCurrentThreadIdentifier(&thread_id)) 233 CHECK(GetCurrentThreadIdentifier(&thread_id));
234 return Thread::Run(message_loop); 234 CHECK_EQ(identifier_, thread_id);
235 CHECK_EQ(Thread::message_loop(), message_loop);
235 236
236 switch (thread_id) { 237 switch (identifier_) {
237 case BrowserThread::UI: 238 case BrowserThread::UI:
238 return UIThreadRun(message_loop); 239 return UIThreadRun(message_loop);
239 case BrowserThread::DB: 240 case BrowserThread::DB:
240 return DBThreadRun(message_loop); 241 return DBThreadRun(message_loop);
241 case BrowserThread::FILE: 242 case BrowserThread::FILE:
242 return FileThreadRun(message_loop); 243 return FileThreadRun(message_loop);
243 case BrowserThread::FILE_USER_BLOCKING: 244 case BrowserThread::FILE_USER_BLOCKING:
244 return FileUserBlockingThreadRun(message_loop); 245 return FileUserBlockingThreadRun(message_loop);
245 case BrowserThread::PROCESS_LAUNCHER: 246 case BrowserThread::PROCESS_LAUNCHER:
246 return ProcessLauncherThreadRun(message_loop); 247 return ProcessLauncherThreadRun(message_loop);
247 case BrowserThread::CACHE: 248 case BrowserThread::CACHE:
248 return CacheThreadRun(message_loop); 249 return CacheThreadRun(message_loop);
249 case BrowserThread::IO: 250 case BrowserThread::IO:
250 return IOThreadRun(message_loop); 251 return IOThreadRun(message_loop);
251 case BrowserThread::ID_COUNT: 252 case BrowserThread::ID_COUNT:
252 CHECK(false); // This shouldn't actually be reached! 253 CHECK(false); // This shouldn't actually be reached!
253 break; 254 break;
254 } 255 }
255 Thread::Run(message_loop); 256
257 // |identifier_| must be set to a valid enum value in the constructor, so it
258 // should be impossible to reach here.
259 CHECK(false);
256 } 260 }
257 261
258 void BrowserThreadImpl::CleanUp() { 262 void BrowserThreadImpl::CleanUp() {
259 BrowserThreadGlobals& globals = g_globals.Get(); 263 BrowserThreadGlobals& globals = g_globals.Get();
260 264
261 using base::subtle::AtomicWord; 265 using base::subtle::AtomicWord;
262 AtomicWord* storage = 266 AtomicWord* storage =
263 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 267 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
264 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 268 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
265 BrowserThreadDelegate* delegate = 269 BrowserThreadDelegate* delegate =
266 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 270 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
267 271
268 if (delegate) 272 if (delegate)
269 delegate->CleanUp(); 273 delegate->CleanUp();
274
275 // PostTaskHelper() accesses the message loop while holding this lock.
276 // However, the message loop will soon be destructed without any locking. So
277 // to prevent a race with accessing the message loop in PostTaskHelper(),
278 // remove this thread from the global array now.
279 base::AutoLock lock(globals.lock);
280 globals.threads[identifier_] = NULL;
270 } 281 }
271 282
272 void BrowserThreadImpl::Initialize() { 283 void BrowserThreadImpl::Initialize() {
273 BrowserThreadGlobals& globals = g_globals.Get(); 284 BrowserThreadGlobals& globals = g_globals.Get();
274 285
275 base::AutoLock lock(globals.lock); 286 base::AutoLock lock(globals.lock);
276 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); 287 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
277 DCHECK(globals.threads[identifier_] == NULL); 288 DCHECK(globals.threads[identifier_] == NULL);
278 globals.threads[identifier_] = this; 289 globals.threads[identifier_] = this;
279 } 290 }
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 return false; 402 return false;
392 403
393 BrowserThreadGlobals& globals = g_globals.Get(); 404 BrowserThreadGlobals& globals = g_globals.Get();
394 base::AutoLock lock(globals.lock); 405 base::AutoLock lock(globals.lock);
395 DCHECK(identifier >= 0 && identifier < ID_COUNT); 406 DCHECK(identifier >= 0 && identifier < ID_COUNT);
396 return globals.threads[identifier] != NULL; 407 return globals.threads[identifier] != NULL;
397 } 408 }
398 409
399 // static 410 // static
400 bool BrowserThread::CurrentlyOn(ID identifier) { 411 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(); 412 BrowserThreadGlobals& globals = g_globals.Get();
407 base::AutoLock lock(globals.lock); 413 base::AutoLock lock(globals.lock);
408 DCHECK(identifier >= 0 && identifier < ID_COUNT); 414 DCHECK(identifier >= 0 && identifier < ID_COUNT);
409 return globals.threads[identifier] && 415 return globals.threads[identifier] &&
410 globals.threads[identifier]->message_loop() == 416 globals.threads[identifier]->message_loop() ==
411 base::MessageLoop::current(); 417 base::MessageLoop::current();
412 } 418 }
413 419
414 static const char* GetThreadName(BrowserThread::ID thread) { 420 static const char* GetThreadName(BrowserThread::ID thread) {
415 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) 421 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, 500 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
495 task, 501 task,
496 reply); 502 reply);
497 } 503 }
498 504
499 // static 505 // static
500 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 506 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
501 if (g_globals == NULL) 507 if (g_globals == NULL)
502 return false; 508 return false;
503 509
504 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
505 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
506 // function.
507 // http://crbug.com/63678
508 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
509 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); 510 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
510 BrowserThreadGlobals& globals = g_globals.Get(); 511 BrowserThreadGlobals& globals = g_globals.Get();
512 // Profiler to track potential contention on |globals.lock|. This only does
513 // real work on canary and local dev builds, so the cost of having this here
514 // should be minimal.
515 tracked_objects::ScopedTracker tracking_profile(FROM_HERE);
516 base::AutoLock lock(globals.lock);
511 for (int i = 0; i < ID_COUNT; ++i) { 517 for (int i = 0; i < ID_COUNT; ++i) {
512 if (globals.threads[i] && 518 if (globals.threads[i] &&
513 globals.threads[i]->message_loop() == cur_message_loop) { 519 globals.threads[i]->message_loop() == cur_message_loop) {
514 *identifier = globals.threads[i]->identifier_; 520 *identifier = globals.threads[i]->identifier_;
515 return true; 521 return true;
516 } 522 }
517 } 523 }
518 524
519 return false; 525 return false;
520 } 526 }
(...skipping 25 matching lines...) Expand all
546 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 552 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
547 &globals.thread_delegates[identifier]); 553 &globals.thread_delegates[identifier]);
548 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 554 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
549 storage, reinterpret_cast<AtomicWord>(delegate)); 555 storage, reinterpret_cast<AtomicWord>(delegate));
550 556
551 // This catches registration when previously registered. 557 // This catches registration when previously registered.
552 DCHECK(!delegate || !old_pointer); 558 DCHECK(!delegate || !old_pointer);
553 } 559 }
554 560
555 } // namespace content 561 } // 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