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 |