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