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.
5 #include "content/browser/browser_thread_impl.h"
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"
23 // Friendly names for the well-known threads.
24 static 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
34 struct BrowserThreadGlobals
{
35 BrowserThreadGlobals()
36 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
37 memset(threads
, 0, BrowserThread::ID_COUNT
* sizeof(threads
[0]));
38 memset(thread_delegates
, 0,
39 BrowserThread::ID_COUNT
* sizeof(thread_delegates
[0]));
42 // This lock protects |threads|. Do not read or modify that array
43 // without holding this lock. Do not block while holding this lock.
46 // This array is protected by |lock|. The threads are not owned by this
47 // array. Typically, the threads are owned on the UI thread by
48 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
49 // array upon destruction.
50 BrowserThreadImpl
* threads
[BrowserThread::ID_COUNT
];
52 // Only atomic operations are used on this array. The delegates are not owned
53 // by this array, rather by whoever calls BrowserThread::SetDelegate.
54 BrowserThreadDelegate
* thread_delegates
[BrowserThread::ID_COUNT
];
56 const scoped_refptr
<base::SequencedWorkerPool
> blocking_pool
;
59 base::LazyInstance
<BrowserThreadGlobals
>::Leaky
60 g_globals
= LAZY_INSTANCE_INITIALIZER
;
64 BrowserThreadImpl::BrowserThreadImpl(ID identifier
)
65 : Thread(g_browser_thread_names
[identifier
]),
66 identifier_(identifier
) {
70 BrowserThreadImpl::BrowserThreadImpl(ID identifier
,
71 base::MessageLoop
* message_loop
)
72 : Thread(message_loop
->thread_name().c_str()), identifier_(identifier
) {
73 set_message_loop(message_loop
);
78 void BrowserThreadImpl::ShutdownThreadPool() {
79 // The goal is to make it impossible for chrome to 'infinite loop' during
80 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
81 // during shutdown get run. There's nothing particularly scientific about the
83 const int kMaxNewShutdownBlockingTasks
= 1000;
84 BrowserThreadGlobals
& globals
= g_globals
.Get();
85 globals
.blocking_pool
->Shutdown(kMaxNewShutdownBlockingTasks
);
89 void BrowserThreadImpl::FlushThreadPoolHelper() {
90 // We don't want to create a pool if none exists.
91 if (g_globals
== NULL
)
93 g_globals
.Get().blocking_pool
->FlushForTesting();
96 void BrowserThreadImpl::Init() {
97 BrowserThreadGlobals
& globals
= g_globals
.Get();
99 using base::subtle::AtomicWord
;
100 AtomicWord
* storage
=
101 reinterpret_cast<AtomicWord
*>(&globals
.thread_delegates
[identifier_
]);
102 AtomicWord stored_pointer
= base::subtle::NoBarrier_Load(storage
);
103 BrowserThreadDelegate
* delegate
=
104 reinterpret_cast<BrowserThreadDelegate
*>(stored_pointer
);
107 message_loop()->PostTask(FROM_HERE
,
108 base::Bind(&BrowserThreadDelegate::InitAsync
,
109 // Delegate is expected to exist for the
110 // duration of the thread's lifetime
111 base::Unretained(delegate
)));
115 // We disable optimizations for this block of functions so the compiler doesn't
116 // merge them all together.
117 MSVC_DISABLE_OPTIMIZE()
118 MSVC_PUSH_DISABLE_WARNING(4748)
120 NOINLINE
void BrowserThreadImpl::UIThreadRun(base::MessageLoop
* message_loop
) {
121 volatile int line_number
= __LINE__
;
122 Thread::Run(message_loop
);
123 CHECK_GT(line_number
, 0);
126 NOINLINE
void BrowserThreadImpl::DBThreadRun(base::MessageLoop
* message_loop
) {
127 volatile int line_number
= __LINE__
;
128 Thread::Run(message_loop
);
129 CHECK_GT(line_number
, 0);
132 NOINLINE
void BrowserThreadImpl::FileThreadRun(
133 base::MessageLoop
* message_loop
) {
134 volatile int line_number
= __LINE__
;
135 Thread::Run(message_loop
);
136 CHECK_GT(line_number
, 0);
139 NOINLINE
void BrowserThreadImpl::FileUserBlockingThreadRun(
140 base::MessageLoop
* message_loop
) {
141 volatile int line_number
= __LINE__
;
142 Thread::Run(message_loop
);
143 CHECK_GT(line_number
, 0);
146 NOINLINE
void BrowserThreadImpl::ProcessLauncherThreadRun(
147 base::MessageLoop
* message_loop
) {
148 volatile int line_number
= __LINE__
;
149 Thread::Run(message_loop
);
150 CHECK_GT(line_number
, 0);
153 NOINLINE
void BrowserThreadImpl::CacheThreadRun(
154 base::MessageLoop
* message_loop
) {
155 volatile int line_number
= __LINE__
;
156 Thread::Run(message_loop
);
157 CHECK_GT(line_number
, 0);
160 NOINLINE
void BrowserThreadImpl::IOThreadRun(base::MessageLoop
* message_loop
) {
161 volatile int line_number
= __LINE__
;
162 Thread::Run(message_loop
);
163 CHECK_GT(line_number
, 0);
167 MSVC_ENABLE_OPTIMIZE();
169 void BrowserThreadImpl::Run(base::MessageLoop
* message_loop
) {
170 BrowserThread::ID thread_id
= ID_COUNT
;
171 if (!GetCurrentThreadIdentifier(&thread_id
))
172 return Thread::Run(message_loop
);
175 case BrowserThread::UI
:
176 return UIThreadRun(message_loop
);
177 case BrowserThread::DB
:
178 return DBThreadRun(message_loop
);
179 case BrowserThread::FILE:
180 return FileThreadRun(message_loop
);
181 case BrowserThread::FILE_USER_BLOCKING
:
182 return FileUserBlockingThreadRun(message_loop
);
183 case BrowserThread::PROCESS_LAUNCHER
:
184 return ProcessLauncherThreadRun(message_loop
);
185 case BrowserThread::CACHE
:
186 return CacheThreadRun(message_loop
);
187 case BrowserThread::IO
:
188 return IOThreadRun(message_loop
);
189 case BrowserThread::ID_COUNT
:
190 CHECK(false); // This shouldn't actually be reached!
193 Thread::Run(message_loop
);
196 void BrowserThreadImpl::CleanUp() {
197 BrowserThreadGlobals
& globals
= g_globals
.Get();
199 using base::subtle::AtomicWord
;
200 AtomicWord
* storage
=
201 reinterpret_cast<AtomicWord
*>(&globals
.thread_delegates
[identifier_
]);
202 AtomicWord stored_pointer
= base::subtle::NoBarrier_Load(storage
);
203 BrowserThreadDelegate
* delegate
=
204 reinterpret_cast<BrowserThreadDelegate
*>(stored_pointer
);
210 void BrowserThreadImpl::Initialize() {
211 BrowserThreadGlobals
& globals
= g_globals
.Get();
213 base::AutoLock
lock(globals
.lock
);
214 DCHECK(identifier_
>= 0 && identifier_
< ID_COUNT
);
215 DCHECK(globals
.threads
[identifier_
] == NULL
);
216 globals
.threads
[identifier_
] = this;
219 BrowserThreadImpl::~BrowserThreadImpl() {
220 // All Thread subclasses must call Stop() in the destructor. This is
221 // doubly important here as various bits of code check they are on
222 // the right BrowserThread.
225 BrowserThreadGlobals
& globals
= g_globals
.Get();
226 base::AutoLock
lock(globals
.lock
);
227 globals
.threads
[identifier_
] = NULL
;
229 // Double check that the threads are ordered correctly in the enumeration.
230 for (int i
= identifier_
+ 1; i
< ID_COUNT
; ++i
) {
231 DCHECK(!globals
.threads
[i
]) <<
232 "Threads must be listed in the reverse order that they die";
238 bool BrowserThreadImpl::PostTaskHelper(
239 BrowserThread::ID identifier
,
240 const tracked_objects::Location
& from_here
,
241 const base::Closure
& task
,
242 base::TimeDelta delay
,
244 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
245 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
246 // order of lifetime. So no need to lock if we know that the target thread
247 // outlives current thread.
248 // Note: since the array is so small, ok to loop instead of creating a map,
249 // which would require a lock because std::map isn't thread safe, defeating
250 // the whole purpose of this optimization.
251 BrowserThread::ID current_thread
= ID_COUNT
;
252 bool target_thread_outlives_current
=
253 GetCurrentThreadIdentifier(¤t_thread
) &&
254 current_thread
>= identifier
;
256 BrowserThreadGlobals
& globals
= g_globals
.Get();
257 if (!target_thread_outlives_current
)
258 globals
.lock
.Acquire();
260 base::MessageLoop
* message_loop
=
261 globals
.threads
[identifier
] ? globals
.threads
[identifier
]->message_loop()
265 message_loop
->PostDelayedTask(from_here
, task
, delay
);
267 message_loop
->PostNonNestableDelayedTask(from_here
, task
, delay
);
271 if (!target_thread_outlives_current
)
272 globals
.lock
.Release();
274 return !!message_loop
;
277 // An implementation of MessageLoopProxy to be used in conjunction
278 // with BrowserThread.
279 class BrowserThreadMessageLoopProxy
: public base::MessageLoopProxy
{
281 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier
)
285 // MessageLoopProxy implementation.
286 virtual bool PostDelayedTask(
287 const tracked_objects::Location
& from_here
,
288 const base::Closure
& task
, base::TimeDelta delay
) OVERRIDE
{
289 return BrowserThread::PostDelayedTask(id_
, from_here
, task
, delay
);
292 virtual bool PostNonNestableDelayedTask(
293 const tracked_objects::Location
& from_here
,
294 const base::Closure
& task
,
295 base::TimeDelta delay
) OVERRIDE
{
296 return BrowserThread::PostNonNestableDelayedTask(id_
, from_here
, task
,
300 virtual bool RunsTasksOnCurrentThread() const OVERRIDE
{
301 return BrowserThread::CurrentlyOn(id_
);
305 virtual ~BrowserThreadMessageLoopProxy() {}
308 BrowserThread::ID id_
;
309 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy
);
313 bool BrowserThread::PostBlockingPoolTask(
314 const tracked_objects::Location
& from_here
,
315 const base::Closure
& task
) {
316 return g_globals
.Get().blocking_pool
->PostWorkerTask(from_here
, task
);
320 bool 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
);
329 bool 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
);
338 base::SequencedWorkerPool
* BrowserThread::GetBlockingPool() {
339 return g_globals
.Get().blocking_pool
.get();
343 bool BrowserThread::IsThreadInitialized(ID identifier
) {
344 if (g_globals
== NULL
)
347 BrowserThreadGlobals
& globals
= g_globals
.Get();
348 base::AutoLock
lock(globals
.lock
);
349 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
350 return globals
.threads
[identifier
] != NULL
;
354 bool 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
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 base::MessageLoop::current();
368 static const char* GetThreadName(BrowserThread::ID thread
) {
369 if (BrowserThread::UI
< thread
&& thread
< BrowserThread::ID_COUNT
)
370 return g_browser_thread_names
[thread
];
371 if (thread
== BrowserThread::UI
)
372 return "Chrome_UIThread";
373 return "Unknown Thread";
377 std::string
BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected
) {
378 const std::string
& message_loop_name
=
379 base::MessageLoop::current()->thread_name();
380 ID actual_browser_thread
;
381 const char* actual_name
= "Unknown Thread";
382 if (!message_loop_name
.empty()) {
383 actual_name
= message_loop_name
.c_str();
384 } else if (GetCurrentThreadIdentifier(&actual_browser_thread
)) {
385 actual_name
= GetThreadName(actual_browser_thread
);
387 std::string result
= "Must be called on ";
388 result
+= GetThreadName(expected
);
389 result
+= "; actually called on ";
390 result
+= actual_name
;
396 bool BrowserThread::IsMessageLoopValid(ID identifier
) {
397 if (g_globals
== NULL
)
400 BrowserThreadGlobals
& globals
= g_globals
.Get();
401 base::AutoLock
lock(globals
.lock
);
402 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
403 return globals
.threads
[identifier
] &&
404 globals
.threads
[identifier
]->message_loop();
408 bool BrowserThread::PostTask(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(), true);
416 bool BrowserThread::PostDelayedTask(ID identifier
,
417 const tracked_objects::Location
& from_here
,
418 const base::Closure
& task
,
419 base::TimeDelta delay
) {
420 return BrowserThreadImpl::PostTaskHelper(
421 identifier
, from_here
, task
, delay
, true);
425 bool BrowserThread::PostNonNestableTask(
427 const tracked_objects::Location
& from_here
,
428 const base::Closure
& task
) {
429 return BrowserThreadImpl::PostTaskHelper(
430 identifier
, from_here
, task
, base::TimeDelta(), false);
434 bool BrowserThread::PostNonNestableDelayedTask(
436 const tracked_objects::Location
& from_here
,
437 const base::Closure
& task
,
438 base::TimeDelta delay
) {
439 return BrowserThreadImpl::PostTaskHelper(
440 identifier
, from_here
, task
, delay
, false);
444 bool BrowserThread::PostTaskAndReply(
446 const tracked_objects::Location
& from_here
,
447 const base::Closure
& task
,
448 const base::Closure
& reply
) {
449 return GetMessageLoopProxyForThread(identifier
)->PostTaskAndReply(from_here
,
455 bool BrowserThread::GetCurrentThreadIdentifier(ID
* identifier
) {
456 if (g_globals
== NULL
)
459 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
460 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
462 // http://crbug.com/63678
463 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton
;
464 base::MessageLoop
* cur_message_loop
= base::MessageLoop::current();
465 BrowserThreadGlobals
& globals
= g_globals
.Get();
466 for (int i
= 0; i
< ID_COUNT
; ++i
) {
467 if (globals
.threads
[i
] &&
468 globals
.threads
[i
]->message_loop() == cur_message_loop
) {
469 *identifier
= globals
.threads
[i
]->identifier_
;
478 scoped_refptr
<base::MessageLoopProxy
>
479 BrowserThread::GetMessageLoopProxyForThread(ID identifier
) {
480 return make_scoped_refptr(new BrowserThreadMessageLoopProxy(identifier
));
484 base::MessageLoop
* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier
) {
485 if (g_globals
== NULL
)
488 BrowserThreadGlobals
& globals
= g_globals
.Get();
489 base::AutoLock
lock(globals
.lock
);
490 base::Thread
* thread
= globals
.threads
[identifier
];
492 base::MessageLoop
* loop
= thread
->message_loop();
497 void BrowserThread::SetDelegate(ID identifier
,
498 BrowserThreadDelegate
* delegate
) {
499 using base::subtle::AtomicWord
;
500 BrowserThreadGlobals
& globals
= g_globals
.Get();
501 AtomicWord
* storage
= reinterpret_cast<AtomicWord
*>(
502 &globals
.thread_delegates
[identifier
]);
503 AtomicWord old_pointer
= base::subtle::NoBarrier_AtomicExchange(
504 storage
, reinterpret_cast<AtomicWord
>(delegate
));
506 // This catches registration when previously registered.
507 DCHECK(!delegate
|| !old_pointer
);
510 } // namespace content