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