browser_thread_impl.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.h"
14#include "base/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                                     MessageLoop* message_loop)
73    : Thread(message_loop->thread_name().c_str()),
74      identifier_(identifier) {
75  set_message_loop(message_loop);
76  Initialize();
77}
78
79// static
80void BrowserThreadImpl::ShutdownThreadPool() {
81  // The goal is to make it impossible for chrome to 'infinite loop' during
82  // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
83  // during shutdown get run. There's nothing particularly scientific about the
84  // number chosen.
85  const int kMaxNewShutdownBlockingTasks = 1000;
86  BrowserThreadGlobals& globals = g_globals.Get();
87  globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
88}
89
90// static
91void BrowserThreadImpl::FlushThreadPoolHelper() {
92  // We don't want to create a pool if none exists.
93  if (g_globals == NULL)
94    return;
95  g_globals.Get().blocking_pool->FlushForTesting();
96}
97
98void BrowserThreadImpl::Init() {
99  BrowserThreadGlobals& globals = g_globals.Get();
100
101  using base::subtle::AtomicWord;
102  AtomicWord* storage =
103      reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
104  AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
105  BrowserThreadDelegate* delegate =
106      reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
107  if (delegate)
108    delegate->Init();
109}
110
111// We disable optimizations for this block of functions so the compiler doesn't
112// merge them all together.
113MSVC_DISABLE_OPTIMIZE()
114MSVC_PUSH_DISABLE_WARNING(4748)
115
116NOINLINE void BrowserThreadImpl::UIThreadRun(MessageLoop* message_loop) {
117  volatile int line_number = __LINE__;
118  Thread::Run(message_loop);
119  CHECK_GT(line_number, 0);
120}
121
122NOINLINE void BrowserThreadImpl::DBThreadRun(MessageLoop* message_loop) {
123  volatile int line_number = __LINE__;
124  Thread::Run(message_loop);
125  CHECK_GT(line_number, 0);
126}
127
128NOINLINE void BrowserThreadImpl::WebKitThreadRun(MessageLoop* message_loop) {
129  volatile int line_number = __LINE__;
130  Thread::Run(message_loop);
131  CHECK_GT(line_number, 0);
132}
133
134NOINLINE void BrowserThreadImpl::FileThreadRun(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::FileUserBlockingThreadRun(
141    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::ProcessLauncherThreadRun(
148    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::CacheThreadRun(MessageLoop* message_loop) {
155  volatile int line_number = __LINE__;
156  Thread::Run(message_loop);
157  CHECK_GT(line_number, 0);
158}
159
160NOINLINE void BrowserThreadImpl::IOThreadRun(MessageLoop* message_loop) {
161  volatile int line_number = __LINE__;
162  Thread::Run(message_loop);
163  CHECK_GT(line_number, 0);
164}
165
166MSVC_POP_WARNING()
167MSVC_ENABLE_OPTIMIZE();
168
169void BrowserThreadImpl::Run(MessageLoop* message_loop) {
170  BrowserThread::ID thread_id;
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::WEBKIT_DEPRECATED:
180      return WebKitThreadRun(message_loop);
181    case BrowserThread::FILE:
182      return FileThreadRun(message_loop);
183    case BrowserThread::FILE_USER_BLOCKING:
184      return FileUserBlockingThreadRun(message_loop);
185    case BrowserThread::PROCESS_LAUNCHER:
186      return ProcessLauncherThreadRun(message_loop);
187    case BrowserThread::CACHE:
188      return CacheThreadRun(message_loop);
189    case BrowserThread::IO:
190      return IOThreadRun(message_loop);
191    case BrowserThread::ID_COUNT:
192      CHECK(false);  // This shouldn't actually be reached!
193      break;
194  }
195  Thread::Run(message_loop);
196}
197
198void BrowserThreadImpl::CleanUp() {
199  BrowserThreadGlobals& globals = g_globals.Get();
200
201  using base::subtle::AtomicWord;
202  AtomicWord* storage =
203      reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
204  AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
205  BrowserThreadDelegate* delegate =
206      reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
207
208  if (delegate)
209    delegate->CleanUp();
210}
211
212void BrowserThreadImpl::Initialize() {
213  BrowserThreadGlobals& globals = g_globals.Get();
214
215  base::AutoLock lock(globals.lock);
216  DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
217  DCHECK(globals.threads[identifier_] == NULL);
218  globals.threads[identifier_] = this;
219}
220
221BrowserThreadImpl::~BrowserThreadImpl() {
222  // All Thread subclasses must call Stop() in the destructor. This is
223  // doubly important here as various bits of code check they are on
224  // the right BrowserThread.
225  Stop();
226
227  BrowserThreadGlobals& globals = g_globals.Get();
228  base::AutoLock lock(globals.lock);
229  globals.threads[identifier_] = NULL;
230#ifndef NDEBUG
231  // Double check that the threads are ordered correctly in the enumeration.
232  for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
233    DCHECK(!globals.threads[i]) <<
234        "Threads must be listed in the reverse order that they die";
235  }
236#endif
237}
238
239// static
240bool BrowserThreadImpl::PostTaskHelper(
241    BrowserThread::ID identifier,
242    const tracked_objects::Location& from_here,
243    const base::Closure& task,
244    base::TimeDelta delay,
245    bool nestable) {
246  DCHECK(identifier >= 0 && identifier < ID_COUNT);
247  // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
248  // order of lifetime.  So no need to lock if we know that the target thread
249  // outlives current thread.
250  // Note: since the array is so small, ok to loop instead of creating a map,
251  // which would require a lock because std::map isn't thread safe, defeating
252  // the whole purpose of this optimization.
253  BrowserThread::ID current_thread;
254  bool target_thread_outlives_current =
255      GetCurrentThreadIdentifier(&current_thread) &&
256      current_thread >= identifier;
257
258  BrowserThreadGlobals& globals = g_globals.Get();
259  if (!target_thread_outlives_current)
260    globals.lock.Acquire();
261
262  MessageLoop* message_loop = globals.threads[identifier] ?
263      globals.threads[identifier]->message_loop() : NULL;
264  if (message_loop) {
265    if (nestable) {
266      message_loop->PostDelayedTask(from_here, task, delay);
267    } else {
268      message_loop->PostNonNestableDelayedTask(from_here, task, delay);
269    }
270  }
271
272  if (!target_thread_outlives_current)
273    globals.lock.Release();
274
275  return !!message_loop;
276}
277
278// An implementation of MessageLoopProxy to be used in conjunction
279// with BrowserThread.
280class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
281 public:
282  explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
283      : id_(identifier) {
284  }
285
286  // MessageLoopProxy implementation.
287  virtual bool PostDelayedTask(
288      const tracked_objects::Location& from_here,
289      const base::Closure& task, base::TimeDelta delay) OVERRIDE {
290    return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
291  }
292
293  virtual bool PostNonNestableDelayedTask(
294      const tracked_objects::Location& from_here,
295      const base::Closure& task,
296      base::TimeDelta delay) OVERRIDE {
297    return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
298                                                     delay);
299  }
300
301  virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
302    return BrowserThread::CurrentlyOn(id_);
303  }
304
305 protected:
306  virtual ~BrowserThreadMessageLoopProxy() {}
307
308 private:
309  BrowserThread::ID id_;
310  DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
311};
312
313// static
314bool BrowserThread::PostBlockingPoolTask(
315    const tracked_objects::Location& from_here,
316    const base::Closure& task) {
317  return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
318}
319
320bool 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
329bool 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
338base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
339  return g_globals.Get().blocking_pool;
340}
341
342// static
343bool BrowserThread::IsWellKnownThread(ID identifier) {
344  if (g_globals == NULL)
345    return false;
346
347  BrowserThreadGlobals& globals = g_globals.Get();
348  base::AutoLock lock(globals.lock);
349  return (identifier >= 0 && identifier < ID_COUNT &&
350          globals.threads[identifier]);
351}
352
353// static
354bool 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             MessageLoop::current();
366}
367
368// static
369bool 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
381bool 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
389bool 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
398bool 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
407bool 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
417bool 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
428bool 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  MessageLoop* cur_message_loop = 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
451scoped_refptr<base::MessageLoopProxy>
452BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
453  scoped_refptr<base::MessageLoopProxy> proxy(
454      new BrowserThreadMessageLoopProxy(identifier));
455  return proxy;
456}
457
458// static
459MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
460  if (g_globals == NULL)
461    return NULL;
462
463  BrowserThreadGlobals& globals = g_globals.Get();
464  base::AutoLock lock(globals.lock);
465  base::Thread* thread = globals.threads[identifier];
466  DCHECK(thread);
467  MessageLoop* loop = thread->message_loop();
468  return loop;
469}
470
471// static
472void BrowserThread::SetDelegate(ID identifier,
473                                BrowserThreadDelegate* delegate) {
474  using base::subtle::AtomicWord;
475  BrowserThreadGlobals& globals = g_globals.Get();
476  AtomicWord* storage = reinterpret_cast<AtomicWord*>(
477      &globals.thread_delegates[identifier]);
478  AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
479      storage, reinterpret_cast<AtomicWord>(delegate));
480
481  // This catches registration when previously registered.
482  DCHECK(!delegate || !old_pointer);
483}
484
485}  // namespace content
486