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