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 #if defined(OS_ANDROID)
     20 #include "base/android/jni_android.h"
     21 #endif
     22 
     23 namespace content {
     24 
     25 namespace {
     26 
     27 // Friendly names for the well-known threads.
     28 static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = {
     29   "",  // UI (name assembled in browser_main.cc).
     30   "Chrome_DBThread",  // DB
     31   "Chrome_FileThread",  // FILE
     32   "Chrome_FileUserBlockingThread",  // FILE_USER_BLOCKING
     33   "Chrome_ProcessLauncherThread",  // PROCESS_LAUNCHER
     34   "Chrome_CacheThread",  // CACHE
     35   "Chrome_IOThread",  // IO
     36 };
     37 
     38 // An implementation of MessageLoopProxy to be used in conjunction
     39 // with BrowserThread.
     40 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
     41  public:
     42   explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
     43       : id_(identifier) {
     44   }
     45 
     46   // MessageLoopProxy implementation.
     47   virtual bool PostDelayedTask(
     48       const tracked_objects::Location& from_here,
     49       const base::Closure& task, base::TimeDelta delay) OVERRIDE {
     50     return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
     51   }
     52 
     53   virtual bool PostNonNestableDelayedTask(
     54       const tracked_objects::Location& from_here,
     55       const base::Closure& task,
     56       base::TimeDelta delay) OVERRIDE {
     57     return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
     58                                                      delay);
     59   }
     60 
     61   virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
     62     return BrowserThread::CurrentlyOn(id_);
     63   }
     64 
     65  protected:
     66   virtual ~BrowserThreadMessageLoopProxy() {}
     67 
     68  private:
     69   BrowserThread::ID id_;
     70   DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
     71 };
     72 
     73 // A separate helper is used just for the proxies, in order to avoid needing
     74 // to initialize the globals to create a proxy.
     75 struct BrowserThreadProxies {
     76   BrowserThreadProxies() {
     77     for (int i = 0; i < BrowserThread::ID_COUNT; ++i) {
     78       proxies[i] =
     79           new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID>(i));
     80     }
     81   }
     82 
     83   scoped_refptr<base::MessageLoopProxy> proxies[BrowserThread::ID_COUNT];
     84 };
     85 
     86 base::LazyInstance<BrowserThreadProxies>::Leaky
     87     g_proxies = LAZY_INSTANCE_INITIALIZER;
     88 
     89 struct BrowserThreadGlobals {
     90   BrowserThreadGlobals()
     91       : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
     92     memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0]));
     93     memset(thread_delegates, 0,
     94            BrowserThread::ID_COUNT * sizeof(thread_delegates[0]));
     95   }
     96 
     97   // This lock protects |threads|. Do not read or modify that array
     98   // without holding this lock. Do not block while holding this lock.
     99   base::Lock lock;
    100 
    101   // This array is protected by |lock|. The threads are not owned by this
    102   // array. Typically, the threads are owned on the UI thread by
    103   // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
    104   // array upon destruction.
    105   BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
    106 
    107   // Only atomic operations are used on this array. The delegates are not owned
    108   // by this array, rather by whoever calls BrowserThread::SetDelegate.
    109   BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
    110 
    111   const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
    112 };
    113 
    114 base::LazyInstance<BrowserThreadGlobals>::Leaky
    115     g_globals = LAZY_INSTANCE_INITIALIZER;
    116 
    117 }  // namespace
    118 
    119 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
    120     : Thread(g_browser_thread_names[identifier]),
    121       identifier_(identifier) {
    122   Initialize();
    123 }
    124 
    125 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
    126                                      base::MessageLoop* message_loop)
    127     : Thread(message_loop->thread_name()), identifier_(identifier) {
    128   set_message_loop(message_loop);
    129   Initialize();
    130 }
    131 
    132 // static
    133 void BrowserThreadImpl::ShutdownThreadPool() {
    134   // The goal is to make it impossible for chrome to 'infinite loop' during
    135   // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
    136   // during shutdown get run. There's nothing particularly scientific about the
    137   // number chosen.
    138   const int kMaxNewShutdownBlockingTasks = 1000;
    139   BrowserThreadGlobals& globals = g_globals.Get();
    140   globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
    141 }
    142 
    143 // static
    144 void BrowserThreadImpl::FlushThreadPoolHelper() {
    145   // We don't want to create a pool if none exists.
    146   if (g_globals == NULL)
    147     return;
    148   g_globals.Get().blocking_pool->FlushForTesting();
    149 }
    150 
    151 void BrowserThreadImpl::Init() {
    152   BrowserThreadGlobals& globals = g_globals.Get();
    153 
    154   using base::subtle::AtomicWord;
    155   AtomicWord* storage =
    156       reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
    157   AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
    158   BrowserThreadDelegate* delegate =
    159       reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
    160   if (delegate) {
    161     delegate->Init();
    162     message_loop()->PostTask(FROM_HERE,
    163                              base::Bind(&BrowserThreadDelegate::InitAsync,
    164                                         // Delegate is expected to exist for the
    165                                         // duration of the thread's lifetime
    166                                         base::Unretained(delegate)));
    167   }
    168 }
    169 
    170 // We disable optimizations for this block of functions so the compiler doesn't
    171 // merge them all together.
    172 MSVC_DISABLE_OPTIMIZE()
    173 MSVC_PUSH_DISABLE_WARNING(4748)
    174 
    175 NOINLINE void BrowserThreadImpl::UIThreadRun(base::MessageLoop* message_loop) {
    176   volatile int line_number = __LINE__;
    177   Thread::Run(message_loop);
    178   CHECK_GT(line_number, 0);
    179 }
    180 
    181 NOINLINE void BrowserThreadImpl::DBThreadRun(base::MessageLoop* message_loop) {
    182   volatile int line_number = __LINE__;
    183   Thread::Run(message_loop);
    184   CHECK_GT(line_number, 0);
    185 }
    186 
    187 NOINLINE void BrowserThreadImpl::FileThreadRun(
    188     base::MessageLoop* message_loop) {
    189   volatile int line_number = __LINE__;
    190   Thread::Run(message_loop);
    191   CHECK_GT(line_number, 0);
    192 }
    193 
    194 NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun(
    195     base::MessageLoop* message_loop) {
    196   volatile int line_number = __LINE__;
    197   Thread::Run(message_loop);
    198   CHECK_GT(line_number, 0);
    199 }
    200 
    201 NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun(
    202     base::MessageLoop* message_loop) {
    203   volatile int line_number = __LINE__;
    204   Thread::Run(message_loop);
    205   CHECK_GT(line_number, 0);
    206 }
    207 
    208 NOINLINE void BrowserThreadImpl::CacheThreadRun(
    209     base::MessageLoop* message_loop) {
    210   volatile int line_number = __LINE__;
    211   Thread::Run(message_loop);
    212   CHECK_GT(line_number, 0);
    213 }
    214 
    215 NOINLINE void BrowserThreadImpl::IOThreadRun(base::MessageLoop* message_loop) {
    216   volatile int line_number = __LINE__;
    217   Thread::Run(message_loop);
    218   CHECK_GT(line_number, 0);
    219 }
    220 
    221 MSVC_POP_WARNING()
    222 MSVC_ENABLE_OPTIMIZE();
    223 
    224 void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
    225 #if defined(OS_ANDROID)
    226   // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
    227   // Though it may create unnecessary VM thread objects, keeping thread name
    228   // gives more benefit in debugging in the platform.
    229   if (!thread_name().empty()) {
    230     base::android::AttachCurrentThreadWithName(thread_name());
    231   }
    232 #endif
    233 
    234   BrowserThread::ID thread_id = ID_COUNT;
    235   if (!GetCurrentThreadIdentifier(&thread_id))
    236     return Thread::Run(message_loop);
    237 
    238   switch (thread_id) {
    239     case BrowserThread::UI:
    240       return UIThreadRun(message_loop);
    241     case BrowserThread::DB:
    242       return DBThreadRun(message_loop);
    243     case BrowserThread::FILE:
    244       return FileThreadRun(message_loop);
    245     case BrowserThread::FILE_USER_BLOCKING:
    246       return FileUserBlockingThreadRun(message_loop);
    247     case BrowserThread::PROCESS_LAUNCHER:
    248       return ProcessLauncherThreadRun(message_loop);
    249     case BrowserThread::CACHE:
    250       return CacheThreadRun(message_loop);
    251     case BrowserThread::IO:
    252       return IOThreadRun(message_loop);
    253     case BrowserThread::ID_COUNT:
    254       CHECK(false);  // This shouldn't actually be reached!
    255       break;
    256   }
    257   Thread::Run(message_loop);
    258 }
    259 
    260 void BrowserThreadImpl::CleanUp() {
    261   BrowserThreadGlobals& globals = g_globals.Get();
    262 
    263   using base::subtle::AtomicWord;
    264   AtomicWord* storage =
    265       reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
    266   AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
    267   BrowserThreadDelegate* delegate =
    268       reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
    269 
    270   if (delegate)
    271     delegate->CleanUp();
    272 }
    273 
    274 void BrowserThreadImpl::Initialize() {
    275   BrowserThreadGlobals& globals = g_globals.Get();
    276 
    277   base::AutoLock lock(globals.lock);
    278   DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
    279   DCHECK(globals.threads[identifier_] == NULL);
    280   globals.threads[identifier_] = this;
    281 }
    282 
    283 BrowserThreadImpl::~BrowserThreadImpl() {
    284   // All Thread subclasses must call Stop() in the destructor. This is
    285   // doubly important here as various bits of code check they are on
    286   // the right BrowserThread.
    287   Stop();
    288 
    289   BrowserThreadGlobals& globals = g_globals.Get();
    290   base::AutoLock lock(globals.lock);
    291   globals.threads[identifier_] = NULL;
    292 #ifndef NDEBUG
    293   // Double check that the threads are ordered correctly in the enumeration.
    294   for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
    295     DCHECK(!globals.threads[i]) <<
    296         "Threads must be listed in the reverse order that they die";
    297   }
    298 #endif
    299 }
    300 
    301 // static
    302 bool BrowserThreadImpl::PostTaskHelper(
    303     BrowserThread::ID identifier,
    304     const tracked_objects::Location& from_here,
    305     const base::Closure& task,
    306     base::TimeDelta delay,
    307     bool nestable) {
    308   DCHECK(identifier >= 0 && identifier < ID_COUNT);
    309   // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
    310   // order of lifetime.  So no need to lock if we know that the target thread
    311   // outlives current thread.
    312   // Note: since the array is so small, ok to loop instead of creating a map,
    313   // which would require a lock because std::map isn't thread safe, defeating
    314   // the whole purpose of this optimization.
    315   BrowserThread::ID current_thread = ID_COUNT;
    316   bool target_thread_outlives_current =
    317       GetCurrentThreadIdentifier(&current_thread) &&
    318       current_thread >= identifier;
    319 
    320   BrowserThreadGlobals& globals = g_globals.Get();
    321   if (!target_thread_outlives_current)
    322     globals.lock.Acquire();
    323 
    324   base::MessageLoop* message_loop =
    325       globals.threads[identifier] ? globals.threads[identifier]->message_loop()
    326                                   : NULL;
    327   if (message_loop) {
    328     if (nestable) {
    329       message_loop->PostDelayedTask(from_here, task, delay);
    330     } else {
    331       message_loop->PostNonNestableDelayedTask(from_here, task, delay);
    332     }
    333   }
    334 
    335   if (!target_thread_outlives_current)
    336     globals.lock.Release();
    337 
    338   return !!message_loop;
    339 }
    340 
    341 // static
    342 bool BrowserThread::PostBlockingPoolTask(
    343     const tracked_objects::Location& from_here,
    344     const base::Closure& task) {
    345   return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
    346 }
    347 
    348 // static
    349 bool BrowserThread::PostBlockingPoolTaskAndReply(
    350     const tracked_objects::Location& from_here,
    351     const base::Closure& task,
    352     const base::Closure& reply) {
    353   return g_globals.Get().blocking_pool->PostTaskAndReply(
    354       from_here, task, reply);
    355 }
    356 
    357 // static
    358 bool BrowserThread::PostBlockingPoolSequencedTask(
    359     const std::string& sequence_token_name,
    360     const tracked_objects::Location& from_here,
    361     const base::Closure& task) {
    362   return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
    363       sequence_token_name, from_here, task);
    364 }
    365 
    366 // static
    367 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
    368   return g_globals.Get().blocking_pool.get();
    369 }
    370 
    371 // static
    372 bool BrowserThread::IsThreadInitialized(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] != NULL;
    380 }
    381 
    382 // static
    383 bool BrowserThread::CurrentlyOn(ID identifier) {
    384   // We shouldn't use MessageLoop::current() since it uses LazyInstance which
    385   // may be deleted by ~AtExitManager when a WorkerPool thread calls this
    386   // function.
    387   // http://crbug.com/63678
    388   base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
    389   BrowserThreadGlobals& globals = g_globals.Get();
    390   base::AutoLock lock(globals.lock);
    391   DCHECK(identifier >= 0 && identifier < ID_COUNT);
    392   return globals.threads[identifier] &&
    393          globals.threads[identifier]->message_loop() ==
    394              base::MessageLoop::current();
    395 }
    396 
    397 static const char* GetThreadName(BrowserThread::ID thread) {
    398   if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
    399     return g_browser_thread_names[thread];
    400   if (thread == BrowserThread::UI)
    401     return "Chrome_UIThread";
    402   return "Unknown Thread";
    403 }
    404 
    405 // static
    406 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
    407   const std::string& message_loop_name =
    408       base::MessageLoop::current()->thread_name();
    409   ID actual_browser_thread;
    410   const char* actual_name = "Unknown Thread";
    411   if (!message_loop_name.empty()) {
    412     actual_name = message_loop_name.c_str();
    413   } else if (GetCurrentThreadIdentifier(&actual_browser_thread)) {
    414     actual_name = GetThreadName(actual_browser_thread);
    415   }
    416   std::string result = "Must be called on ";
    417   result += GetThreadName(expected);
    418   result += "; actually called on ";
    419   result += actual_name;
    420   result += ".";
    421   return result;
    422 }
    423 
    424 // static
    425 bool BrowserThread::IsMessageLoopValid(ID identifier) {
    426   if (g_globals == NULL)
    427     return false;
    428 
    429   BrowserThreadGlobals& globals = g_globals.Get();
    430   base::AutoLock lock(globals.lock);
    431   DCHECK(identifier >= 0 && identifier < ID_COUNT);
    432   return globals.threads[identifier] &&
    433          globals.threads[identifier]->message_loop();
    434 }
    435 
    436 // static
    437 bool BrowserThread::PostTask(ID identifier,
    438                              const tracked_objects::Location& from_here,
    439                              const base::Closure& task) {
    440   return BrowserThreadImpl::PostTaskHelper(
    441       identifier, from_here, task, base::TimeDelta(), true);
    442 }
    443 
    444 // static
    445 bool BrowserThread::PostDelayedTask(ID identifier,
    446                                     const tracked_objects::Location& from_here,
    447                                     const base::Closure& task,
    448                                     base::TimeDelta delay) {
    449   return BrowserThreadImpl::PostTaskHelper(
    450       identifier, from_here, task, delay, true);
    451 }
    452 
    453 // static
    454 bool BrowserThread::PostNonNestableTask(
    455     ID identifier,
    456     const tracked_objects::Location& from_here,
    457     const base::Closure& task) {
    458   return BrowserThreadImpl::PostTaskHelper(
    459       identifier, from_here, task, base::TimeDelta(), false);
    460 }
    461 
    462 // static
    463 bool BrowserThread::PostNonNestableDelayedTask(
    464     ID identifier,
    465     const tracked_objects::Location& from_here,
    466     const base::Closure& task,
    467     base::TimeDelta delay) {
    468   return BrowserThreadImpl::PostTaskHelper(
    469       identifier, from_here, task, delay, false);
    470 }
    471 
    472 // static
    473 bool BrowserThread::PostTaskAndReply(
    474     ID identifier,
    475     const tracked_objects::Location& from_here,
    476     const base::Closure& task,
    477     const base::Closure& reply) {
    478   return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
    479                                                                     task,
    480                                                                     reply);
    481 }
    482 
    483 // static
    484 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
    485   if (g_globals == NULL)
    486     return false;
    487 
    488   // We shouldn't use MessageLoop::current() since it uses LazyInstance which
    489   // may be deleted by ~AtExitManager when a WorkerPool thread calls this
    490   // function.
    491   // http://crbug.com/63678
    492   base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
    493   base::MessageLoop* cur_message_loop = base::MessageLoop::current();
    494   BrowserThreadGlobals& globals = g_globals.Get();
    495   for (int i = 0; i < ID_COUNT; ++i) {
    496     if (globals.threads[i] &&
    497         globals.threads[i]->message_loop() == cur_message_loop) {
    498       *identifier = globals.threads[i]->identifier_;
    499       return true;
    500     }
    501   }
    502 
    503   return false;
    504 }
    505 
    506 // static
    507 scoped_refptr<base::MessageLoopProxy>
    508 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
    509   return g_proxies.Get().proxies[identifier];
    510 }
    511 
    512 // static
    513 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
    514   if (g_globals == NULL)
    515     return NULL;
    516 
    517   BrowserThreadGlobals& globals = g_globals.Get();
    518   base::AutoLock lock(globals.lock);
    519   base::Thread* thread = globals.threads[identifier];
    520   DCHECK(thread);
    521   base::MessageLoop* loop = thread->message_loop();
    522   return loop;
    523 }
    524 
    525 // static
    526 void BrowserThread::SetDelegate(ID identifier,
    527                                 BrowserThreadDelegate* delegate) {
    528   using base::subtle::AtomicWord;
    529   BrowserThreadGlobals& globals = g_globals.Get();
    530   AtomicWord* storage = reinterpret_cast<AtomicWord*>(
    531       &globals.thread_delegates[identifier]);
    532   AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
    533       storage, reinterpret_cast<AtomicWord>(delegate));
    534 
    535   // This catches registration when previously registered.
    536   DCHECK(!delegate || !old_pointer);
    537 }
    538 
    539 }  // namespace content
    540