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 = ID_COUNT; 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 = ID_COUNT; 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 // static 320 bool BrowserThread::PostBlockingPoolTaskAndReply( 321 const tracked_objects::Location& from_here, 322 const base::Closure& task, 323 const base::Closure& reply) { 324 return g_globals.Get().blocking_pool->PostTaskAndReply( 325 from_here, task, reply); 326 } 327 328 // static 329 bool BrowserThread::PostBlockingPoolSequencedTask( 330 const std::string& sequence_token_name, 331 const tracked_objects::Location& from_here, 332 const base::Closure& task) { 333 return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask( 334 sequence_token_name, from_here, task); 335 } 336 337 // static 338 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { 339 return g_globals.Get().blocking_pool.get(); 340 } 341 342 // static 343 bool BrowserThread::IsThreadInitialized(ID identifier) { 344 if (g_globals == NULL) 345 return false; 346 347 BrowserThreadGlobals& globals = g_globals.Get(); 348 base::AutoLock lock(globals.lock); 349 DCHECK(identifier >= 0 && identifier < ID_COUNT); 350 return globals.threads[identifier] != NULL; 351 } 352 353 // static 354 bool BrowserThread::CurrentlyOn(ID identifier) { 355 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 356 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 357 // function. 358 // http://crbug.com/63678 359 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; 360 BrowserThreadGlobals& globals = g_globals.Get(); 361 base::AutoLock lock(globals.lock); 362 DCHECK(identifier >= 0 && identifier < ID_COUNT); 363 return globals.threads[identifier] && 364 globals.threads[identifier]->message_loop() == 365 base::MessageLoop::current(); 366 } 367 368 // static 369 bool BrowserThread::IsMessageLoopValid(ID identifier) { 370 if (g_globals == NULL) 371 return false; 372 373 BrowserThreadGlobals& globals = g_globals.Get(); 374 base::AutoLock lock(globals.lock); 375 DCHECK(identifier >= 0 && identifier < ID_COUNT); 376 return globals.threads[identifier] && 377 globals.threads[identifier]->message_loop(); 378 } 379 380 // static 381 bool BrowserThread::PostTask(ID identifier, 382 const tracked_objects::Location& from_here, 383 const base::Closure& task) { 384 return BrowserThreadImpl::PostTaskHelper( 385 identifier, from_here, task, base::TimeDelta(), true); 386 } 387 388 // static 389 bool BrowserThread::PostDelayedTask(ID identifier, 390 const tracked_objects::Location& from_here, 391 const base::Closure& task, 392 base::TimeDelta delay) { 393 return BrowserThreadImpl::PostTaskHelper( 394 identifier, from_here, task, delay, true); 395 } 396 397 // static 398 bool BrowserThread::PostNonNestableTask( 399 ID identifier, 400 const tracked_objects::Location& from_here, 401 const base::Closure& task) { 402 return BrowserThreadImpl::PostTaskHelper( 403 identifier, from_here, task, base::TimeDelta(), false); 404 } 405 406 // static 407 bool BrowserThread::PostNonNestableDelayedTask( 408 ID identifier, 409 const tracked_objects::Location& from_here, 410 const base::Closure& task, 411 base::TimeDelta delay) { 412 return BrowserThreadImpl::PostTaskHelper( 413 identifier, from_here, task, delay, false); 414 } 415 416 // static 417 bool BrowserThread::PostTaskAndReply( 418 ID identifier, 419 const tracked_objects::Location& from_here, 420 const base::Closure& task, 421 const base::Closure& reply) { 422 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, 423 task, 424 reply); 425 } 426 427 // static 428 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 429 if (g_globals == NULL) 430 return false; 431 432 // We shouldn't use MessageLoop::current() since it uses LazyInstance which 433 // may be deleted by ~AtExitManager when a WorkerPool thread calls this 434 // function. 435 // http://crbug.com/63678 436 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; 437 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); 438 BrowserThreadGlobals& globals = g_globals.Get(); 439 for (int i = 0; i < ID_COUNT; ++i) { 440 if (globals.threads[i] && 441 globals.threads[i]->message_loop() == cur_message_loop) { 442 *identifier = globals.threads[i]->identifier_; 443 return true; 444 } 445 } 446 447 return false; 448 } 449 450 // static 451 scoped_refptr<base::MessageLoopProxy> 452 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { 453 return make_scoped_refptr(new BrowserThreadMessageLoopProxy(identifier)); 454 } 455 456 // static 457 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 458 if (g_globals == NULL) 459 return NULL; 460 461 BrowserThreadGlobals& globals = g_globals.Get(); 462 base::AutoLock lock(globals.lock); 463 base::Thread* thread = globals.threads[identifier]; 464 DCHECK(thread); 465 base::MessageLoop* loop = thread->message_loop(); 466 return loop; 467 } 468 469 // static 470 void BrowserThread::SetDelegate(ID identifier, 471 BrowserThreadDelegate* delegate) { 472 using base::subtle::AtomicWord; 473 BrowserThreadGlobals& globals = g_globals.Get(); 474 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 475 &globals.thread_delegates[identifier]); 476 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 477 storage, reinterpret_cast<AtomicWord>(delegate)); 478 479 // This catches registration when previously registered. 480 DCHECK(!delegate || !old_pointer); 481 } 482 483 } // namespace content 484