| 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/profiler/scoped_tracker.h" | 16 #include "base/profiler/scoped_tracker.h" |
| 17 #include "base/single_thread_task_runner.h" | 17 #include "base/single_thread_task_runner.h" |
| 18 #include "base/synchronization/read_write_lock.h" |
| 18 #include "base/threading/sequenced_worker_pool.h" | 19 #include "base/threading/sequenced_worker_pool.h" |
| 19 #include "build/build_config.h" | 20 #include "build/build_config.h" |
| 20 #include "content/public/browser/browser_thread_delegate.h" | 21 #include "content/public/browser/browser_thread_delegate.h" |
| 21 #include "content/public/browser/content_browser_client.h" | 22 #include "content/public/browser/content_browser_client.h" |
| 22 #include "net/disk_cache/simple/simple_backend_impl.h" | 23 #include "net/disk_cache/simple/simple_backend_impl.h" |
| 23 | 24 |
| 24 #if defined(OS_ANDROID) | 25 #if defined(OS_ANDROID) |
| 25 #include "base/android/jni_android.h" | 26 #include "base/android/jni_android.h" |
| 26 #endif | 27 #endif |
| 27 | 28 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 struct BrowserThreadGlobals { | 93 struct BrowserThreadGlobals { |
| 93 BrowserThreadGlobals() | 94 BrowserThreadGlobals() |
| 94 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) { | 95 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) { |
| 95 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0])); | 96 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0])); |
| 96 memset(thread_delegates, 0, | 97 memset(thread_delegates, 0, |
| 97 BrowserThread::ID_COUNT * sizeof(thread_delegates[0])); | 98 BrowserThread::ID_COUNT * sizeof(thread_delegates[0])); |
| 98 } | 99 } |
| 99 | 100 |
| 100 // This lock protects |threads|. Do not read or modify that array | 101 // This lock protects |threads|. Do not read or modify that array |
| 101 // without holding this lock. Do not block while holding this lock. | 102 // without holding this lock. Do not block while holding this lock. |
| 102 base::Lock lock; | 103 base::ReadWriteLock lock; |
| 103 | 104 |
| 104 // This array is protected by |lock|. The threads are not owned by this | 105 // This array is protected by |lock|. The threads are not owned by this |
| 105 // array. Typically, the threads are owned on the UI thread by | 106 // array. Typically, the threads are owned on the UI thread by |
| 106 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this | 107 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this |
| 107 // array upon destruction. | 108 // array upon destruction. |
| 108 BrowserThreadImpl* threads[BrowserThread::ID_COUNT]; | 109 BrowserThreadImpl* threads[BrowserThread::ID_COUNT]; |
| 109 | 110 |
| 110 // Only atomic operations are used on this array. The delegates are not owned | 111 // Only atomic operations are used on this array. The delegates are not owned |
| 111 // by this array, rather by whoever calls BrowserThread::SetDelegate. | 112 // by this array, rather by whoever calls BrowserThread::SetDelegate. |
| 112 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; | 113 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 BrowserThreadDelegate* delegate = | 270 BrowserThreadDelegate* delegate = |
| 270 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); | 271 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); |
| 271 | 272 |
| 272 if (delegate) | 273 if (delegate) |
| 273 delegate->CleanUp(); | 274 delegate->CleanUp(); |
| 274 | 275 |
| 275 // PostTaskHelper() accesses the message loop while holding this lock. | 276 // PostTaskHelper() accesses the message loop while holding this lock. |
| 276 // However, the message loop will soon be destructed without any locking. So | 277 // 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 // to prevent a race with accessing the message loop in PostTaskHelper(), |
| 278 // remove this thread from the global array now. | 279 // remove this thread from the global array now. |
| 279 base::AutoLock lock(globals.lock); | 280 base::AutoWriteLock lock(globals.lock); |
| 280 globals.threads[identifier_] = NULL; | 281 globals.threads[identifier_] = NULL; |
| 281 } | 282 } |
| 282 | 283 |
| 283 void BrowserThreadImpl::Initialize() { | 284 void BrowserThreadImpl::Initialize() { |
| 284 BrowserThreadGlobals& globals = g_globals.Get(); | 285 BrowserThreadGlobals& globals = g_globals.Get(); |
| 285 | 286 |
| 286 base::AutoLock lock(globals.lock); | 287 base::AutoWriteLock lock(globals.lock); |
| 287 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); | 288 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); |
| 288 DCHECK(globals.threads[identifier_] == NULL); | 289 DCHECK(globals.threads[identifier_] == NULL); |
| 289 globals.threads[identifier_] = this; | 290 globals.threads[identifier_] = this; |
| 290 } | 291 } |
| 291 | 292 |
| 292 BrowserThreadImpl::~BrowserThreadImpl() { | 293 BrowserThreadImpl::~BrowserThreadImpl() { |
| 293 // All Thread subclasses must call Stop() in the destructor. This is | 294 // All Thread subclasses must call Stop() in the destructor. This is |
| 294 // doubly important here as various bits of code check they are on | 295 // doubly important here as various bits of code check they are on |
| 295 // the right BrowserThread. | 296 // the right BrowserThread. |
| 296 Stop(); | 297 Stop(); |
| 297 | 298 |
| 298 BrowserThreadGlobals& globals = g_globals.Get(); | 299 BrowserThreadGlobals& globals = g_globals.Get(); |
| 299 base::AutoLock lock(globals.lock); | 300 base::AutoWriteLock lock(globals.lock); |
| 300 globals.threads[identifier_] = NULL; | 301 globals.threads[identifier_] = NULL; |
| 301 #ifndef NDEBUG | 302 #ifndef NDEBUG |
| 302 // Double check that the threads are ordered correctly in the enumeration. | 303 // Double check that the threads are ordered correctly in the enumeration. |
| 303 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { | 304 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { |
| 304 DCHECK(!globals.threads[i]) << | 305 DCHECK(!globals.threads[i]) << |
| 305 "Threads must be listed in the reverse order that they die"; | 306 "Threads must be listed in the reverse order that they die"; |
| 306 } | 307 } |
| 307 #endif | 308 #endif |
| 308 } | 309 } |
| 309 | 310 |
| 310 bool BrowserThreadImpl::StartWithOptions(const Options& options) { | 311 bool BrowserThreadImpl::StartWithOptions(const Options& options) { |
| 311 // The global thread table needs to be locked while a new thread is | 312 // The global thread table needs to be locked while a new thread is |
| 312 // starting, as the new thread can asynchronously start touching the | 313 // starting, as the new thread can asynchronously start touching the |
| 313 // table (and other thread's message_loop). | 314 // table (and other thread's message_loop). |
| 314 BrowserThreadGlobals& globals = g_globals.Get(); | 315 BrowserThreadGlobals& globals = g_globals.Get(); |
| 315 base::AutoLock lock(globals.lock); | 316 base::AutoWriteLock lock(globals.lock); |
| 316 return Thread::StartWithOptions(options); | 317 return Thread::StartWithOptions(options); |
| 317 } | 318 } |
| 318 | 319 |
| 319 // static | 320 // static |
| 320 bool BrowserThreadImpl::PostTaskHelper( | 321 bool BrowserThreadImpl::PostTaskHelper( |
| 321 BrowserThread::ID identifier, | 322 BrowserThread::ID identifier, |
| 322 const tracked_objects::Location& from_here, | 323 const tracked_objects::Location& from_here, |
| 323 const base::Closure& task, | 324 const base::Closure& task, |
| 324 base::TimeDelta delay, | 325 base::TimeDelta delay, |
| 325 bool nestable) { | 326 bool nestable) { |
| 326 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 327 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 327 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in | 328 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in |
| 328 // order of lifetime. So no need to lock if we know that the target thread | 329 // order of lifetime. So no need to lock if we know that the target thread |
| 329 // outlives current thread. | 330 // outlives current thread. |
| 330 // Note: since the array is so small, ok to loop instead of creating a map, | 331 // Note: since the array is so small, ok to loop instead of creating a map, |
| 331 // which would require a lock because std::map isn't thread safe, defeating | 332 // which would require a lock because std::map isn't thread safe, defeating |
| 332 // the whole purpose of this optimization. | 333 // the whole purpose of this optimization. |
| 333 BrowserThread::ID current_thread = ID_COUNT; | 334 BrowserThread::ID current_thread = ID_COUNT; |
| 334 bool target_thread_outlives_current = | 335 bool target_thread_outlives_current = |
| 335 GetCurrentThreadIdentifier(¤t_thread) && | 336 GetCurrentThreadIdentifier(¤t_thread) && |
| 336 current_thread >= identifier; | 337 current_thread >= identifier; |
| 337 | 338 |
| 338 BrowserThreadGlobals& globals = g_globals.Get(); | 339 BrowserThreadGlobals& globals = g_globals.Get(); |
| 339 if (!target_thread_outlives_current) | 340 if (!target_thread_outlives_current) |
| 340 globals.lock.Acquire(); | 341 globals.lock.ReadAcquire(); |
| 341 | 342 |
| 342 base::MessageLoop* message_loop = | 343 base::MessageLoop* message_loop = |
| 343 globals.threads[identifier] ? globals.threads[identifier]->message_loop() | 344 globals.threads[identifier] ? globals.threads[identifier]->message_loop() |
| 344 : NULL; | 345 : NULL; |
| 345 if (message_loop) { | 346 if (message_loop) { |
| 346 if (nestable) { | 347 if (nestable) { |
| 347 message_loop->task_runner()->PostDelayedTask(from_here, task, delay); | 348 message_loop->task_runner()->PostDelayedTask(from_here, task, delay); |
| 348 } else { | 349 } else { |
| 349 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task, | 350 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task, |
| 350 delay); | 351 delay); |
| 351 } | 352 } |
| 352 } | 353 } |
| 353 | 354 |
| 354 if (!target_thread_outlives_current) | 355 if (!target_thread_outlives_current) |
| 355 globals.lock.Release(); | 356 globals.lock.ReadRelease(); |
| 356 | 357 |
| 357 return !!message_loop; | 358 return !!message_loop; |
| 358 } | 359 } |
| 359 | 360 |
| 360 // static | 361 // static |
| 361 bool BrowserThread::PostBlockingPoolTask( | 362 bool BrowserThread::PostBlockingPoolTask( |
| 362 const tracked_objects::Location& from_here, | 363 const tracked_objects::Location& from_here, |
| 363 const base::Closure& task) { | 364 const base::Closure& task) { |
| 364 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task); | 365 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task); |
| 365 } | 366 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 395 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { | 396 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { |
| 396 return g_globals.Get().blocking_pool.get(); | 397 return g_globals.Get().blocking_pool.get(); |
| 397 } | 398 } |
| 398 | 399 |
| 399 // static | 400 // static |
| 400 bool BrowserThread::IsThreadInitialized(ID identifier) { | 401 bool BrowserThread::IsThreadInitialized(ID identifier) { |
| 401 if (g_globals == NULL) | 402 if (g_globals == NULL) |
| 402 return false; | 403 return false; |
| 403 | 404 |
| 404 BrowserThreadGlobals& globals = g_globals.Get(); | 405 BrowserThreadGlobals& globals = g_globals.Get(); |
| 405 base::AutoLock lock(globals.lock); | 406 base::AutoReadLock lock(globals.lock); |
| 406 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 407 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 407 return globals.threads[identifier] != NULL; | 408 return globals.threads[identifier] != NULL; |
| 408 } | 409 } |
| 409 | 410 |
| 410 // static | 411 // static |
| 411 bool BrowserThread::CurrentlyOn(ID identifier) { | 412 bool BrowserThread::CurrentlyOn(ID identifier) { |
| 412 BrowserThreadGlobals& globals = g_globals.Get(); | 413 BrowserThreadGlobals& globals = g_globals.Get(); |
| 413 base::AutoLock lock(globals.lock); | 414 base::AutoReadLock lock(globals.lock); |
| 414 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 415 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 415 return globals.threads[identifier] && | 416 return globals.threads[identifier] && |
| 416 globals.threads[identifier]->message_loop() == | 417 globals.threads[identifier]->message_loop() == |
| 417 base::MessageLoop::current(); | 418 base::MessageLoop::current(); |
| 418 } | 419 } |
| 419 | 420 |
| 420 static const char* GetThreadName(BrowserThread::ID thread) { | 421 static const char* GetThreadName(BrowserThread::ID thread) { |
| 421 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) | 422 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) |
| 422 return g_browser_thread_names[thread]; | 423 return g_browser_thread_names[thread]; |
| 423 if (thread == BrowserThread::UI) | 424 if (thread == BrowserThread::UI) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 442 result += "."; | 443 result += "."; |
| 443 return result; | 444 return result; |
| 444 } | 445 } |
| 445 | 446 |
| 446 // static | 447 // static |
| 447 bool BrowserThread::IsMessageLoopValid(ID identifier) { | 448 bool BrowserThread::IsMessageLoopValid(ID identifier) { |
| 448 if (g_globals == NULL) | 449 if (g_globals == NULL) |
| 449 return false; | 450 return false; |
| 450 | 451 |
| 451 BrowserThreadGlobals& globals = g_globals.Get(); | 452 BrowserThreadGlobals& globals = g_globals.Get(); |
| 452 base::AutoLock lock(globals.lock); | 453 base::AutoReadLock lock(globals.lock); |
| 453 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 454 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 454 return globals.threads[identifier] && | 455 return globals.threads[identifier] && |
| 455 globals.threads[identifier]->message_loop(); | 456 globals.threads[identifier]->message_loop(); |
| 456 } | 457 } |
| 457 | 458 |
| 458 // static | 459 // static |
| 459 bool BrowserThread::PostTask(ID identifier, | 460 bool BrowserThread::PostTask(ID identifier, |
| 460 const tracked_objects::Location& from_here, | 461 const tracked_objects::Location& from_here, |
| 461 const base::Closure& task) { | 462 const base::Closure& task) { |
| 462 return BrowserThreadImpl::PostTaskHelper( | 463 return BrowserThreadImpl::PostTaskHelper( |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { | 507 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { |
| 507 if (g_globals == NULL) | 508 if (g_globals == NULL) |
| 508 return false; | 509 return false; |
| 509 | 510 |
| 510 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); | 511 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); |
| 511 BrowserThreadGlobals& globals = g_globals.Get(); | 512 BrowserThreadGlobals& globals = g_globals.Get(); |
| 512 // Profiler to track potential contention on |globals.lock|. This only does | 513 // 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 // real work on canary and local dev builds, so the cost of having this here |
| 514 // should be minimal. | 515 // should be minimal. |
| 515 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); | 516 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); |
| 516 base::AutoLock lock(globals.lock); | 517 base::AutoReadLock lock(globals.lock); |
| 517 for (int i = 0; i < ID_COUNT; ++i) { | 518 for (int i = 0; i < ID_COUNT; ++i) { |
| 518 if (globals.threads[i] && | 519 if (globals.threads[i] && |
| 519 globals.threads[i]->message_loop() == cur_message_loop) { | 520 globals.threads[i]->message_loop() == cur_message_loop) { |
| 520 *identifier = globals.threads[i]->identifier_; | 521 *identifier = globals.threads[i]->identifier_; |
| 521 return true; | 522 return true; |
| 522 } | 523 } |
| 523 } | 524 } |
| 524 | 525 |
| 525 return false; | 526 return false; |
| 526 } | 527 } |
| 527 | 528 |
| 528 // static | 529 // static |
| 529 scoped_refptr<base::SingleThreadTaskRunner> | 530 scoped_refptr<base::SingleThreadTaskRunner> |
| 530 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { | 531 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { |
| 531 return g_task_runners.Get().proxies[identifier]; | 532 return g_task_runners.Get().proxies[identifier]; |
| 532 } | 533 } |
| 533 | 534 |
| 534 // static | 535 // static |
| 535 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { | 536 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { |
| 536 if (g_globals == NULL) | 537 if (g_globals == NULL) |
| 537 return NULL; | 538 return NULL; |
| 538 | 539 |
| 539 BrowserThreadGlobals& globals = g_globals.Get(); | 540 BrowserThreadGlobals& globals = g_globals.Get(); |
| 540 base::AutoLock lock(globals.lock); | 541 base::AutoReadLock lock(globals.lock); |
| 541 base::Thread* thread = globals.threads[identifier]; | 542 base::Thread* thread = globals.threads[identifier]; |
| 542 DCHECK(thread); | 543 DCHECK(thread); |
| 543 base::MessageLoop* loop = thread->message_loop(); | 544 base::MessageLoop* loop = thread->message_loop(); |
| 544 return loop; | 545 return loop; |
| 545 } | 546 } |
| 546 | 547 |
| 547 // static | 548 // static |
| 548 void BrowserThread::SetDelegate(ID identifier, | 549 void BrowserThread::SetDelegate(ID identifier, |
| 549 BrowserThreadDelegate* delegate) { | 550 BrowserThreadDelegate* delegate) { |
| 550 using base::subtle::AtomicWord; | 551 using base::subtle::AtomicWord; |
| 551 BrowserThreadGlobals& globals = g_globals.Get(); | 552 BrowserThreadGlobals& globals = g_globals.Get(); |
| 552 AtomicWord* storage = reinterpret_cast<AtomicWord*>( | 553 AtomicWord* storage = reinterpret_cast<AtomicWord*>( |
| 553 &globals.thread_delegates[identifier]); | 554 &globals.thread_delegates[identifier]); |
| 554 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( | 555 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( |
| 555 storage, reinterpret_cast<AtomicWord>(delegate)); | 556 storage, reinterpret_cast<AtomicWord>(delegate)); |
| 556 | 557 |
| 557 // This catches registration when previously registered. | 558 // This catches registration when previously registered. |
| 558 DCHECK(!delegate || !old_pointer); | 559 DCHECK(!delegate || !old_pointer); |
| 559 } | 560 } |
| 560 | 561 |
| 561 } // namespace content | 562 } // namespace content |
| OLD | NEW |