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 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 151 // during shutdown get run. There's nothing particularly scientific about the | 151 // during shutdown get run. There's nothing particularly scientific about the |
| 152 // number chosen. | 152 // number chosen. |
| 153 const int kMaxNewShutdownBlockingTasks = 1000; | 153 const int kMaxNewShutdownBlockingTasks = 1000; |
| 154 BrowserThreadGlobals& globals = g_globals.Get(); | 154 BrowserThreadGlobals& globals = g_globals.Get(); |
| 155 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks); | 155 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks); |
| 156 } | 156 } |
| 157 | 157 |
| 158 // static | 158 // static |
| 159 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() { | 159 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() { |
| 160 // We don't want to create a pool if none exists. | 160 // We don't want to create a pool if none exists. |
| 161 if (g_globals == NULL) | 161 if (g_globals == nullptr) |
| 162 return; | 162 return; |
| 163 g_globals.Get().blocking_pool->FlushForTesting(); | 163 g_globals.Get().blocking_pool->FlushForTesting(); |
| 164 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); | 164 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); |
| 165 } | 165 } |
| 166 | 166 |
| 167 void BrowserThreadImpl::Init() { | 167 void BrowserThreadImpl::Init() { |
| 168 BrowserThreadGlobals& globals = g_globals.Get(); | 168 BrowserThreadGlobals& globals = g_globals.Get(); |
| 169 | 169 |
| 170 using base::subtle::AtomicWord; | 170 using base::subtle::AtomicWord; |
| 171 AtomicWord* storage = | 171 AtomicWord* storage = |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); | 279 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); |
| 280 | 280 |
| 281 if (delegate) | 281 if (delegate) |
| 282 delegate->CleanUp(); | 282 delegate->CleanUp(); |
| 283 | 283 |
| 284 // PostTaskHelper() accesses the message loop while holding this lock. | 284 // PostTaskHelper() accesses the message loop while holding this lock. |
| 285 // However, the message loop will soon be destructed without any locking. So | 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(), | 286 // to prevent a race with accessing the message loop in PostTaskHelper(), |
| 287 // remove this thread from the global array now. | 287 // remove this thread from the global array now. |
| 288 base::AutoLock lock(globals.lock); | 288 base::AutoLock lock(globals.lock); |
| 289 globals.threads[identifier_] = NULL; | 289 globals.threads[identifier_] = nullptr; |
| 290 } | 290 } |
| 291 | 291 |
| 292 void BrowserThreadImpl::Initialize() { | 292 void BrowserThreadImpl::Initialize() { |
| 293 BrowserThreadGlobals& globals = g_globals.Get(); | 293 BrowserThreadGlobals& globals = g_globals.Get(); |
| 294 | 294 |
| 295 base::AutoLock lock(globals.lock); | 295 base::AutoLock lock(globals.lock); |
| 296 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); | 296 DCHECK(identifier_ >= 0); |
|
no sievers
2016/07/21 19:08:01
nit: you can even do DCHECK_GE(identifier, 0) whic
AKV
2016/07/22 14:26:13
Done. Thanks, that's very helpful in catching fail
| |
| 297 DCHECK(globals.threads[identifier_] == NULL); | 297 DCHECK(identifier_ < ID_COUNT); |
| 298 DCHECK(globals.threads[identifier_] == nullptr); | |
| 298 globals.threads[identifier_] = this; | 299 globals.threads[identifier_] = this; |
| 299 } | 300 } |
| 300 | 301 |
| 301 BrowserThreadImpl::~BrowserThreadImpl() { | 302 BrowserThreadImpl::~BrowserThreadImpl() { |
| 302 // All Thread subclasses must call Stop() in the destructor. This is | 303 // All Thread subclasses must call Stop() in the destructor. This is |
| 303 // doubly important here as various bits of code check they are on | 304 // doubly important here as various bits of code check they are on |
| 304 // the right BrowserThread. | 305 // the right BrowserThread. |
| 305 Stop(); | 306 Stop(); |
| 306 | 307 |
| 307 BrowserThreadGlobals& globals = g_globals.Get(); | 308 BrowserThreadGlobals& globals = g_globals.Get(); |
| 308 base::AutoLock lock(globals.lock); | 309 base::AutoLock lock(globals.lock); |
| 309 globals.threads[identifier_] = NULL; | 310 globals.threads[identifier_] = nullptr; |
| 310 #ifndef NDEBUG | 311 #ifndef NDEBUG |
| 311 // Double check that the threads are ordered correctly in the enumeration. | 312 // Double check that the threads are ordered correctly in the enumeration. |
| 312 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { | 313 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { |
| 313 DCHECK(!globals.threads[i]) << | 314 DCHECK(!globals.threads[i]) << |
| 314 "Threads must be listed in the reverse order that they die"; | 315 "Threads must be listed in the reverse order that they die"; |
| 315 } | 316 } |
| 316 #endif | 317 #endif |
| 317 } | 318 } |
| 318 | 319 |
| 319 bool BrowserThreadImpl::StartWithOptions(const Options& options) { | 320 bool BrowserThreadImpl::StartWithOptions(const Options& options) { |
| 320 // 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 |
| 321 // starting, as the new thread can asynchronously start touching the | 322 // starting, as the new thread can asynchronously start touching the |
| 322 // table (and other thread's message_loop). | 323 // table (and other thread's message_loop). |
| 323 BrowserThreadGlobals& globals = g_globals.Get(); | 324 BrowserThreadGlobals& globals = g_globals.Get(); |
| 324 base::AutoLock lock(globals.lock); | 325 base::AutoLock lock(globals.lock); |
| 325 return Thread::StartWithOptions(options); | 326 return Thread::StartWithOptions(options); |
| 326 } | 327 } |
| 327 | 328 |
| 328 // static | 329 // static |
| 329 bool BrowserThreadImpl::PostTaskHelper( | 330 bool BrowserThreadImpl::PostTaskHelper( |
| 330 BrowserThread::ID identifier, | 331 BrowserThread::ID identifier, |
| 331 const tracked_objects::Location& from_here, | 332 const tracked_objects::Location& from_here, |
| 332 const base::Closure& task, | 333 const base::Closure& task, |
| 333 base::TimeDelta delay, | 334 base::TimeDelta delay, |
| 334 bool nestable) { | 335 bool nestable) { |
| 335 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 336 DCHECK(identifier >= 0); |
| 337 DCHECK(identifier < ID_COUNT); | |
| 336 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in | 338 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in |
| 337 // order of lifetime. So no need to lock if we know that the target thread | 339 // order of lifetime. So no need to lock if we know that the target thread |
| 338 // outlives current thread. | 340 // outlives current thread. |
| 339 // Note: since the array is so small, ok to loop instead of creating a map, | 341 // Note: since the array is so small, ok to loop instead of creating a map, |
| 340 // which would require a lock because std::map isn't thread safe, defeating | 342 // which would require a lock because std::map isn't thread safe, defeating |
| 341 // the whole purpose of this optimization. | 343 // the whole purpose of this optimization. |
| 342 BrowserThread::ID current_thread = ID_COUNT; | 344 BrowserThread::ID current_thread = ID_COUNT; |
| 343 bool target_thread_outlives_current = | 345 bool target_thread_outlives_current = |
| 344 GetCurrentThreadIdentifier(¤t_thread) && | 346 GetCurrentThreadIdentifier(¤t_thread) && |
| 345 current_thread >= identifier; | 347 current_thread >= identifier; |
| 346 | 348 |
| 347 BrowserThreadGlobals& globals = g_globals.Get(); | 349 BrowserThreadGlobals& globals = g_globals.Get(); |
| 348 if (!target_thread_outlives_current) | 350 if (!target_thread_outlives_current) |
| 349 globals.lock.Acquire(); | 351 globals.lock.Acquire(); |
| 350 | 352 |
| 351 base::MessageLoop* message_loop = | 353 base::MessageLoop* message_loop = |
| 352 globals.threads[identifier] ? globals.threads[identifier]->message_loop() | 354 globals.threads[identifier] ? globals.threads[identifier]->message_loop() |
| 353 : NULL; | 355 : nullptr; |
| 354 if (message_loop) { | 356 if (message_loop) { |
| 355 if (nestable) { | 357 if (nestable) { |
| 356 message_loop->task_runner()->PostDelayedTask(from_here, task, delay); | 358 message_loop->task_runner()->PostDelayedTask(from_here, task, delay); |
| 357 } else { | 359 } else { |
| 358 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task, | 360 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task, |
| 359 delay); | 361 delay); |
| 360 } | 362 } |
| 361 } | 363 } |
| 362 | 364 |
| 363 if (!target_thread_outlives_current) | 365 if (!target_thread_outlives_current) |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 400 task); | 402 task); |
| 401 } | 403 } |
| 402 | 404 |
| 403 // static | 405 // static |
| 404 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { | 406 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { |
| 405 return g_globals.Get().blocking_pool.get(); | 407 return g_globals.Get().blocking_pool.get(); |
| 406 } | 408 } |
| 407 | 409 |
| 408 // static | 410 // static |
| 409 bool BrowserThread::IsThreadInitialized(ID identifier) { | 411 bool BrowserThread::IsThreadInitialized(ID identifier) { |
| 410 if (g_globals == NULL) | 412 if (g_globals == nullptr) |
| 411 return false; | 413 return false; |
| 412 | 414 |
| 413 BrowserThreadGlobals& globals = g_globals.Get(); | 415 BrowserThreadGlobals& globals = g_globals.Get(); |
| 414 base::AutoLock lock(globals.lock); | 416 base::AutoLock lock(globals.lock); |
| 415 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 417 DCHECK(identifier >= 0); |
| 416 return globals.threads[identifier] != NULL; | 418 DCHECK(identifier < ID_COUNT); |
| 419 return globals.threads[identifier] != nullptr; | |
| 417 } | 420 } |
| 418 | 421 |
| 419 // static | 422 // static |
| 420 bool BrowserThread::CurrentlyOn(ID identifier) { | 423 bool BrowserThread::CurrentlyOn(ID identifier) { |
| 421 BrowserThreadGlobals& globals = g_globals.Get(); | 424 BrowserThreadGlobals& globals = g_globals.Get(); |
| 422 base::AutoLock lock(globals.lock); | 425 base::AutoLock lock(globals.lock); |
| 423 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 426 DCHECK(identifier >= 0); |
| 427 DCHECK(identifier < ID_COUNT); | |
| 424 return globals.threads[identifier] && | 428 return globals.threads[identifier] && |
| 425 globals.threads[identifier]->message_loop() == | 429 globals.threads[identifier]->message_loop() == |
| 426 base::MessageLoop::current(); | 430 base::MessageLoop::current(); |
| 427 } | 431 } |
| 428 | 432 |
| 429 // static | 433 // static |
| 430 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { | 434 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { |
| 431 std::string actual_name = base::PlatformThread::GetName(); | 435 std::string actual_name = base::PlatformThread::GetName(); |
| 432 if (actual_name.empty()) | 436 if (actual_name.empty()) |
| 433 actual_name = "Unknown Thread"; | 437 actual_name = "Unknown Thread"; |
| 434 | 438 |
| 435 std::string result = "Must be called on "; | 439 std::string result = "Must be called on "; |
| 436 result += GetThreadName(expected); | 440 result += GetThreadName(expected); |
| 437 result += "; actually called on "; | 441 result += "; actually called on "; |
| 438 result += actual_name; | 442 result += actual_name; |
| 439 result += "."; | 443 result += "."; |
| 440 return result; | 444 return result; |
| 441 } | 445 } |
| 442 | 446 |
| 443 // static | 447 // static |
| 444 bool BrowserThread::IsMessageLoopValid(ID identifier) { | 448 bool BrowserThread::IsMessageLoopValid(ID identifier) { |
| 445 if (g_globals == NULL) | 449 if (g_globals == nullptr) |
| 446 return false; | 450 return false; |
| 447 | 451 |
| 448 BrowserThreadGlobals& globals = g_globals.Get(); | 452 BrowserThreadGlobals& globals = g_globals.Get(); |
| 449 base::AutoLock lock(globals.lock); | 453 base::AutoLock lock(globals.lock); |
| 450 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 454 DCHECK(identifier >= 0); |
| 455 DCHECK(identifier < ID_COUNT); | |
| 451 return globals.threads[identifier] && | 456 return globals.threads[identifier] && |
| 452 globals.threads[identifier]->message_loop(); | 457 globals.threads[identifier]->message_loop(); |
| 453 } | 458 } |
| 454 | 459 |
| 455 // static | 460 // static |
| 456 bool BrowserThread::PostTask(ID identifier, | 461 bool BrowserThread::PostTask(ID identifier, |
| 457 const tracked_objects::Location& from_here, | 462 const tracked_objects::Location& from_here, |
| 458 const base::Closure& task) { | 463 const base::Closure& task) { |
| 459 return BrowserThreadImpl::PostTaskHelper( | 464 return BrowserThreadImpl::PostTaskHelper( |
| 460 identifier, from_here, task, base::TimeDelta(), true); | 465 identifier, from_here, task, base::TimeDelta(), true); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 493 ID identifier, | 498 ID identifier, |
| 494 const tracked_objects::Location& from_here, | 499 const tracked_objects::Location& from_here, |
| 495 const base::Closure& task, | 500 const base::Closure& task, |
| 496 const base::Closure& reply) { | 501 const base::Closure& reply) { |
| 497 return GetTaskRunnerForThread(identifier) | 502 return GetTaskRunnerForThread(identifier) |
| 498 ->PostTaskAndReply(from_here, task, reply); | 503 ->PostTaskAndReply(from_here, task, reply); |
| 499 } | 504 } |
| 500 | 505 |
| 501 // static | 506 // static |
| 502 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { | 507 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { |
| 503 if (g_globals == NULL) | 508 if (g_globals == nullptr) |
| 504 return false; | 509 return false; |
| 505 | 510 |
| 506 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); | 511 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); |
| 507 BrowserThreadGlobals& globals = g_globals.Get(); | 512 BrowserThreadGlobals& globals = g_globals.Get(); |
| 508 // Profiler to track potential contention on |globals.lock|. This only does | 513 // Profiler to track potential contention on |globals.lock|. This only does |
| 509 // real work on canary and local dev builds, so the cost of having this here | 514 // real work on canary and local dev builds, so the cost of having this here |
| 510 // should be minimal. | 515 // should be minimal. |
| 511 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); | 516 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); |
| 512 base::AutoLock lock(globals.lock); | 517 base::AutoLock lock(globals.lock); |
| 513 for (int i = 0; i < ID_COUNT; ++i) { | 518 for (int i = 0; i < ID_COUNT; ++i) { |
| 514 if (globals.threads[i] && | 519 if (globals.threads[i] && |
| 515 globals.threads[i]->message_loop() == cur_message_loop) { | 520 globals.threads[i]->message_loop() == cur_message_loop) { |
| 516 *identifier = globals.threads[i]->identifier_; | 521 *identifier = globals.threads[i]->identifier_; |
| 517 return true; | 522 return true; |
| 518 } | 523 } |
| 519 } | 524 } |
| 520 | 525 |
| 521 return false; | 526 return false; |
| 522 } | 527 } |
| 523 | 528 |
| 524 // static | 529 // static |
| 525 scoped_refptr<base::SingleThreadTaskRunner> | 530 scoped_refptr<base::SingleThreadTaskRunner> |
| 526 BrowserThread::GetTaskRunnerForThread(ID identifier) { | 531 BrowserThread::GetTaskRunnerForThread(ID identifier) { |
| 527 return g_task_runners.Get().proxies[identifier]; | 532 return g_task_runners.Get().proxies[identifier]; |
| 528 } | 533 } |
| 529 | 534 |
| 530 // static | 535 // static |
| 531 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { | 536 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { |
| 532 if (g_globals == NULL) | 537 if (g_globals == nullptr) |
| 533 return NULL; | 538 return nullptr; |
| 534 | 539 |
| 535 BrowserThreadGlobals& globals = g_globals.Get(); | 540 BrowserThreadGlobals& globals = g_globals.Get(); |
| 536 base::AutoLock lock(globals.lock); | 541 base::AutoLock lock(globals.lock); |
| 537 base::Thread* thread = globals.threads[identifier]; | 542 base::Thread* thread = globals.threads[identifier]; |
| 538 DCHECK(thread); | 543 DCHECK(thread); |
| 539 base::MessageLoop* loop = thread->message_loop(); | 544 base::MessageLoop* loop = thread->message_loop(); |
| 540 return loop; | 545 return loop; |
| 541 } | 546 } |
| 542 | 547 |
| 543 // static | 548 // static |
| 544 void BrowserThread::SetDelegate(ID identifier, | 549 void BrowserThread::SetDelegate(ID identifier, |
| 545 BrowserThreadDelegate* delegate) { | 550 BrowserThreadDelegate* delegate) { |
| 546 using base::subtle::AtomicWord; | 551 using base::subtle::AtomicWord; |
| 547 BrowserThreadGlobals& globals = g_globals.Get(); | 552 BrowserThreadGlobals& globals = g_globals.Get(); |
| 548 AtomicWord* storage = reinterpret_cast<AtomicWord*>( | 553 AtomicWord* storage = reinterpret_cast<AtomicWord*>( |
| 549 &globals.thread_delegates[identifier]); | 554 &globals.thread_delegates[identifier]); |
| 550 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( | 555 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( |
| 551 storage, reinterpret_cast<AtomicWord>(delegate)); | 556 storage, reinterpret_cast<AtomicWord>(delegate)); |
| 552 | 557 |
| 553 // This catches registration when previously registered. | 558 // This catches registration when previously registered. |
| 554 DCHECK(!delegate || !old_pointer); | 559 DCHECK(!delegate); |
| 560 DCHECK(!old_pointer); | |
|
no sievers
2016/07/21 19:08:01
This is wrong. The current code basically checks t
AKV
2016/07/22 14:26:13
Done. Thanks.
| |
| 555 } | 561 } |
| 556 | 562 |
| 557 } // namespace content | 563 } // namespace content |
| OLD | NEW |