browser_thread_impl.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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 23namespace content { 24 25namespace { 26 27// Friendly names for the well-known threads. 28static 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. 40class 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. 75struct 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 86base::LazyInstance<BrowserThreadProxies>::Leaky 87 g_proxies = LAZY_INSTANCE_INITIALIZER; 88 89struct 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 114base::LazyInstance<BrowserThreadGlobals>::Leaky 115 g_globals = LAZY_INSTANCE_INITIALIZER; 116 117} // namespace 118 119BrowserThreadImpl::BrowserThreadImpl(ID identifier) 120 : Thread(g_browser_thread_names[identifier]), 121 identifier_(identifier) { 122 Initialize(); 123} 124 125BrowserThreadImpl::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 133void 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 144void 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 151void 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. 172MSVC_DISABLE_OPTIMIZE() 173MSVC_PUSH_DISABLE_WARNING(4748) 174 175NOINLINE 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 181NOINLINE 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 187NOINLINE 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 194NOINLINE 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 201NOINLINE 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 208NOINLINE 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 215NOINLINE 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 221MSVC_POP_WARNING() 222MSVC_ENABLE_OPTIMIZE(); 223 224void 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 260void 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 274void 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 283BrowserThreadImpl::~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 302bool 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 342bool 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 349bool 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 358bool 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 367base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { 368 return g_globals.Get().blocking_pool.get(); 369} 370 371// static 372bool 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 383bool 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 397static 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 406std::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 425bool 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 437bool 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 445bool 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 454bool 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 463bool 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 473bool 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 484bool 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 507scoped_refptr<base::MessageLoopProxy> 508BrowserThread::GetMessageLoopProxyForThread(ID identifier) { 509 return g_proxies.Get().proxies[identifier]; 510} 511 512// static 513base::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 526void 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