| 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 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners = | 99 base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners = |
| 100 LAZY_INSTANCE_INITIALIZER; | 100 LAZY_INSTANCE_INITIALIZER; |
| 101 | 101 |
| 102 struct BrowserThreadGlobals { | 102 struct BrowserThreadGlobals { |
| 103 BrowserThreadGlobals() | 103 BrowserThreadGlobals() |
| 104 : blocking_pool( | 104 : blocking_pool( |
| 105 new base::SequencedWorkerPool(3, | 105 new base::SequencedWorkerPool(3, |
| 106 "BrowserBlocking", | 106 "BrowserBlocking", |
| 107 base::TaskPriority::USER_VISIBLE)) { | 107 base::TaskPriority::USER_VISIBLE)) { |
| 108 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0])); | 108 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0])); |
| 109 memset(thread_ids, 0, BrowserThread::ID_COUNT * sizeof(thread_ids[0])); | |
| 110 memset(thread_delegates, 0, | 109 memset(thread_delegates, 0, |
| 111 BrowserThread::ID_COUNT * sizeof(thread_delegates[0])); | 110 BrowserThread::ID_COUNT * sizeof(thread_delegates[0])); |
| 112 } | 111 } |
| 113 | 112 |
| 114 // This lock protects |threads| and |thread_ids|. Do not read or modify those | 113 // This lock protects |threads|. Do not read or modify that array |
| 115 // arrays without holding this lock. Do not block while holding this lock. | 114 // without holding this lock. Do not block while holding this lock. |
| 116 base::Lock lock; | 115 base::Lock lock; |
| 117 | 116 |
| 118 // This array is protected by |lock|. IDs in this array are populated as soon | |
| 119 // as their respective thread is started and are never reset. | |
| 120 base::PlatformThreadId thread_ids[BrowserThread::ID_COUNT]; | |
| 121 | |
| 122 // This array is protected by |lock|. The threads are not owned by this | 117 // This array is protected by |lock|. The threads are not owned by this |
| 123 // array. Typically, the threads are owned on the UI thread by | 118 // array. Typically, the threads are owned on the UI thread by |
| 124 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this | 119 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this |
| 125 // array upon destruction. | 120 // array upon destruction. |
| 126 BrowserThreadImpl* threads[BrowserThread::ID_COUNT]; | 121 BrowserThreadImpl* threads[BrowserThread::ID_COUNT]; |
| 127 | 122 |
| 128 // Only atomic operations are used on this array. The delegates are not owned | 123 // Only atomic operations are used on this array. The delegates are not owned |
| 129 // by this array, rather by whoever calls BrowserThread::SetDelegate. | 124 // by this array, rather by whoever calls BrowserThread::SetDelegate. |
| 130 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; | 125 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; |
| 131 | 126 |
| 132 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; | 127 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; |
| 133 }; | 128 }; |
| 134 | 129 |
| 135 base::LazyInstance<BrowserThreadGlobals>::Leaky | 130 base::LazyInstance<BrowserThreadGlobals>::Leaky |
| 136 g_globals = LAZY_INSTANCE_INITIALIZER; | 131 g_globals = LAZY_INSTANCE_INITIALIZER; |
| 137 | 132 |
| 138 } // namespace | 133 } // namespace |
| 139 | 134 |
| 140 BrowserThreadImpl::BrowserThreadImpl(ID identifier) | 135 BrowserThreadImpl::BrowserThreadImpl(ID identifier) |
| 141 : Thread(GetThreadName(identifier)), identifier_(identifier) { | 136 : Thread(GetThreadName(identifier)), identifier_(identifier) { |
| 142 Initialize(); | 137 Initialize(); |
| 143 | |
| 144 // Unit tests may create multiple TestBrowserThreadBundles, causing the same | |
| 145 // BrowserThread ID to be reinitialized. We explicitly clear the thread ID | |
| 146 // here so Start() can sanity check. | |
| 147 BrowserThreadGlobals& globals = g_globals.Get(); | |
| 148 base::AutoLock lock(globals.lock); | |
| 149 globals.thread_ids[identifier] = base::kInvalidThreadId; | |
| 150 } | 138 } |
| 151 | 139 |
| 152 BrowserThreadImpl::BrowserThreadImpl(ID identifier, | 140 BrowserThreadImpl::BrowserThreadImpl(ID identifier, |
| 153 base::MessageLoop* message_loop) | 141 base::MessageLoop* message_loop) |
| 154 : Thread(GetThreadName(identifier)), identifier_(identifier) { | 142 : Thread(GetThreadName(identifier)), identifier_(identifier) { |
| 155 set_message_loop(message_loop); | 143 set_message_loop(message_loop); |
| 156 Initialize(); | 144 Initialize(); |
| 157 | |
| 158 // If constructed with an explicit message loop, this is a fake BrowserThread | |
| 159 // which runs on the current thread. | |
| 160 BrowserThreadGlobals& globals = g_globals.Get(); | |
| 161 base::AutoLock lock(globals.lock); | |
| 162 globals.thread_ids[identifier] = base::PlatformThread::CurrentId(); | |
| 163 } | 145 } |
| 164 | 146 |
| 165 // static | 147 // static |
| 166 void BrowserThreadImpl::ShutdownThreadPool() { | 148 void BrowserThreadImpl::ShutdownThreadPool() { |
| 167 // The goal is to make it impossible for chrome to 'infinite loop' during | 149 // The goal is to make it impossible for chrome to 'infinite loop' during |
| 168 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued | 150 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued |
| 169 // during shutdown get run. There's nothing particularly scientific about the | 151 // during shutdown get run. There's nothing particularly scientific about the |
| 170 // number chosen. | 152 // number chosen. |
| 171 const int kMaxNewShutdownBlockingTasks = 1000; | 153 const int kMaxNewShutdownBlockingTasks = 1000; |
| 172 BrowserThreadGlobals& globals = g_globals.Get(); | 154 BrowserThreadGlobals& globals = g_globals.Get(); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 globals.threads[identifier_] = nullptr; | 310 globals.threads[identifier_] = nullptr; |
| 329 #ifndef NDEBUG | 311 #ifndef NDEBUG |
| 330 // Double check that the threads are ordered correctly in the enumeration. | 312 // Double check that the threads are ordered correctly in the enumeration. |
| 331 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { | 313 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { |
| 332 DCHECK(!globals.threads[i]) << | 314 DCHECK(!globals.threads[i]) << |
| 333 "Threads must be listed in the reverse order that they die"; | 315 "Threads must be listed in the reverse order that they die"; |
| 334 } | 316 } |
| 335 #endif | 317 #endif |
| 336 } | 318 } |
| 337 | 319 |
| 338 bool BrowserThreadImpl::Start() { | |
| 339 return StartWithOptions(base::Thread::Options()); | |
| 340 } | |
| 341 | |
| 342 bool BrowserThreadImpl::StartWithOptions(const Options& options) { | 320 bool BrowserThreadImpl::StartWithOptions(const Options& options) { |
| 343 // The global thread table needs to be locked while a new thread is | 321 // The global thread table needs to be locked while a new thread is |
| 344 // starting, as the new thread can asynchronously start touching the | 322 // starting, as the new thread can asynchronously start touching the |
| 345 // table (and other thread's message_loop). | 323 // table (and other thread's message_loop). |
| 346 BrowserThreadGlobals& globals = g_globals.Get(); | 324 BrowserThreadGlobals& globals = g_globals.Get(); |
| 347 base::AutoLock lock(globals.lock); | 325 base::AutoLock lock(globals.lock); |
| 348 DCHECK_EQ(globals.thread_ids[identifier_], base::kInvalidThreadId); | 326 return Thread::StartWithOptions(options); |
| 349 bool result = Thread::StartWithOptions(options); | |
| 350 globals.thread_ids[identifier_] = GetThreadId(); | |
| 351 return result; | |
| 352 } | 327 } |
| 353 | 328 |
| 354 bool BrowserThreadImpl::StartAndWaitForTesting() { | |
| 355 if (!Start()) | |
| 356 return false; | |
| 357 WaitUntilThreadStarted(); | |
| 358 return true; | |
| 359 } | |
| 360 // static | 329 // static |
| 361 bool BrowserThreadImpl::PostTaskHelper( | 330 bool BrowserThreadImpl::PostTaskHelper( |
| 362 BrowserThread::ID identifier, | 331 BrowserThread::ID identifier, |
| 363 const tracked_objects::Location& from_here, | 332 const tracked_objects::Location& from_here, |
| 364 const base::Closure& task, | 333 const base::Closure& task, |
| 365 base::TimeDelta delay, | 334 base::TimeDelta delay, |
| 366 bool nestable) { | 335 bool nestable) { |
| 367 DCHECK_GE(identifier, 0); | 336 DCHECK_GE(identifier, 0); |
| 368 DCHECK_LT(identifier, ID_COUNT); | 337 DCHECK_LT(identifier, ID_COUNT); |
| 369 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in | 338 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 DCHECK_LT(identifier, ID_COUNT); | 418 DCHECK_LT(identifier, ID_COUNT); |
| 450 return globals.threads[identifier] != nullptr; | 419 return globals.threads[identifier] != nullptr; |
| 451 } | 420 } |
| 452 | 421 |
| 453 // static | 422 // static |
| 454 bool BrowserThread::CurrentlyOn(ID identifier) { | 423 bool BrowserThread::CurrentlyOn(ID identifier) { |
| 455 BrowserThreadGlobals& globals = g_globals.Get(); | 424 BrowserThreadGlobals& globals = g_globals.Get(); |
| 456 base::AutoLock lock(globals.lock); | 425 base::AutoLock lock(globals.lock); |
| 457 DCHECK_GE(identifier, 0); | 426 DCHECK_GE(identifier, 0); |
| 458 DCHECK_LT(identifier, ID_COUNT); | 427 DCHECK_LT(identifier, ID_COUNT); |
| 459 return base::PlatformThread::CurrentId() == globals.thread_ids[identifier]; | 428 return globals.threads[identifier] && |
| 429 globals.threads[identifier]->message_loop() == |
| 430 base::MessageLoop::current(); |
| 460 } | 431 } |
| 461 | 432 |
| 462 // static | 433 // static |
| 463 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { | 434 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { |
| 464 std::string actual_name = base::PlatformThread::GetName(); | 435 std::string actual_name = base::PlatformThread::GetName(); |
| 465 if (actual_name.empty()) | 436 if (actual_name.empty()) |
| 466 actual_name = "Unknown Thread"; | 437 actual_name = "Unknown Thread"; |
| 467 | 438 |
| 468 std::string result = "Must be called on "; | 439 std::string result = "Must be called on "; |
| 469 result += GetThreadName(expected); | 440 result += GetThreadName(expected); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 AtomicWord* storage = reinterpret_cast<AtomicWord*>( | 553 AtomicWord* storage = reinterpret_cast<AtomicWord*>( |
| 583 &globals.thread_delegates[identifier]); | 554 &globals.thread_delegates[identifier]); |
| 584 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( | 555 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( |
| 585 storage, reinterpret_cast<AtomicWord>(delegate)); | 556 storage, reinterpret_cast<AtomicWord>(delegate)); |
| 586 | 557 |
| 587 // This catches registration when previously registered. | 558 // This catches registration when previously registered. |
| 588 DCHECK(!delegate || !old_pointer); | 559 DCHECK(!delegate || !old_pointer); |
| 589 } | 560 } |
| 590 | 561 |
| 591 } // namespace content | 562 } // namespace content |
| OLD | NEW |