Home | History | Annotate | Download | only in browser
      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(&current_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