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