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