• 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 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 {
BrowserThreadGlobalscontent::__anon15a113920111::BrowserThreadGlobals35   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 
BrowserThreadImpl(ID identifier)64 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
65     : Thread(g_browser_thread_names[identifier]),
66       identifier_(identifier) {
67   Initialize();
68 }
69 
BrowserThreadImpl(ID identifier,base::MessageLoop * message_loop)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
ShutdownThreadPool()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
FlushThreadPoolHelper()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 
Init()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 
UIThreadRun(base::MessageLoop * message_loop)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 
DBThreadRun(base::MessageLoop * message_loop)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 
FileThreadRun(base::MessageLoop * message_loop)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 
FileUserBlockingThreadRun(base::MessageLoop * message_loop)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 
ProcessLauncherThreadRun(base::MessageLoop * message_loop)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 
CacheThreadRun(base::MessageLoop * message_loop)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 
IOThreadRun(base::MessageLoop * message_loop)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 
Run(base::MessageLoop * message_loop)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 
CleanUp()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 
Initialize()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 
~BrowserThreadImpl()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
PostTaskHelper(BrowserThread::ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay,bool nestable)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:
BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)281   explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
282       : id_(identifier) {
283   }
284 
285   // MessageLoopProxy implementation.
PostDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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 
PostNonNestableDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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 
RunsTasksOnCurrentThread() const300   virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
301     return BrowserThread::CurrentlyOn(id_);
302   }
303 
304  protected:
~BrowserThreadMessageLoopProxy()305   virtual ~BrowserThreadMessageLoopProxy() {}
306 
307  private:
308   BrowserThread::ID id_;
309   DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
310 };
311 
312 // static
PostBlockingPoolTask(const tracked_objects::Location & from_here,const base::Closure & task)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
PostBlockingPoolTaskAndReply(const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)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
PostBlockingPoolSequencedTask(const std::string & sequence_token_name,const tracked_objects::Location & from_here,const base::Closure & task)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
GetBlockingPool()338 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
339   return g_globals.Get().blocking_pool.get();
340 }
341 
342 // static
IsThreadInitialized(ID identifier)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
CurrentlyOn(ID identifier)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
IsMessageLoopValid(ID identifier)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
PostTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)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
PostDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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
PostNonNestableTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)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
PostNonNestableDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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
PostTaskAndReply(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)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
GetCurrentThreadIdentifier(ID * identifier)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>
GetMessageLoopProxyForThread(ID identifier)452 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
453   return make_scoped_refptr(new BrowserThreadMessageLoopProxy(identifier));
454 }
455 
456 // static
UnsafeGetMessageLoopForThread(ID identifier)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
SetDelegate(ID identifier,BrowserThreadDelegate * delegate)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