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