Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: content/browser/browser_thread_impl.cc

Issue 1989723003: Use a reader-writer lock to protect the threads table in BrowserThreadImpl. Base URL: https://chromium.googlesource.com/chromium/src.git@rw-lock-incoming-task-queue
Patch Set: Rebase Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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(&current_thread) && 336 GetCurrentThreadIdentifier(&current_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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698