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
24namespace content {
25
26namespace {
27
28// Friendly names for the well-known threads.
29static 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.
41class 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.
76struct 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
87base::LazyInstance<BrowserThreadProxies>::Leaky
88    g_proxies = LAZY_INSTANCE_INITIALIZER;
89
90struct 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
115base::LazyInstance<BrowserThreadGlobals>::Leaky
116    g_globals = LAZY_INSTANCE_INITIALIZER;
117
118}  // namespace
119
120BrowserThreadImpl::BrowserThreadImpl(ID identifier)
121    : Thread(g_browser_thread_names[identifier]),
122      identifier_(identifier) {
123  Initialize();
124}
125
126BrowserThreadImpl::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
134void 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
145void 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
153void 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.
174MSVC_DISABLE_OPTIMIZE()
175MSVC_PUSH_DISABLE_WARNING(4748)
176
177NOINLINE 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
183NOINLINE 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
189NOINLINE 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
196NOINLINE 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
203NOINLINE 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
210NOINLINE 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
217NOINLINE 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
223MSVC_POP_WARNING()
224MSVC_ENABLE_OPTIMIZE();
225
226void 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
262void 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
276void 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
285BrowserThreadImpl::~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
304bool 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
344bool 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
351bool 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
360bool 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
369base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
370  return g_globals.Get().blocking_pool.get();
371}
372
373// static
374bool 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
385bool 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
399static 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
408std::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
427bool 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
439bool 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
447bool 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
456bool 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
465bool 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
475bool 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
486bool 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
509scoped_refptr<base::MessageLoopProxy>
510BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
511  return g_proxies.Get().proxies[identifier];
512}
513
514// static
515base::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
528void 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