browser_thread_impl.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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
19namespace content {
20
21namespace {
22
23// Friendly names for the well-known threads.
24static 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// An implementation of MessageLoopProxy to be used in conjunction
35// with BrowserThread.
36class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
37 public:
38  explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
39      : id_(identifier) {
40  }
41
42  // MessageLoopProxy implementation.
43  virtual bool PostDelayedTask(
44      const tracked_objects::Location& from_here,
45      const base::Closure& task, base::TimeDelta delay) OVERRIDE {
46    return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
47  }
48
49  virtual bool PostNonNestableDelayedTask(
50      const tracked_objects::Location& from_here,
51      const base::Closure& task,
52      base::TimeDelta delay) OVERRIDE {
53    return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
54                                                     delay);
55  }
56
57  virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
58    return BrowserThread::CurrentlyOn(id_);
59  }
60
61 protected:
62  virtual ~BrowserThreadMessageLoopProxy() {}
63
64 private:
65  BrowserThread::ID id_;
66  DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
67};
68
69// A separate helper is used just for the proxies, in order to avoid needing
70// to initialize the globals to create a proxy.
71struct BrowserThreadProxies {
72  BrowserThreadProxies() {
73    for (int i = 0; i < BrowserThread::ID_COUNT; ++i) {
74      proxies[i] =
75          new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID>(i));
76    }
77  }
78
79  scoped_refptr<base::MessageLoopProxy> proxies[BrowserThread::ID_COUNT];
80};
81
82base::LazyInstance<BrowserThreadProxies>::Leaky
83    g_proxies = LAZY_INSTANCE_INITIALIZER;
84
85struct BrowserThreadGlobals {
86  BrowserThreadGlobals()
87      : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
88    memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0]));
89    memset(thread_delegates, 0,
90           BrowserThread::ID_COUNT * sizeof(thread_delegates[0]));
91  }
92
93  // This lock protects |threads|. Do not read or modify that array
94  // without holding this lock. Do not block while holding this lock.
95  base::Lock lock;
96
97  // This array is protected by |lock|. The threads are not owned by this
98  // array. Typically, the threads are owned on the UI thread by
99  // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
100  // array upon destruction.
101  BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
102
103  // Only atomic operations are used on this array. The delegates are not owned
104  // by this array, rather by whoever calls BrowserThread::SetDelegate.
105  BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
106
107  const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
108};
109
110base::LazyInstance<BrowserThreadGlobals>::Leaky
111    g_globals = LAZY_INSTANCE_INITIALIZER;
112
113}  // namespace
114
115BrowserThreadImpl::BrowserThreadImpl(ID identifier)
116    : Thread(g_browser_thread_names[identifier]),
117      identifier_(identifier) {
118  Initialize();
119}
120
121BrowserThreadImpl::BrowserThreadImpl(ID identifier,
122                                     base::MessageLoop* message_loop)
123    : Thread(message_loop->thread_name()), identifier_(identifier) {
124  set_message_loop(message_loop);
125  Initialize();
126}
127
128// static
129void BrowserThreadImpl::ShutdownThreadPool() {
130  // The goal is to make it impossible for chrome to 'infinite loop' during
131  // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
132  // during shutdown get run. There's nothing particularly scientific about the
133  // number chosen.
134  const int kMaxNewShutdownBlockingTasks = 1000;
135  BrowserThreadGlobals& globals = g_globals.Get();
136  globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
137}
138
139// static
140void BrowserThreadImpl::FlushThreadPoolHelper() {
141  // We don't want to create a pool if none exists.
142  if (g_globals == NULL)
143    return;
144  g_globals.Get().blocking_pool->FlushForTesting();
145}
146
147void BrowserThreadImpl::Init() {
148  BrowserThreadGlobals& globals = g_globals.Get();
149
150  using base::subtle::AtomicWord;
151  AtomicWord* storage =
152      reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
153  AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
154  BrowserThreadDelegate* delegate =
155      reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
156  if (delegate) {
157    delegate->Init();
158    message_loop()->PostTask(FROM_HERE,
159                             base::Bind(&BrowserThreadDelegate::InitAsync,
160                                        // Delegate is expected to exist for the
161                                        // duration of the thread's lifetime
162                                        base::Unretained(delegate)));
163  }
164}
165
166// We disable optimizations for this block of functions so the compiler doesn't
167// merge them all together.
168MSVC_DISABLE_OPTIMIZE()
169MSVC_PUSH_DISABLE_WARNING(4748)
170
171NOINLINE void BrowserThreadImpl::UIThreadRun(base::MessageLoop* message_loop) {
172  volatile int line_number = __LINE__;
173  Thread::Run(message_loop);
174  CHECK_GT(line_number, 0);
175}
176
177NOINLINE void BrowserThreadImpl::DBThreadRun(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::FileThreadRun(
184    base::MessageLoop* message_loop) {
185  volatile int line_number = __LINE__;
186  Thread::Run(message_loop);
187  CHECK_GT(line_number, 0);
188}
189
190NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun(
191    base::MessageLoop* message_loop) {
192  volatile int line_number = __LINE__;
193  Thread::Run(message_loop);
194  CHECK_GT(line_number, 0);
195}
196
197NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun(
198    base::MessageLoop* message_loop) {
199  volatile int line_number = __LINE__;
200  Thread::Run(message_loop);
201  CHECK_GT(line_number, 0);
202}
203
204NOINLINE void BrowserThreadImpl::CacheThreadRun(
205    base::MessageLoop* message_loop) {
206  volatile int line_number = __LINE__;
207  Thread::Run(message_loop);
208  CHECK_GT(line_number, 0);
209}
210
211NOINLINE void BrowserThreadImpl::IOThreadRun(base::MessageLoop* message_loop) {
212  volatile int line_number = __LINE__;
213  Thread::Run(message_loop);
214  CHECK_GT(line_number, 0);
215}
216
217MSVC_POP_WARNING()
218MSVC_ENABLE_OPTIMIZE();
219
220void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
221  BrowserThread::ID thread_id = ID_COUNT;
222  if (!GetCurrentThreadIdentifier(&thread_id))
223    return Thread::Run(message_loop);
224
225  switch (thread_id) {
226    case BrowserThread::UI:
227      return UIThreadRun(message_loop);
228    case BrowserThread::DB:
229      return DBThreadRun(message_loop);
230    case BrowserThread::FILE:
231      return FileThreadRun(message_loop);
232    case BrowserThread::FILE_USER_BLOCKING:
233      return FileUserBlockingThreadRun(message_loop);
234    case BrowserThread::PROCESS_LAUNCHER:
235      return ProcessLauncherThreadRun(message_loop);
236    case BrowserThread::CACHE:
237      return CacheThreadRun(message_loop);
238    case BrowserThread::IO:
239      return IOThreadRun(message_loop);
240    case BrowserThread::ID_COUNT:
241      CHECK(false);  // This shouldn't actually be reached!
242      break;
243  }
244  Thread::Run(message_loop);
245}
246
247void BrowserThreadImpl::CleanUp() {
248  BrowserThreadGlobals& globals = g_globals.Get();
249
250  using base::subtle::AtomicWord;
251  AtomicWord* storage =
252      reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
253  AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
254  BrowserThreadDelegate* delegate =
255      reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
256
257  if (delegate)
258    delegate->CleanUp();
259}
260
261void BrowserThreadImpl::Initialize() {
262  BrowserThreadGlobals& globals = g_globals.Get();
263
264  base::AutoLock lock(globals.lock);
265  DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
266  DCHECK(globals.threads[identifier_] == NULL);
267  globals.threads[identifier_] = this;
268}
269
270BrowserThreadImpl::~BrowserThreadImpl() {
271  // All Thread subclasses must call Stop() in the destructor. This is
272  // doubly important here as various bits of code check they are on
273  // the right BrowserThread.
274  Stop();
275
276  BrowserThreadGlobals& globals = g_globals.Get();
277  base::AutoLock lock(globals.lock);
278  globals.threads[identifier_] = NULL;
279#ifndef NDEBUG
280  // Double check that the threads are ordered correctly in the enumeration.
281  for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
282    DCHECK(!globals.threads[i]) <<
283        "Threads must be listed in the reverse order that they die";
284  }
285#endif
286}
287
288// static
289bool BrowserThreadImpl::PostTaskHelper(
290    BrowserThread::ID identifier,
291    const tracked_objects::Location& from_here,
292    const base::Closure& task,
293    base::TimeDelta delay,
294    bool nestable) {
295  DCHECK(identifier >= 0 && identifier < ID_COUNT);
296  // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
297  // order of lifetime.  So no need to lock if we know that the target thread
298  // outlives current thread.
299  // Note: since the array is so small, ok to loop instead of creating a map,
300  // which would require a lock because std::map isn't thread safe, defeating
301  // the whole purpose of this optimization.
302  BrowserThread::ID current_thread = ID_COUNT;
303  bool target_thread_outlives_current =
304      GetCurrentThreadIdentifier(&current_thread) &&
305      current_thread >= identifier;
306
307  BrowserThreadGlobals& globals = g_globals.Get();
308  if (!target_thread_outlives_current)
309    globals.lock.Acquire();
310
311  base::MessageLoop* message_loop =
312      globals.threads[identifier] ? globals.threads[identifier]->message_loop()
313                                  : NULL;
314  if (message_loop) {
315    if (nestable) {
316      message_loop->PostDelayedTask(from_here, task, delay);
317    } else {
318      message_loop->PostNonNestableDelayedTask(from_here, task, delay);
319    }
320  }
321
322  if (!target_thread_outlives_current)
323    globals.lock.Release();
324
325  return !!message_loop;
326}
327
328// static
329bool BrowserThread::PostBlockingPoolTask(
330    const tracked_objects::Location& from_here,
331    const base::Closure& task) {
332  return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
333}
334
335// static
336bool BrowserThread::PostBlockingPoolTaskAndReply(
337    const tracked_objects::Location& from_here,
338    const base::Closure& task,
339    const base::Closure& reply) {
340  return g_globals.Get().blocking_pool->PostTaskAndReply(
341      from_here, task, reply);
342}
343
344// static
345bool BrowserThread::PostBlockingPoolSequencedTask(
346    const std::string& sequence_token_name,
347    const tracked_objects::Location& from_here,
348    const base::Closure& task) {
349  return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
350      sequence_token_name, from_here, task);
351}
352
353// static
354base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
355  return g_globals.Get().blocking_pool.get();
356}
357
358// static
359bool BrowserThread::IsThreadInitialized(ID identifier) {
360  if (g_globals == NULL)
361    return false;
362
363  BrowserThreadGlobals& globals = g_globals.Get();
364  base::AutoLock lock(globals.lock);
365  DCHECK(identifier >= 0 && identifier < ID_COUNT);
366  return globals.threads[identifier] != NULL;
367}
368
369// static
370bool BrowserThread::CurrentlyOn(ID identifier) {
371  // We shouldn't use MessageLoop::current() since it uses LazyInstance which
372  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
373  // function.
374  // http://crbug.com/63678
375  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
376  BrowserThreadGlobals& globals = g_globals.Get();
377  base::AutoLock lock(globals.lock);
378  DCHECK(identifier >= 0 && identifier < ID_COUNT);
379  return globals.threads[identifier] &&
380         globals.threads[identifier]->message_loop() ==
381             base::MessageLoop::current();
382}
383
384static const char* GetThreadName(BrowserThread::ID thread) {
385  if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
386    return g_browser_thread_names[thread];
387  if (thread == BrowserThread::UI)
388    return "Chrome_UIThread";
389  return "Unknown Thread";
390}
391
392// static
393std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
394  const std::string& message_loop_name =
395      base::MessageLoop::current()->thread_name();
396  ID actual_browser_thread;
397  const char* actual_name = "Unknown Thread";
398  if (!message_loop_name.empty()) {
399    actual_name = message_loop_name.c_str();
400  } else if (GetCurrentThreadIdentifier(&actual_browser_thread)) {
401    actual_name = GetThreadName(actual_browser_thread);
402  }
403  std::string result = "Must be called on ";
404  result += GetThreadName(expected);
405  result += "; actually called on ";
406  result += actual_name;
407  result += ".";
408  return result;
409}
410
411// static
412bool BrowserThread::IsMessageLoopValid(ID identifier) {
413  if (g_globals == NULL)
414    return false;
415
416  BrowserThreadGlobals& globals = g_globals.Get();
417  base::AutoLock lock(globals.lock);
418  DCHECK(identifier >= 0 && identifier < ID_COUNT);
419  return globals.threads[identifier] &&
420         globals.threads[identifier]->message_loop();
421}
422
423// static
424bool BrowserThread::PostTask(ID identifier,
425                             const tracked_objects::Location& from_here,
426                             const base::Closure& task) {
427  return BrowserThreadImpl::PostTaskHelper(
428      identifier, from_here, task, base::TimeDelta(), true);
429}
430
431// static
432bool BrowserThread::PostDelayedTask(ID identifier,
433                                    const tracked_objects::Location& from_here,
434                                    const base::Closure& task,
435                                    base::TimeDelta delay) {
436  return BrowserThreadImpl::PostTaskHelper(
437      identifier, from_here, task, delay, true);
438}
439
440// static
441bool BrowserThread::PostNonNestableTask(
442    ID identifier,
443    const tracked_objects::Location& from_here,
444    const base::Closure& task) {
445  return BrowserThreadImpl::PostTaskHelper(
446      identifier, from_here, task, base::TimeDelta(), false);
447}
448
449// static
450bool BrowserThread::PostNonNestableDelayedTask(
451    ID identifier,
452    const tracked_objects::Location& from_here,
453    const base::Closure& task,
454    base::TimeDelta delay) {
455  return BrowserThreadImpl::PostTaskHelper(
456      identifier, from_here, task, delay, false);
457}
458
459// static
460bool BrowserThread::PostTaskAndReply(
461    ID identifier,
462    const tracked_objects::Location& from_here,
463    const base::Closure& task,
464    const base::Closure& reply) {
465  return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
466                                                                    task,
467                                                                    reply);
468}
469
470// static
471bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
472  if (g_globals == NULL)
473    return false;
474
475  // We shouldn't use MessageLoop::current() since it uses LazyInstance which
476  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
477  // function.
478  // http://crbug.com/63678
479  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
480  base::MessageLoop* cur_message_loop = base::MessageLoop::current();
481  BrowserThreadGlobals& globals = g_globals.Get();
482  for (int i = 0; i < ID_COUNT; ++i) {
483    if (globals.threads[i] &&
484        globals.threads[i]->message_loop() == cur_message_loop) {
485      *identifier = globals.threads[i]->identifier_;
486      return true;
487    }
488  }
489
490  return false;
491}
492
493// static
494scoped_refptr<base::MessageLoopProxy>
495BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
496  return g_proxies.Get().proxies[identifier];
497}
498
499// static
500base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
501  if (g_globals == NULL)
502    return NULL;
503
504  BrowserThreadGlobals& globals = g_globals.Get();
505  base::AutoLock lock(globals.lock);
506  base::Thread* thread = globals.threads[identifier];
507  DCHECK(thread);
508  base::MessageLoop* loop = thread->message_loop();
509  return loop;
510}
511
512// static
513void BrowserThread::SetDelegate(ID identifier,
514                                BrowserThreadDelegate* delegate) {
515  using base::subtle::AtomicWord;
516  BrowserThreadGlobals& globals = g_globals.Get();
517  AtomicWord* storage = reinterpret_cast<AtomicWord*>(
518      &globals.thread_delegates[identifier]);
519  AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
520      storage, reinterpret_cast<AtomicWord>(delegate));
521
522  // This catches registration when previously registered.
523  DCHECK(!delegate || !old_pointer);
524}
525
526}  // namespace content
527