browser_thread_impl.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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
23namespace content {
24
25namespace {
26
27// Friendly names for the well-known threads.
28static 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.
40class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
41 public:
42  explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
43      : id_(identifier) {
44  }
45
46  // MessageLoopProxy implementation.
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
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
61  virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
62    return BrowserThread::CurrentlyOn(id_);
63  }
64
65 protected:
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.
75struct BrowserThreadProxies {
76  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
86base::LazyInstance<BrowserThreadProxies>::Leaky
87    g_proxies = LAZY_INSTANCE_INITIALIZER;
88
89struct BrowserThreadGlobals {
90  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
114base::LazyInstance<BrowserThreadGlobals>::Leaky
115    g_globals = LAZY_INSTANCE_INITIALIZER;
116
117}  // namespace
118
119BrowserThreadImpl::BrowserThreadImpl(ID identifier)
120    : Thread(g_browser_thread_names[identifier]),
121      identifier_(identifier) {
122  Initialize();
123}
124
125BrowserThreadImpl::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
133void 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
144void 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
151void 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.
172MSVC_DISABLE_OPTIMIZE()
173MSVC_PUSH_DISABLE_WARNING(4748)
174
175NOINLINE 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
181NOINLINE 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
187NOINLINE 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
194NOINLINE 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
201NOINLINE 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
208NOINLINE 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
215NOINLINE 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
221MSVC_POP_WARNING()
222MSVC_ENABLE_OPTIMIZE();
223
224void 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
260void 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
274void 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
283BrowserThreadImpl::~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
302bool 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
342bool 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
349bool 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
358bool 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
367base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
368  return g_globals.Get().blocking_pool.get();
369}
370
371// static
372bool 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
383bool 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
397static 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
406std::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
425bool 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
437bool 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
445bool 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
454bool 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
463bool 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
473bool 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
484bool 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
507scoped_refptr<base::MessageLoopProxy>
508BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
509  return g_proxies.Get().proxies[identifier];
510}
511
512// static
513base::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
526void 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