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