browser_thread_impl.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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  // content::BrowserMainLoop. BrowserThreadImpl objects remove themselves from
50  // this 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  BrowserThreadGlobals& globals = g_globals.Get();
82  globals.blocking_pool->Shutdown();
83}
84
85void BrowserThreadImpl::Init() {
86  BrowserThreadGlobals& globals = g_globals.Get();
87
88  using base::subtle::AtomicWord;
89  AtomicWord* storage =
90      reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
91  AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
92  BrowserThreadDelegate* delegate =
93      reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
94  if (delegate)
95    delegate->Init();
96}
97
98// We disable optimizations for this block of functions so the compiler doesn't
99// merge them all together.
100MSVC_DISABLE_OPTIMIZE()
101MSVC_PUSH_DISABLE_WARNING(4748)
102
103NOINLINE void BrowserThreadImpl::UIThreadRun(MessageLoop* message_loop) {
104  volatile int line_number = __LINE__;
105  Thread::Run(message_loop);
106  CHECK_GT(line_number, 0);
107}
108
109NOINLINE void BrowserThreadImpl::DBThreadRun(MessageLoop* message_loop) {
110  volatile int line_number = __LINE__;
111  Thread::Run(message_loop);
112  CHECK_GT(line_number, 0);
113}
114
115NOINLINE void BrowserThreadImpl::WebKitThreadRun(MessageLoop* message_loop) {
116  volatile int line_number = __LINE__;
117  Thread::Run(message_loop);
118  CHECK_GT(line_number, 0);
119}
120
121NOINLINE void BrowserThreadImpl::FileThreadRun(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::FileUserBlockingThreadRun(
128    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::ProcessLauncherThreadRun(
135    MessageLoop* message_loop) {
136  volatile int line_number = __LINE__;
137  Thread::Run(message_loop);
138  CHECK_GT(line_number, 0);
139}
140
141NOINLINE void BrowserThreadImpl::CacheThreadRun(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::IOThreadRun(MessageLoop* message_loop) {
148  volatile int line_number = __LINE__;
149  Thread::Run(message_loop);
150  CHECK_GT(line_number, 0);
151}
152
153MSVC_POP_WARNING()
154MSVC_ENABLE_OPTIMIZE();
155
156void BrowserThreadImpl::Run(MessageLoop* message_loop) {
157  BrowserThread::ID thread_id;
158  if (!GetCurrentThreadIdentifier(&thread_id))
159    return Thread::Run(message_loop);
160
161  switch (thread_id) {
162    case BrowserThread::UI:
163      return UIThreadRun(message_loop);
164    case BrowserThread::DB:
165      return DBThreadRun(message_loop);
166    case BrowserThread::WEBKIT_DEPRECATED:
167      return WebKitThreadRun(message_loop);
168    case BrowserThread::FILE:
169      return FileThreadRun(message_loop);
170    case BrowserThread::FILE_USER_BLOCKING:
171      return FileUserBlockingThreadRun(message_loop);
172    case BrowserThread::PROCESS_LAUNCHER:
173      return ProcessLauncherThreadRun(message_loop);
174    case BrowserThread::CACHE:
175      return CacheThreadRun(message_loop);
176    case BrowserThread::IO:
177      return IOThreadRun(message_loop);
178    case BrowserThread::ID_COUNT:
179      CHECK(false);  // This shouldn't actually be reached!
180      break;
181  }
182  Thread::Run(message_loop);
183}
184
185void BrowserThreadImpl::CleanUp() {
186  BrowserThreadGlobals& globals = g_globals.Get();
187
188  using base::subtle::AtomicWord;
189  AtomicWord* storage =
190      reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
191  AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
192  BrowserThreadDelegate* delegate =
193      reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
194
195  if (delegate)
196    delegate->CleanUp();
197}
198
199void BrowserThreadImpl::Initialize() {
200  BrowserThreadGlobals& globals = g_globals.Get();
201
202  base::AutoLock lock(globals.lock);
203  DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
204  DCHECK(globals.threads[identifier_] == NULL);
205  globals.threads[identifier_] = this;
206}
207
208BrowserThreadImpl::~BrowserThreadImpl() {
209  // All Thread subclasses must call Stop() in the destructor. This is
210  // doubly important here as various bits of code check they are on
211  // the right BrowserThread.
212  Stop();
213
214  BrowserThreadGlobals& globals = g_globals.Get();
215  base::AutoLock lock(globals.lock);
216  globals.threads[identifier_] = NULL;
217#ifndef NDEBUG
218  // Double check that the threads are ordered correctly in the enumeration.
219  for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
220    DCHECK(!globals.threads[i]) <<
221        "Threads must be listed in the reverse order that they die";
222  }
223#endif
224}
225
226// static
227bool BrowserThreadImpl::PostTaskHelper(
228    BrowserThread::ID identifier,
229    const tracked_objects::Location& from_here,
230    const base::Closure& task,
231    base::TimeDelta delay,
232    bool nestable) {
233  DCHECK(identifier >= 0 && identifier < ID_COUNT);
234  // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
235  // order of lifetime.  So no need to lock if we know that the target thread
236  // outlives current thread.
237  // Note: since the array is so small, ok to loop instead of creating a map,
238  // which would require a lock because std::map isn't thread safe, defeating
239  // the whole purpose of this optimization.
240  BrowserThread::ID current_thread;
241  bool target_thread_outlives_current =
242      GetCurrentThreadIdentifier(&current_thread) &&
243      current_thread >= identifier;
244
245  BrowserThreadGlobals& globals = g_globals.Get();
246  if (!target_thread_outlives_current)
247    globals.lock.Acquire();
248
249  MessageLoop* message_loop = globals.threads[identifier] ?
250      globals.threads[identifier]->message_loop() : NULL;
251  if (message_loop) {
252    if (nestable) {
253      message_loop->PostDelayedTask(from_here, task, delay);
254    } else {
255      message_loop->PostNonNestableDelayedTask(from_here, task, delay);
256    }
257  }
258
259  if (!target_thread_outlives_current)
260    globals.lock.Release();
261
262  return !!message_loop;
263}
264
265// An implementation of MessageLoopProxy to be used in conjunction
266// with BrowserThread.
267class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
268 public:
269  explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
270      : id_(identifier) {
271  }
272
273  // MessageLoopProxy implementation.
274  virtual bool PostDelayedTask(
275      const tracked_objects::Location& from_here,
276      const base::Closure& task, base::TimeDelta delay) OVERRIDE {
277    return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
278  }
279
280  virtual bool PostNonNestableDelayedTask(
281      const tracked_objects::Location& from_here,
282      const base::Closure& task,
283      base::TimeDelta delay) OVERRIDE {
284    return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
285                                                     delay);
286  }
287
288  virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
289    return BrowserThread::CurrentlyOn(id_);
290  }
291
292 protected:
293  virtual ~BrowserThreadMessageLoopProxy() {}
294
295 private:
296  BrowserThread::ID id_;
297  DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
298};
299
300// static
301bool BrowserThread::PostBlockingPoolTask(
302    const tracked_objects::Location& from_here,
303    const base::Closure& task) {
304  return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
305}
306
307bool BrowserThread::PostBlockingPoolTaskAndReply(
308    const tracked_objects::Location& from_here,
309    const base::Closure& task,
310    const base::Closure& reply) {
311  return g_globals.Get().blocking_pool->PostTaskAndReply(
312      from_here, task, reply);
313}
314
315// static
316bool BrowserThread::PostBlockingPoolSequencedTask(
317    const std::string& sequence_token_name,
318    const tracked_objects::Location& from_here,
319    const base::Closure& task) {
320  return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
321      sequence_token_name, from_here, task);
322}
323
324// static
325base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
326  return g_globals.Get().blocking_pool;
327}
328
329// static
330bool BrowserThread::IsWellKnownThread(ID identifier) {
331  if (g_globals == NULL)
332    return false;
333
334  BrowserThreadGlobals& globals = g_globals.Get();
335  base::AutoLock lock(globals.lock);
336  return (identifier >= 0 && identifier < ID_COUNT &&
337          globals.threads[identifier]);
338}
339
340// static
341bool BrowserThread::CurrentlyOn(ID identifier) {
342  // We shouldn't use MessageLoop::current() since it uses LazyInstance which
343  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
344  // function.
345  // http://crbug.com/63678
346  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
347  BrowserThreadGlobals& globals = g_globals.Get();
348  base::AutoLock lock(globals.lock);
349  DCHECK(identifier >= 0 && identifier < ID_COUNT);
350  return globals.threads[identifier] &&
351         globals.threads[identifier]->message_loop() ==
352             MessageLoop::current();
353}
354
355// static
356bool BrowserThread::IsMessageLoopValid(ID identifier) {
357  if (g_globals == NULL)
358    return false;
359
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}
366
367// static
368bool BrowserThread::PostTask(ID identifier,
369                             const tracked_objects::Location& from_here,
370                             const base::Closure& task) {
371  return BrowserThreadImpl::PostTaskHelper(
372      identifier, from_here, task, base::TimeDelta(), true);
373}
374
375// static
376bool BrowserThread::PostDelayedTask(ID identifier,
377                                    const tracked_objects::Location& from_here,
378                                    const base::Closure& task,
379                                    base::TimeDelta delay) {
380  return BrowserThreadImpl::PostTaskHelper(
381      identifier, from_here, task, delay, true);
382}
383
384// static
385bool BrowserThread::PostNonNestableTask(
386    ID identifier,
387    const tracked_objects::Location& from_here,
388    const base::Closure& task) {
389  return BrowserThreadImpl::PostTaskHelper(
390      identifier, from_here, task, base::TimeDelta(), false);
391}
392
393// static
394bool BrowserThread::PostNonNestableDelayedTask(
395    ID identifier,
396    const tracked_objects::Location& from_here,
397    const base::Closure& task,
398    base::TimeDelta delay) {
399  return BrowserThreadImpl::PostTaskHelper(
400      identifier, from_here, task, delay, false);
401}
402
403// static
404bool BrowserThread::PostTaskAndReply(
405    ID identifier,
406    const tracked_objects::Location& from_here,
407    const base::Closure& task,
408    const base::Closure& reply) {
409  return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
410                                                                    task,
411                                                                    reply);
412}
413
414// static
415bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
416  if (g_globals == NULL)
417    return false;
418
419  // We shouldn't use MessageLoop::current() since it uses LazyInstance which
420  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
421  // function.
422  // http://crbug.com/63678
423  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
424  MessageLoop* cur_message_loop = MessageLoop::current();
425  BrowserThreadGlobals& globals = g_globals.Get();
426  for (int i = 0; i < ID_COUNT; ++i) {
427    if (globals.threads[i] &&
428        globals.threads[i]->message_loop() == cur_message_loop) {
429      *identifier = globals.threads[i]->identifier_;
430      return true;
431    }
432  }
433
434  return false;
435}
436
437// static
438scoped_refptr<base::MessageLoopProxy>
439BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
440  scoped_refptr<base::MessageLoopProxy> proxy(
441      new BrowserThreadMessageLoopProxy(identifier));
442  return proxy;
443}
444
445// static
446MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
447  if (g_globals == NULL)
448    return NULL;
449
450  BrowserThreadGlobals& globals = g_globals.Get();
451  base::AutoLock lock(globals.lock);
452  base::Thread* thread = globals.threads[identifier];
453  DCHECK(thread);
454  MessageLoop* loop = thread->message_loop();
455  return loop;
456}
457
458// static
459void BrowserThread::SetDelegate(ID identifier,
460                                BrowserThreadDelegate* delegate) {
461  using base::subtle::AtomicWord;
462  BrowserThreadGlobals& globals = g_globals.Get();
463  AtomicWord* storage = reinterpret_cast<AtomicWord*>(
464      &globals.thread_delegates[identifier]);
465  AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
466      storage, reinterpret_cast<AtomicWord>(delegate));
467
468  // This catches registration when previously registered.
469  DCHECK(!delegate || !old_pointer);
470}
471
472}  // namespace content
473