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