Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |