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_GE(identifier_, 0); |
297 DCHECK(globals.threads[identifier_] == NULL); | 297 DCHECK_LT(identifier_, ID_COUNT); |
| 298 DCHECK_EQ(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_GE(identifier, 0); |
| 337 DCHECK_LT(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_GE(identifier, 0); |
416 return globals.threads[identifier] != NULL; | 418 DCHECK_LT(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_GE(identifier, 0); |
| 427 DCHECK_LT(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_GE(identifier, 0); |
| 455 DCHECK_LT(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 || !old_pointer); |
555 } | 560 } |
556 | 561 |
557 } // namespace content | 562 } // namespace content |
OLD | NEW |