• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)42   explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
43       : id_(identifier) {
44   }
45 
46   // MessageLoopProxy implementation.
PostDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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 
PostNonNestableDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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 
RunsTasksOnCurrentThread() const61   virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
62     return BrowserThread::CurrentlyOn(id_);
63   }
64 
65  protected:
~BrowserThreadMessageLoopProxy()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 {
BrowserThreadProxiescontent::__anonbf31eb0c0111::BrowserThreadProxies76   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 {
BrowserThreadGlobalscontent::__anonbf31eb0c0111::BrowserThreadGlobals90   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 
BrowserThreadImpl(ID identifier)119 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
120     : Thread(g_browser_thread_names[identifier]),
121       identifier_(identifier) {
122   Initialize();
123 }
124 
BrowserThreadImpl(ID identifier,base::MessageLoop * message_loop)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
ShutdownThreadPool()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
FlushThreadPoolHelper()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 
Init()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 
UIThreadRun(base::MessageLoop * message_loop)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 
DBThreadRun(base::MessageLoop * message_loop)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 
FileThreadRun(base::MessageLoop * message_loop)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 
FileUserBlockingThreadRun(base::MessageLoop * message_loop)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 
ProcessLauncherThreadRun(base::MessageLoop * message_loop)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 
CacheThreadRun(base::MessageLoop * message_loop)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 
IOThreadRun(base::MessageLoop * message_loop)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 
Run(base::MessageLoop * message_loop)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 
CleanUp()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 
Initialize()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 
~BrowserThreadImpl()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
PostTaskHelper(BrowserThread::ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay,bool nestable)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
PostBlockingPoolTask(const tracked_objects::Location & from_here,const base::Closure & task)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
PostBlockingPoolTaskAndReply(const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)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
PostBlockingPoolSequencedTask(const std::string & sequence_token_name,const tracked_objects::Location & from_here,const base::Closure & task)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
GetBlockingPool()367 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
368   return g_globals.Get().blocking_pool.get();
369 }
370 
371 // static
IsThreadInitialized(ID identifier)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
CurrentlyOn(ID identifier)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 
GetThreadName(BrowserThread::ID thread)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
GetDCheckCurrentlyOnErrorMessage(ID expected)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
IsMessageLoopValid(ID identifier)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
PostTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)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
PostDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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
PostNonNestableTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)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
PostNonNestableDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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
PostTaskAndReply(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)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
GetCurrentThreadIdentifier(ID * identifier)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>
GetMessageLoopProxyForThread(ID identifier)508 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
509   return g_proxies.Get().proxies[identifier];
510 }
511 
512 // static
UnsafeGetMessageLoopForThread(ID identifier)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
SetDelegate(ID identifier,BrowserThreadDelegate * delegate)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