browser_thread_impl.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 3// found in the LICENSE file. 4 5#include "content/browser/browser_thread_impl.h" 6 7#include <string> 8 9#include "base/atomicops.h" 10#include "base/bind.h" 11#include "base/compiler_specific.h" 12#include "base/lazy_instance.h" 13#include "base/message_loop/message_loop.h" 14#include "base/message_loop/message_loop_proxy.h" 15#include "base/threading/sequenced_worker_pool.h" 16#include "base/threading/thread_restrictions.h" 17#include "content/public/browser/browser_thread_delegate.h" 18 19namespace content { 20 21namespace { 22 23// Friendly names for the well-known threads. 24static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = { 25 "", // UI (name assembled in browser_main.cc). 26 "Chrome_DBThread", // DB 27 "Chrome_FileThread", // FILE 28 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING 29 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER 30 "Chrome_CacheThread", // CACHE 31 "Chrome_IOThread", // IO 32}; 33 34// An implementation of MessageLoopProxy to be used in conjunction 35// with BrowserThread. 36class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy { 37 public: 38 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier) 39 : id_(identifier) { 40 } 41 42 // MessageLoopProxy implementation. 43 virtual bool PostDelayedTask( 44 const tracked_objects::Location& from_here, 45 const base::Closure& task, base::TimeDelta delay) OVERRIDE { 46 return BrowserThread::PostDelayedTask(id_, from_here, task, delay); 47 } 48 49 virtual bool PostNonNestableDelayedTask( 50 const tracked_objects::Location& from_here, 51 const base::Closure& task, 52 base::TimeDelta delay) OVERRIDE { 53 return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task, 54 delay); 55 } 56 57 virtual bool RunsTasksOnCurrentThread() const OVERRIDE { 58 return BrowserThread::CurrentlyOn(id_); 59 } 60 61 protected: 62 virtual ~BrowserThreadMessageLoopProxy() {} 63 64 private: 65 BrowserThread::ID id_; 66 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy); 67}; 68 69// A separate helper is used just for the proxies, in order to avoid needing 70// to initialize the globals to create a proxy. 71struct BrowserThreadProxies { 72 BrowserThreadProxies() { 73 for (int i = 0; i < BrowserThread::ID_COUNT; ++i) { 74 proxies[i] = 75 new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID>(i)); 76 } 77 } 78 79 scoped_refptr<base::MessageLoopProxy> proxies[BrowserThread::ID_COUNT]; 80}; 81 82base::LazyInstance<BrowserThreadProxies>::Leaky 83 g_proxies = LAZY_INSTANCE_INITIALIZER; 84 85struct BrowserThreadGlobals { 86 BrowserThreadGlobals() 87 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) { 88 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0])); 89 memset(thread_delegates, 0, 90 BrowserThread::ID_COUNT * sizeof(thread_delegates[0])); 91 } 92 93 // This lock protects |threads|. Do not read or modify that array 94 // without holding this lock. Do not block while holding this lock. 95 base::Lock lock; 96 97 // This array is protected by |lock|. The threads are not owned by this 98 // array. Typically, the threads are owned on the UI thread by 99 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this 100 // array upon destruction. 101 BrowserThreadImpl* threads[BrowserThread::ID_COUNT]; 102 103 // Only atomic operations are used on this array. The delegates are not owned 104 // by this array, rather by whoever calls BrowserThread::SetDelegate. 105 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; 106 107 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; 108}; 109 110base::LazyInstance<BrowserThreadGlobals>::Leaky 111 g_globals = LAZY_INSTANCE_INITIALIZER; 112 113} // namespace 114 115BrowserThreadImpl::BrowserThreadImpl(ID identifier) 116 : Thread(g_browser_thread_names[identifier]), 117 identifier_(identifier) { 118 Initialize(); 119} 120 121BrowserThreadImpl::BrowserThreadImpl(ID identifier, 122 base::MessageLoop* message_loop) 123 : Thread(message_loop->thread_name()), identifier_(identifier) { 124 set_message_loop(message_loop); 125 Initialize(); 126} 127 128// static 129void BrowserThreadImpl::ShutdownThreadPool() { 130 // The goal is to make it impossible for chrome to 'infinite loop' during 131 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued 132 // during shutdown get run. There's nothing particularly scientific about the 133 // number chosen. 134 const int kMaxNewShutdownBlockingTasks = 1000; 135 BrowserThreadGlobals& globals = g_globals.Get(); 136 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks); 137} 138 139// static 140void BrowserThreadImpl::FlushThreadPoolHelper() { 141 // We don't want to create a pool if none exists. 142 if (g_globals == NULL) 143 return; 144 g_globals.Get().blocking_pool->FlushForTesting(); 145} 146 147void BrowserThreadImpl::Init() { 148 BrowserThreadGlobals& globals = g_globals.Get(); 149 150 using base::subtle::AtomicWord; 151 AtomicWord* storage = 152 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 153 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 154 BrowserThreadDelegate* delegate = 155 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 156 if (delegate) { 157 delegate->Init(); 158 message_loop()->PostTask(FROM_HERE, 159 base::Bind(&BrowserThreadDelegate::InitAsync, 160 // Delegate is expected to exist for the 161 // duration of the thread's lifetime 162 base::Unretained(delegate))); 163 } 164} 165 166// We disable optimizations for this block of functions so the compiler doesn't 167// merge them all together. 168MSVC_DISABLE_OPTIMIZE() 169MSVC_PUSH_DISABLE_WARNING(4748) 170 171NOINLINE void BrowserThreadImpl::UIThreadRun(base::MessageLoop* message_loop) { 172 volatile int line_number = __LINE__; 173 Thread::Run(message_loop); 174 CHECK_GT(line_number, 0); 175} 176 177NOINLINE void BrowserThreadImpl::DBThreadRun(base::MessageLoop* message_loop) { 178 volatile int line_number = __LINE__; 179 Thread::Run(message_loop); 180 CHECK_GT(line_number, 0); 181} 182 183NOINLINE void BrowserThreadImpl::FileThreadRun( 184 base::MessageLoop* message_loop) { 185 volatile int line_number = __LINE__; 186 Thread::Run(message_loop); 187 CHECK_GT(line_number, 0); 188} 189 190NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun( 191 base::MessageLoop* message_loop) { 192 volatile int line_number = __LINE__; 193 Thread::Run(message_loop); 194 CHECK_GT(line_number, 0); 195} 196 197NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun( 198 base::MessageLoop* message_loop) { 199 volatile int line_number = __LINE__; 200 Thread::Run(message_loop); 201 CHECK_GT(line_number, 0); 202} 203 204NOINLINE void BrowserThreadImpl::CacheThreadRun( 205 base::MessageLoop* message_loop) { 206 volatile int line_number = __LINE__; 207 Thread::Run(message_loop); 208 CHECK_GT(line_number, 0); 209} 210 211NOINLINE void BrowserThreadImpl::IOThreadRun(base::MessageLoop* message_loop) { 212 volatile int line_number = __LINE__; 213 Thread::Run(message_loop); 214 CHECK_GT(line_number, 0); 215} 216 217MSVC_POP_WARNING() 218MSVC_ENABLE_OPTIMIZE(); 219 220void BrowserThreadImpl::Run(base::MessageLoop* message_loop) { 221 BrowserThread::ID thread_id = ID_COUNT; 222 if (!GetCurrentThreadIdentifier(&thread_id)) 223 return Thread::Run(message_loop); 224 225 switch (thread_id) { 226 case BrowserThread::UI: 227 return UIThreadRun(message_loop); 228 case BrowserThread::DB: 229 return DBThreadRun(message_loop); 230 case BrowserThread::FILE: 231 return FileThreadRun(message_loop); 232 case BrowserThread::FILE_USER_BLOCKING: 233 return FileUserBlockingThreadRun(message_loop); 234 case BrowserThread::PROCESS_LAUNCHER: 235 return ProcessLauncherThreadRun(message_loop); 236 case BrowserThread::CACHE: 237 return CacheThreadRun(message_loop); 238 case BrowserThread::IO: 239 return IOThreadRun(message_loop); 240 case BrowserThread::ID_COUNT: 241 CHECK(false); // This shouldn't actually be reached! 242 break; 243 } 244 Thread::Run(message_loop); 245} 246 247void BrowserThreadImpl::CleanUp() { 248 BrowserThreadGlobals& globals = g_globals.Get(); 249 250 using base::subtle::AtomicWord; 251 AtomicWord* storage = 252 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 253 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 254 BrowserThreadDelegate* delegate = 255 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 256 257 if (delegate) 258 delegate->CleanUp(); 259} 260 261void BrowserThreadImpl::Initialize() { 262 BrowserThreadGlobals& globals = g_globals.Get(); 263 264 base::AutoLock lock(globals.lock); 265 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); 266 DCHECK(globals.threads[identifier_] == NULL); 267 globals.threads[identifier_] = this; 268} 269 270BrowserThreadImpl::~BrowserThreadImpl() { 271 // All Thread subclasses must call Stop() in the destructor. This is 272 // doubly important here as various bits of code check they are on 273 // the right BrowserThread. 274 Stop(); 275 276 BrowserThreadGlobals& globals = g_globals.Get(); 277 base::AutoLock lock(globals.lock); 278 globals.threads[identifier_] = NULL; 279#ifndef NDEBUG 280 // Double check that the threads are ordered correctly in the enumeration. 281 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 282 DCHECK(!globals.threads[i]) << 283 "Threads must be listed in the reverse order that they die"; 284 } 285#endif 286} 287 288// static 289bool BrowserThreadImpl::PostTaskHelper( 290 BrowserThread::ID identifier, 291 const tracked_objects::Location& from_here, 292 const base::Closure& task, 293 base::TimeDelta delay, 294 bool nestable) { 295 DCHECK(identifier >= 0 && identifier < ID_COUNT); 296 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in 297 // order of lifetime. So no need to lock if we know that the target thread 298 // outlives current thread. 299 // Note: since the array is so small, ok to loop instead of creating a map, 300 // which would require a lock because std::map isn't thread safe, defeating 301 // the whole purpose of this optimization. 302 BrowserThread::ID current_thread = ID_COUNT; 303 bool target_thread_outlives_current = 304 GetCurrentThreadIdentifier(¤t_thread) && 305 current_thread >= identifier; 306 307 BrowserThreadGlobals& globals = g_globals.Get(); 308 if (!target_thread_outlives_current) 309 globals.lock.Acquire(); 310 311 base::MessageLoop* message_loop = 312 globals.threads[identifier] ? globals.threads[identifier]->message_loop() 313 : NULL; 314 if (message_loop) { 315 if (nestable) { 316 message_loop->PostDelayedTask(from_here, task, delay); 317 } else { 318 message_loop->PostNonNestableDelayedTask(from_here, task, delay); 319 } 320 } 321 322 if (!target_thread_outlives_current) 323 globals.lock.Release(); 324 325 return !!message_loop; 326} 327 328// static 329bool BrowserThread::PostBlockingPoolTask( 330 const tracked_objects::Location& from_here, 331 const base::Closure& task) { 332 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task); 333} 334 335// static 336bool BrowserThread::PostBlockingPoolTaskAndReply( 337 const tracked_objects::Location& from_here, 338 const base::Closure& task, 339 const base::Closure& reply) { 340 return g_globals.Get().blocking_pool->PostTaskAndReply( 341 from_here, task, reply); 342} 343 344// static 345bool BrowserThread::PostBlockingPoolSequencedTask( 346 const std::string& sequence_token_name, 347 const tracked_objects::Location& from_here, 348 const base::Closure& task) { 349 return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask( 350 sequence_token_name, from_here, task); 351} 352 353// static 354base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { 355 return g_globals.Get().blocking_pool.get(); 356} 357 358// static 359bool BrowserThread::IsThreadInitialized(ID identifier) { 360 if (g_globals == NULL) 361 return false; 362 363 BrowserThreadGlobals& globals = g_globals.Get(); 364 base::AutoLock lock(globals.lock); 365 DCHECK(identifier >= 0 && identifier < ID_COUNT); 366 return globals.threads[identifier] != NULL; 367} 368 369// static 370bool BrowserThread::CurrentlyOn(ID identifier) { 371 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 372 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 373 // function. 374 // http://crbug.com/63678 375 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; 376 BrowserThreadGlobals& globals = g_globals.Get(); 377 base::AutoLock lock(globals.lock); 378 DCHECK(identifier >= 0 && identifier < ID_COUNT); 379 return globals.threads[identifier] && 380 globals.threads[identifier]->message_loop() == 381 base::MessageLoop::current(); 382} 383 384static const char* GetThreadName(BrowserThread::ID thread) { 385 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) 386 return g_browser_thread_names[thread]; 387 if (thread == BrowserThread::UI) 388 return "Chrome_UIThread"; 389 return "Unknown Thread"; 390} 391 392// static 393std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { 394 const std::string& message_loop_name = 395 base::MessageLoop::current()->thread_name(); 396 ID actual_browser_thread; 397 const char* actual_name = "Unknown Thread"; 398 if (!message_loop_name.empty()) { 399 actual_name = message_loop_name.c_str(); 400 } else if (GetCurrentThreadIdentifier(&actual_browser_thread)) { 401 actual_name = GetThreadName(actual_browser_thread); 402 } 403 std::string result = "Must be called on "; 404 result += GetThreadName(expected); 405 result += "; actually called on "; 406 result += actual_name; 407 result += "."; 408 return result; 409} 410 411// static 412bool BrowserThread::IsMessageLoopValid(ID identifier) { 413 if (g_globals == NULL) 414 return false; 415 416 BrowserThreadGlobals& globals = g_globals.Get(); 417 base::AutoLock lock(globals.lock); 418 DCHECK(identifier >= 0 && identifier < ID_COUNT); 419 return globals.threads[identifier] && 420 globals.threads[identifier]->message_loop(); 421} 422 423// static 424bool BrowserThread::PostTask(ID identifier, 425 const tracked_objects::Location& from_here, 426 const base::Closure& task) { 427 return BrowserThreadImpl::PostTaskHelper( 428 identifier, from_here, task, base::TimeDelta(), true); 429} 430 431// static 432bool BrowserThread::PostDelayedTask(ID identifier, 433 const tracked_objects::Location& from_here, 434 const base::Closure& task, 435 base::TimeDelta delay) { 436 return BrowserThreadImpl::PostTaskHelper( 437 identifier, from_here, task, delay, true); 438} 439 440// static 441bool BrowserThread::PostNonNestableTask( 442 ID identifier, 443 const tracked_objects::Location& from_here, 444 const base::Closure& task) { 445 return BrowserThreadImpl::PostTaskHelper( 446 identifier, from_here, task, base::TimeDelta(), false); 447} 448 449// static 450bool BrowserThread::PostNonNestableDelayedTask( 451 ID identifier, 452 const tracked_objects::Location& from_here, 453 const base::Closure& task, 454 base::TimeDelta delay) { 455 return BrowserThreadImpl::PostTaskHelper( 456 identifier, from_here, task, delay, false); 457} 458 459// static 460bool BrowserThread::PostTaskAndReply( 461 ID identifier, 462 const tracked_objects::Location& from_here, 463 const base::Closure& task, 464 const base::Closure& reply) { 465 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, 466 task, 467 reply); 468} 469 470// static 471bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 472 if (g_globals == NULL) 473 return false; 474 475 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 476 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 477 // function. 478 // http://crbug.com/63678 479 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; 480 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); 481 BrowserThreadGlobals& globals = g_globals.Get(); 482 for (int i = 0; i < ID_COUNT; ++i) { 483 if (globals.threads[i] && 484 globals.threads[i]->message_loop() == cur_message_loop) { 485 *identifier = globals.threads[i]->identifier_; 486 return true; 487 } 488 } 489 490 return false; 491} 492 493// static 494scoped_refptr<base::MessageLoopProxy> 495BrowserThread::GetMessageLoopProxyForThread(ID identifier) { 496 return g_proxies.Get().proxies[identifier]; 497} 498 499// static 500base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 501 if (g_globals == NULL) 502 return NULL; 503 504 BrowserThreadGlobals& globals = g_globals.Get(); 505 base::AutoLock lock(globals.lock); 506 base::Thread* thread = globals.threads[identifier]; 507 DCHECK(thread); 508 base::MessageLoop* loop = thread->message_loop(); 509 return loop; 510} 511 512// static 513void BrowserThread::SetDelegate(ID identifier, 514 BrowserThreadDelegate* delegate) { 515 using base::subtle::AtomicWord; 516 BrowserThreadGlobals& globals = g_globals.Get(); 517 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 518 &globals.thread_delegates[identifier]); 519 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 520 storage, reinterpret_cast<AtomicWord>(delegate)); 521 522 // This catches registration when previously registered. 523 DCHECK(!delegate || !old_pointer); 524} 525 526} // namespace content 527