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