browser_thread_impl.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.h" 14#include "base/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 19namespace content { 20 21namespace { 22 23// Friendly names for the well-known threads. 24static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = { 25 "", // UI (name assembled in browser_main.cc). 26 "Chrome_DBThread", // DB 27 "Chrome_WebKitThread", // WEBKIT_DEPRECATED 28 "Chrome_FileThread", // FILE 29 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING 30 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER 31 "Chrome_CacheThread", // CACHE 32 "Chrome_IOThread", // IO 33}; 34 35struct BrowserThreadGlobals { 36 BrowserThreadGlobals() 37 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) { 38 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0])); 39 memset(thread_delegates, 0, 40 BrowserThread::ID_COUNT * sizeof(thread_delegates[0])); 41 } 42 43 // This lock protects |threads|. Do not read or modify that array 44 // without holding this lock. Do not block while holding this lock. 45 base::Lock lock; 46 47 // This array is protected by |lock|. The threads are not owned by this 48 // array. Typically, the threads are owned on the UI thread by 49 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this 50 // array upon destruction. 51 BrowserThreadImpl* threads[BrowserThread::ID_COUNT]; 52 53 // Only atomic operations are used on this array. The delegates are not owned 54 // by this array, rather by whoever calls BrowserThread::SetDelegate. 55 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; 56 57 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; 58}; 59 60base::LazyInstance<BrowserThreadGlobals>::Leaky 61 g_globals = LAZY_INSTANCE_INITIALIZER; 62 63} // namespace 64 65BrowserThreadImpl::BrowserThreadImpl(ID identifier) 66 : Thread(g_browser_thread_names[identifier]), 67 identifier_(identifier) { 68 Initialize(); 69} 70 71BrowserThreadImpl::BrowserThreadImpl(ID identifier, 72 MessageLoop* message_loop) 73 : Thread(message_loop->thread_name().c_str()), 74 identifier_(identifier) { 75 set_message_loop(message_loop); 76 Initialize(); 77} 78 79// static 80void BrowserThreadImpl::ShutdownThreadPool() { 81 // The goal is to make it impossible for chrome to 'infinite loop' during 82 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued 83 // during shutdown get run. There's nothing particularly scientific about the 84 // number chosen. 85 const int kMaxNewShutdownBlockingTasks = 1000; 86 BrowserThreadGlobals& globals = g_globals.Get(); 87 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks); 88} 89 90// static 91void BrowserThreadImpl::FlushThreadPoolHelper() { 92 // We don't want to create a pool if none exists. 93 if (g_globals == NULL) 94 return; 95 g_globals.Get().blocking_pool->FlushForTesting(); 96} 97 98void BrowserThreadImpl::Init() { 99 BrowserThreadGlobals& globals = g_globals.Get(); 100 101 using base::subtle::AtomicWord; 102 AtomicWord* storage = 103 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 104 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 105 BrowserThreadDelegate* delegate = 106 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 107 if (delegate) 108 delegate->Init(); 109} 110 111// We disable optimizations for this block of functions so the compiler doesn't 112// merge them all together. 113MSVC_DISABLE_OPTIMIZE() 114MSVC_PUSH_DISABLE_WARNING(4748) 115 116NOINLINE void BrowserThreadImpl::UIThreadRun(MessageLoop* message_loop) { 117 volatile int line_number = __LINE__; 118 Thread::Run(message_loop); 119 CHECK_GT(line_number, 0); 120} 121 122NOINLINE void BrowserThreadImpl::DBThreadRun(MessageLoop* message_loop) { 123 volatile int line_number = __LINE__; 124 Thread::Run(message_loop); 125 CHECK_GT(line_number, 0); 126} 127 128NOINLINE void BrowserThreadImpl::WebKitThreadRun(MessageLoop* message_loop) { 129 volatile int line_number = __LINE__; 130 Thread::Run(message_loop); 131 CHECK_GT(line_number, 0); 132} 133 134NOINLINE void BrowserThreadImpl::FileThreadRun(MessageLoop* message_loop) { 135 volatile int line_number = __LINE__; 136 Thread::Run(message_loop); 137 CHECK_GT(line_number, 0); 138} 139 140NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun( 141 MessageLoop* message_loop) { 142 volatile int line_number = __LINE__; 143 Thread::Run(message_loop); 144 CHECK_GT(line_number, 0); 145} 146 147NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun( 148 MessageLoop* message_loop) { 149 volatile int line_number = __LINE__; 150 Thread::Run(message_loop); 151 CHECK_GT(line_number, 0); 152} 153 154NOINLINE void BrowserThreadImpl::CacheThreadRun(MessageLoop* message_loop) { 155 volatile int line_number = __LINE__; 156 Thread::Run(message_loop); 157 CHECK_GT(line_number, 0); 158} 159 160NOINLINE void BrowserThreadImpl::IOThreadRun(MessageLoop* message_loop) { 161 volatile int line_number = __LINE__; 162 Thread::Run(message_loop); 163 CHECK_GT(line_number, 0); 164} 165 166MSVC_POP_WARNING() 167MSVC_ENABLE_OPTIMIZE(); 168 169void BrowserThreadImpl::Run(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::WEBKIT_DEPRECATED: 180 return WebKitThreadRun(message_loop); 181 case BrowserThread::FILE: 182 return FileThreadRun(message_loop); 183 case BrowserThread::FILE_USER_BLOCKING: 184 return FileUserBlockingThreadRun(message_loop); 185 case BrowserThread::PROCESS_LAUNCHER: 186 return ProcessLauncherThreadRun(message_loop); 187 case BrowserThread::CACHE: 188 return CacheThreadRun(message_loop); 189 case BrowserThread::IO: 190 return IOThreadRun(message_loop); 191 case BrowserThread::ID_COUNT: 192 CHECK(false); // This shouldn't actually be reached! 193 break; 194 } 195 Thread::Run(message_loop); 196} 197 198void BrowserThreadImpl::CleanUp() { 199 BrowserThreadGlobals& globals = g_globals.Get(); 200 201 using base::subtle::AtomicWord; 202 AtomicWord* storage = 203 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 204 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 205 BrowserThreadDelegate* delegate = 206 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 207 208 if (delegate) 209 delegate->CleanUp(); 210} 211 212void BrowserThreadImpl::Initialize() { 213 BrowserThreadGlobals& globals = g_globals.Get(); 214 215 base::AutoLock lock(globals.lock); 216 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); 217 DCHECK(globals.threads[identifier_] == NULL); 218 globals.threads[identifier_] = this; 219} 220 221BrowserThreadImpl::~BrowserThreadImpl() { 222 // All Thread subclasses must call Stop() in the destructor. This is 223 // doubly important here as various bits of code check they are on 224 // the right BrowserThread. 225 Stop(); 226 227 BrowserThreadGlobals& globals = g_globals.Get(); 228 base::AutoLock lock(globals.lock); 229 globals.threads[identifier_] = NULL; 230#ifndef NDEBUG 231 // Double check that the threads are ordered correctly in the enumeration. 232 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 233 DCHECK(!globals.threads[i]) << 234 "Threads must be listed in the reverse order that they die"; 235 } 236#endif 237} 238 239// static 240bool BrowserThreadImpl::PostTaskHelper( 241 BrowserThread::ID identifier, 242 const tracked_objects::Location& from_here, 243 const base::Closure& task, 244 base::TimeDelta delay, 245 bool nestable) { 246 DCHECK(identifier >= 0 && identifier < ID_COUNT); 247 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in 248 // order of lifetime. So no need to lock if we know that the target thread 249 // outlives current thread. 250 // Note: since the array is so small, ok to loop instead of creating a map, 251 // which would require a lock because std::map isn't thread safe, defeating 252 // the whole purpose of this optimization. 253 BrowserThread::ID current_thread; 254 bool target_thread_outlives_current = 255 GetCurrentThreadIdentifier(¤t_thread) && 256 current_thread >= identifier; 257 258 BrowserThreadGlobals& globals = g_globals.Get(); 259 if (!target_thread_outlives_current) 260 globals.lock.Acquire(); 261 262 MessageLoop* message_loop = globals.threads[identifier] ? 263 globals.threads[identifier]->message_loop() : NULL; 264 if (message_loop) { 265 if (nestable) { 266 message_loop->PostDelayedTask(from_here, task, delay); 267 } else { 268 message_loop->PostNonNestableDelayedTask(from_here, task, delay); 269 } 270 } 271 272 if (!target_thread_outlives_current) 273 globals.lock.Release(); 274 275 return !!message_loop; 276} 277 278// An implementation of MessageLoopProxy to be used in conjunction 279// with BrowserThread. 280class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy { 281 public: 282 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier) 283 : id_(identifier) { 284 } 285 286 // MessageLoopProxy implementation. 287 virtual bool PostDelayedTask( 288 const tracked_objects::Location& from_here, 289 const base::Closure& task, base::TimeDelta delay) OVERRIDE { 290 return BrowserThread::PostDelayedTask(id_, from_here, task, delay); 291 } 292 293 virtual bool PostNonNestableDelayedTask( 294 const tracked_objects::Location& from_here, 295 const base::Closure& task, 296 base::TimeDelta delay) OVERRIDE { 297 return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task, 298 delay); 299 } 300 301 virtual bool RunsTasksOnCurrentThread() const OVERRIDE { 302 return BrowserThread::CurrentlyOn(id_); 303 } 304 305 protected: 306 virtual ~BrowserThreadMessageLoopProxy() {} 307 308 private: 309 BrowserThread::ID id_; 310 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy); 311}; 312 313// static 314bool BrowserThread::PostBlockingPoolTask( 315 const tracked_objects::Location& from_here, 316 const base::Closure& task) { 317 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task); 318} 319 320bool 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 329bool 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 338base::SequencedWorkerPool* BrowserThread::GetBlockingPool() { 339 return g_globals.Get().blocking_pool; 340} 341 342// static 343bool BrowserThread::IsWellKnownThread(ID identifier) { 344 if (g_globals == NULL) 345 return false; 346 347 BrowserThreadGlobals& globals = g_globals.Get(); 348 base::AutoLock lock(globals.lock); 349 return (identifier >= 0 && identifier < ID_COUNT && 350 globals.threads[identifier]); 351} 352 353// static 354bool 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 MessageLoop::current(); 366} 367 368// static 369bool 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 381bool 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 389bool 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 398bool 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 407bool 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 417bool 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 428bool 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 MessageLoop* cur_message_loop = 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 451scoped_refptr<base::MessageLoopProxy> 452BrowserThread::GetMessageLoopProxyForThread(ID identifier) { 453 scoped_refptr<base::MessageLoopProxy> proxy( 454 new BrowserThreadMessageLoopProxy(identifier)); 455 return proxy; 456} 457 458// static 459MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { 460 if (g_globals == NULL) 461 return NULL; 462 463 BrowserThreadGlobals& globals = g_globals.Get(); 464 base::AutoLock lock(globals.lock); 465 base::Thread* thread = globals.threads[identifier]; 466 DCHECK(thread); 467 MessageLoop* loop = thread->message_loop(); 468 return loop; 469} 470 471// static 472void BrowserThread::SetDelegate(ID identifier, 473 BrowserThreadDelegate* delegate) { 474 using base::subtle::AtomicWord; 475 BrowserThreadGlobals& globals = g_globals.Get(); 476 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 477 &globals.thread_delegates[identifier]); 478 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 479 storage, reinterpret_cast<AtomicWord>(delegate)); 480 481 // This catches registration when previously registered. 482 DCHECK(!delegate || !old_pointer); 483} 484 485} // namespace content 486