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"
19 #if defined(OS_ANDROID)
20 #include "base/android/jni_android.h"
27 // Friendly names for the well-known threads.
28 static const char* g_browser_thread_names
[BrowserThread::ID_COUNT
] = {
29 "", // UI (name assembled in browser_main.cc).
30 "Chrome_DBThread", // DB
31 "Chrome_FileThread", // FILE
32 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING
33 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER
34 "Chrome_CacheThread", // CACHE
35 "Chrome_IOThread", // IO
38 // An implementation of MessageLoopProxy to be used in conjunction
39 // with BrowserThread.
40 class BrowserThreadMessageLoopProxy
: public base::MessageLoopProxy
{
42 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier
)
46 // MessageLoopProxy implementation.
47 virtual bool PostDelayedTask(
48 const tracked_objects::Location
& from_here
,
49 const base::Closure
& task
, base::TimeDelta delay
) OVERRIDE
{
50 return BrowserThread::PostDelayedTask(id_
, from_here
, task
, delay
);
53 virtual bool PostNonNestableDelayedTask(
54 const tracked_objects::Location
& from_here
,
55 const base::Closure
& task
,
56 base::TimeDelta delay
) OVERRIDE
{
57 return BrowserThread::PostNonNestableDelayedTask(id_
, from_here
, task
,
61 virtual bool RunsTasksOnCurrentThread() const OVERRIDE
{
62 return BrowserThread::CurrentlyOn(id_
);
66 virtual ~BrowserThreadMessageLoopProxy() {}
69 BrowserThread::ID id_
;
70 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy
);
73 // A separate helper is used just for the proxies, in order to avoid needing
74 // to initialize the globals to create a proxy.
75 struct BrowserThreadProxies
{
76 BrowserThreadProxies() {
77 for (int i
= 0; i
< BrowserThread::ID_COUNT
; ++i
) {
79 new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID
>(i
));
83 scoped_refptr
<base::MessageLoopProxy
> proxies
[BrowserThread::ID_COUNT
];
86 base::LazyInstance
<BrowserThreadProxies
>::Leaky
87 g_proxies
= LAZY_INSTANCE_INITIALIZER
;
89 struct BrowserThreadGlobals
{
90 BrowserThreadGlobals()
91 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
92 memset(threads
, 0, BrowserThread::ID_COUNT
* sizeof(threads
[0]));
93 memset(thread_delegates
, 0,
94 BrowserThread::ID_COUNT
* sizeof(thread_delegates
[0]));
97 // This lock protects |threads|. Do not read or modify that array
98 // without holding this lock. Do not block while holding this lock.
101 // This array is protected by |lock|. The threads are not owned by this
102 // array. Typically, the threads are owned on the UI thread by
103 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
104 // array upon destruction.
105 BrowserThreadImpl
* threads
[BrowserThread::ID_COUNT
];
107 // Only atomic operations are used on this array. The delegates are not owned
108 // by this array, rather by whoever calls BrowserThread::SetDelegate.
109 BrowserThreadDelegate
* thread_delegates
[BrowserThread::ID_COUNT
];
111 const scoped_refptr
<base::SequencedWorkerPool
> blocking_pool
;
114 base::LazyInstance
<BrowserThreadGlobals
>::Leaky
115 g_globals
= LAZY_INSTANCE_INITIALIZER
;
119 BrowserThreadImpl::BrowserThreadImpl(ID identifier
)
120 : Thread(g_browser_thread_names
[identifier
]),
121 identifier_(identifier
) {
125 BrowserThreadImpl::BrowserThreadImpl(ID identifier
,
126 base::MessageLoop
* message_loop
)
127 : Thread(message_loop
->thread_name()), identifier_(identifier
) {
128 set_message_loop(message_loop
);
133 void BrowserThreadImpl::ShutdownThreadPool() {
134 // The goal is to make it impossible for chrome to 'infinite loop' during
135 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
136 // during shutdown get run. There's nothing particularly scientific about the
138 const int kMaxNewShutdownBlockingTasks
= 1000;
139 BrowserThreadGlobals
& globals
= g_globals
.Get();
140 globals
.blocking_pool
->Shutdown(kMaxNewShutdownBlockingTasks
);
144 void BrowserThreadImpl::FlushThreadPoolHelper() {
145 // We don't want to create a pool if none exists.
146 if (g_globals
== NULL
)
148 g_globals
.Get().blocking_pool
->FlushForTesting();
151 void BrowserThreadImpl::Init() {
152 BrowserThreadGlobals
& globals
= g_globals
.Get();
154 using base::subtle::AtomicWord
;
155 AtomicWord
* storage
=
156 reinterpret_cast<AtomicWord
*>(&globals
.thread_delegates
[identifier_
]);
157 AtomicWord stored_pointer
= base::subtle::NoBarrier_Load(storage
);
158 BrowserThreadDelegate
* delegate
=
159 reinterpret_cast<BrowserThreadDelegate
*>(stored_pointer
);
162 message_loop()->PostTask(FROM_HERE
,
163 base::Bind(&BrowserThreadDelegate::InitAsync
,
164 // Delegate is expected to exist for the
165 // duration of the thread's lifetime
166 base::Unretained(delegate
)));
170 // We disable optimizations for this block of functions so the compiler doesn't
171 // merge them all together.
172 MSVC_DISABLE_OPTIMIZE()
173 MSVC_PUSH_DISABLE_WARNING(4748)
175 NOINLINE
void BrowserThreadImpl::UIThreadRun(base::MessageLoop
* message_loop
) {
176 volatile int line_number
= __LINE__
;
177 Thread::Run(message_loop
);
178 CHECK_GT(line_number
, 0);
181 NOINLINE
void BrowserThreadImpl::DBThreadRun(base::MessageLoop
* message_loop
) {
182 volatile int line_number
= __LINE__
;
183 Thread::Run(message_loop
);
184 CHECK_GT(line_number
, 0);
187 NOINLINE
void BrowserThreadImpl::FileThreadRun(
188 base::MessageLoop
* message_loop
) {
189 volatile int line_number
= __LINE__
;
190 Thread::Run(message_loop
);
191 CHECK_GT(line_number
, 0);
194 NOINLINE
void BrowserThreadImpl::FileUserBlockingThreadRun(
195 base::MessageLoop
* message_loop
) {
196 volatile int line_number
= __LINE__
;
197 Thread::Run(message_loop
);
198 CHECK_GT(line_number
, 0);
201 NOINLINE
void BrowserThreadImpl::ProcessLauncherThreadRun(
202 base::MessageLoop
* message_loop
) {
203 volatile int line_number
= __LINE__
;
204 Thread::Run(message_loop
);
205 CHECK_GT(line_number
, 0);
208 NOINLINE
void BrowserThreadImpl::CacheThreadRun(
209 base::MessageLoop
* message_loop
) {
210 volatile int line_number
= __LINE__
;
211 Thread::Run(message_loop
);
212 CHECK_GT(line_number
, 0);
215 NOINLINE
void BrowserThreadImpl::IOThreadRun(base::MessageLoop
* message_loop
) {
216 volatile int line_number
= __LINE__
;
217 Thread::Run(message_loop
);
218 CHECK_GT(line_number
, 0);
222 MSVC_ENABLE_OPTIMIZE();
224 void BrowserThreadImpl::Run(base::MessageLoop
* message_loop
) {
225 #if defined(OS_ANDROID)
226 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
227 // Though it may create unnecessary VM thread objects, keeping thread name
228 // gives more benefit in debugging in the platform.
229 if (!thread_name().empty()) {
230 base::android::AttachCurrentThreadWithName(thread_name());
234 BrowserThread::ID thread_id
= ID_COUNT
;
235 if (!GetCurrentThreadIdentifier(&thread_id
))
236 return Thread::Run(message_loop
);
239 case BrowserThread::UI
:
240 return UIThreadRun(message_loop
);
241 case BrowserThread::DB
:
242 return DBThreadRun(message_loop
);
243 case BrowserThread::FILE:
244 return FileThreadRun(message_loop
);
245 case BrowserThread::FILE_USER_BLOCKING
:
246 return FileUserBlockingThreadRun(message_loop
);
247 case BrowserThread::PROCESS_LAUNCHER
:
248 return ProcessLauncherThreadRun(message_loop
);
249 case BrowserThread::CACHE
:
250 return CacheThreadRun(message_loop
);
251 case BrowserThread::IO
:
252 return IOThreadRun(message_loop
);
253 case BrowserThread::ID_COUNT
:
254 CHECK(false); // This shouldn't actually be reached!
257 Thread::Run(message_loop
);
260 void BrowserThreadImpl::CleanUp() {
261 BrowserThreadGlobals
& globals
= g_globals
.Get();
263 using base::subtle::AtomicWord
;
264 AtomicWord
* storage
=
265 reinterpret_cast<AtomicWord
*>(&globals
.thread_delegates
[identifier_
]);
266 AtomicWord stored_pointer
= base::subtle::NoBarrier_Load(storage
);
267 BrowserThreadDelegate
* delegate
=
268 reinterpret_cast<BrowserThreadDelegate
*>(stored_pointer
);
274 void BrowserThreadImpl::Initialize() {
275 BrowserThreadGlobals
& globals
= g_globals
.Get();
277 base::AutoLock
lock(globals
.lock
);
278 DCHECK(identifier_
>= 0 && identifier_
< ID_COUNT
);
279 DCHECK(globals
.threads
[identifier_
] == NULL
);
280 globals
.threads
[identifier_
] = this;
283 BrowserThreadImpl::~BrowserThreadImpl() {
284 // All Thread subclasses must call Stop() in the destructor. This is
285 // doubly important here as various bits of code check they are on
286 // the right BrowserThread.
289 BrowserThreadGlobals
& globals
= g_globals
.Get();
290 base::AutoLock
lock(globals
.lock
);
291 globals
.threads
[identifier_
] = NULL
;
293 // Double check that the threads are ordered correctly in the enumeration.
294 for (int i
= identifier_
+ 1; i
< ID_COUNT
; ++i
) {
295 DCHECK(!globals
.threads
[i
]) <<
296 "Threads must be listed in the reverse order that they die";
302 bool BrowserThreadImpl::PostTaskHelper(
303 BrowserThread::ID identifier
,
304 const tracked_objects::Location
& from_here
,
305 const base::Closure
& task
,
306 base::TimeDelta delay
,
308 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
309 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
310 // order of lifetime. So no need to lock if we know that the target thread
311 // outlives current thread.
312 // Note: since the array is so small, ok to loop instead of creating a map,
313 // which would require a lock because std::map isn't thread safe, defeating
314 // the whole purpose of this optimization.
315 BrowserThread::ID current_thread
= ID_COUNT
;
316 bool target_thread_outlives_current
=
317 GetCurrentThreadIdentifier(¤t_thread
) &&
318 current_thread
>= identifier
;
320 BrowserThreadGlobals
& globals
= g_globals
.Get();
321 if (!target_thread_outlives_current
)
322 globals
.lock
.Acquire();
324 base::MessageLoop
* message_loop
=
325 globals
.threads
[identifier
] ? globals
.threads
[identifier
]->message_loop()
329 message_loop
->PostDelayedTask(from_here
, task
, delay
);
331 message_loop
->PostNonNestableDelayedTask(from_here
, task
, delay
);
335 if (!target_thread_outlives_current
)
336 globals
.lock
.Release();
338 return !!message_loop
;
342 bool BrowserThread::PostBlockingPoolTask(
343 const tracked_objects::Location
& from_here
,
344 const base::Closure
& task
) {
345 return g_globals
.Get().blocking_pool
->PostWorkerTask(from_here
, task
);
349 bool BrowserThread::PostBlockingPoolTaskAndReply(
350 const tracked_objects::Location
& from_here
,
351 const base::Closure
& task
,
352 const base::Closure
& reply
) {
353 return g_globals
.Get().blocking_pool
->PostTaskAndReply(
354 from_here
, task
, reply
);
358 bool BrowserThread::PostBlockingPoolSequencedTask(
359 const std::string
& sequence_token_name
,
360 const tracked_objects::Location
& from_here
,
361 const base::Closure
& task
) {
362 return g_globals
.Get().blocking_pool
->PostNamedSequencedWorkerTask(
363 sequence_token_name
, from_here
, task
);
367 base::SequencedWorkerPool
* BrowserThread::GetBlockingPool() {
368 return g_globals
.Get().blocking_pool
.get();
372 bool BrowserThread::IsThreadInitialized(ID identifier
) {
373 if (g_globals
== NULL
)
376 BrowserThreadGlobals
& globals
= g_globals
.Get();
377 base::AutoLock
lock(globals
.lock
);
378 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
379 return globals
.threads
[identifier
] != NULL
;
383 bool BrowserThread::CurrentlyOn(ID identifier
) {
384 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
385 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
387 // http://crbug.com/63678
388 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton
;
389 BrowserThreadGlobals
& globals
= g_globals
.Get();
390 base::AutoLock
lock(globals
.lock
);
391 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
392 return globals
.threads
[identifier
] &&
393 globals
.threads
[identifier
]->message_loop() ==
394 base::MessageLoop::current();
397 static const char* GetThreadName(BrowserThread::ID thread
) {
398 if (BrowserThread::UI
< thread
&& thread
< BrowserThread::ID_COUNT
)
399 return g_browser_thread_names
[thread
];
400 if (thread
== BrowserThread::UI
)
401 return "Chrome_UIThread";
402 return "Unknown Thread";
406 std::string
BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected
) {
407 const std::string
& message_loop_name
=
408 base::MessageLoop::current()->thread_name();
409 ID actual_browser_thread
;
410 const char* actual_name
= "Unknown Thread";
411 if (!message_loop_name
.empty()) {
412 actual_name
= message_loop_name
.c_str();
413 } else if (GetCurrentThreadIdentifier(&actual_browser_thread
)) {
414 actual_name
= GetThreadName(actual_browser_thread
);
416 std::string result
= "Must be called on ";
417 result
+= GetThreadName(expected
);
418 result
+= "; actually called on ";
419 result
+= actual_name
;
425 bool BrowserThread::IsMessageLoopValid(ID identifier
) {
426 if (g_globals
== NULL
)
429 BrowserThreadGlobals
& globals
= g_globals
.Get();
430 base::AutoLock
lock(globals
.lock
);
431 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
432 return globals
.threads
[identifier
] &&
433 globals
.threads
[identifier
]->message_loop();
437 bool BrowserThread::PostTask(ID identifier
,
438 const tracked_objects::Location
& from_here
,
439 const base::Closure
& task
) {
440 return BrowserThreadImpl::PostTaskHelper(
441 identifier
, from_here
, task
, base::TimeDelta(), true);
445 bool BrowserThread::PostDelayedTask(ID identifier
,
446 const tracked_objects::Location
& from_here
,
447 const base::Closure
& task
,
448 base::TimeDelta delay
) {
449 return BrowserThreadImpl::PostTaskHelper(
450 identifier
, from_here
, task
, delay
, true);
454 bool BrowserThread::PostNonNestableTask(
456 const tracked_objects::Location
& from_here
,
457 const base::Closure
& task
) {
458 return BrowserThreadImpl::PostTaskHelper(
459 identifier
, from_here
, task
, base::TimeDelta(), false);
463 bool BrowserThread::PostNonNestableDelayedTask(
465 const tracked_objects::Location
& from_here
,
466 const base::Closure
& task
,
467 base::TimeDelta delay
) {
468 return BrowserThreadImpl::PostTaskHelper(
469 identifier
, from_here
, task
, delay
, false);
473 bool BrowserThread::PostTaskAndReply(
475 const tracked_objects::Location
& from_here
,
476 const base::Closure
& task
,
477 const base::Closure
& reply
) {
478 return GetMessageLoopProxyForThread(identifier
)->PostTaskAndReply(from_here
,
484 bool BrowserThread::GetCurrentThreadIdentifier(ID
* identifier
) {
485 if (g_globals
== NULL
)
488 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
489 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
491 // http://crbug.com/63678
492 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton
;
493 base::MessageLoop
* cur_message_loop
= base::MessageLoop::current();
494 BrowserThreadGlobals
& globals
= g_globals
.Get();
495 for (int i
= 0; i
< ID_COUNT
; ++i
) {
496 if (globals
.threads
[i
] &&
497 globals
.threads
[i
]->message_loop() == cur_message_loop
) {
498 *identifier
= globals
.threads
[i
]->identifier_
;
507 scoped_refptr
<base::MessageLoopProxy
>
508 BrowserThread::GetMessageLoopProxyForThread(ID identifier
) {
509 return g_proxies
.Get().proxies
[identifier
];
513 base::MessageLoop
* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier
) {
514 if (g_globals
== NULL
)
517 BrowserThreadGlobals
& globals
= g_globals
.Get();
518 base::AutoLock
lock(globals
.lock
);
519 base::Thread
* thread
= globals
.threads
[identifier
];
521 base::MessageLoop
* loop
= thread
->message_loop();
526 void BrowserThread::SetDelegate(ID identifier
,
527 BrowserThreadDelegate
* delegate
) {
528 using base::subtle::AtomicWord
;
529 BrowserThreadGlobals
& globals
= g_globals
.Get();
530 AtomicWord
* storage
= reinterpret_cast<AtomicWord
*>(
531 &globals
.thread_delegates
[identifier
]);
532 AtomicWord old_pointer
= base::subtle::NoBarrier_AtomicExchange(
533 storage
, reinterpret_cast<AtomicWord
>(delegate
));
535 // This catches registration when previously registered.
536 DCHECK(!delegate
|| !old_pointer
);
539 } // namespace content