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"
18 #include "content/public/browser/content_browser_client.h"
19 #include "net/disk_cache/simple/simple_backend_impl.h"
21 #if defined(OS_ANDROID)
22 #include "base/android/jni_android.h"
29 // Friendly names for the well-known threads.
30 static const char* g_browser_thread_names
[BrowserThread::ID_COUNT
] = {
31 "", // UI (name assembled in browser_main.cc).
32 "Chrome_DBThread", // DB
33 "Chrome_FileThread", // FILE
34 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING
35 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER
36 "Chrome_CacheThread", // CACHE
37 "Chrome_IOThread", // IO
40 // An implementation of MessageLoopProxy to be used in conjunction
41 // with BrowserThread.
42 class BrowserThreadMessageLoopProxy
: public base::MessageLoopProxy
{
44 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier
)
48 // MessageLoopProxy implementation.
49 bool PostDelayedTask(const tracked_objects::Location
& from_here
,
50 const base::Closure
& task
,
51 base::TimeDelta delay
) override
{
52 return BrowserThread::PostDelayedTask(id_
, from_here
, task
, delay
);
55 bool PostNonNestableDelayedTask(const tracked_objects::Location
& from_here
,
56 const base::Closure
& task
,
57 base::TimeDelta delay
) override
{
58 return BrowserThread::PostNonNestableDelayedTask(id_
, from_here
, task
,
62 bool RunsTasksOnCurrentThread() const override
{
63 return BrowserThread::CurrentlyOn(id_
);
67 ~BrowserThreadMessageLoopProxy() override
{}
70 BrowserThread::ID id_
;
71 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy
);
74 // A separate helper is used just for the proxies, in order to avoid needing
75 // to initialize the globals to create a proxy.
76 struct BrowserThreadProxies
{
77 BrowserThreadProxies() {
78 for (int i
= 0; i
< BrowserThread::ID_COUNT
; ++i
) {
80 new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID
>(i
));
84 scoped_refptr
<base::MessageLoopProxy
> proxies
[BrowserThread::ID_COUNT
];
87 base::LazyInstance
<BrowserThreadProxies
>::Leaky
88 g_proxies
= LAZY_INSTANCE_INITIALIZER
;
90 struct BrowserThreadGlobals
{
91 BrowserThreadGlobals()
92 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
93 memset(threads
, 0, BrowserThread::ID_COUNT
* sizeof(threads
[0]));
94 memset(thread_delegates
, 0,
95 BrowserThread::ID_COUNT
* sizeof(thread_delegates
[0]));
98 // This lock protects |threads|. Do not read or modify that array
99 // without holding this lock. Do not block while holding this lock.
102 // This array is protected by |lock|. The threads are not owned by this
103 // array. Typically, the threads are owned on the UI thread by
104 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
105 // array upon destruction.
106 BrowserThreadImpl
* threads
[BrowserThread::ID_COUNT
];
108 // Only atomic operations are used on this array. The delegates are not owned
109 // by this array, rather by whoever calls BrowserThread::SetDelegate.
110 BrowserThreadDelegate
* thread_delegates
[BrowserThread::ID_COUNT
];
112 const scoped_refptr
<base::SequencedWorkerPool
> blocking_pool
;
115 base::LazyInstance
<BrowserThreadGlobals
>::Leaky
116 g_globals
= LAZY_INSTANCE_INITIALIZER
;
120 BrowserThreadImpl::BrowserThreadImpl(ID identifier
)
121 : Thread(g_browser_thread_names
[identifier
]),
122 identifier_(identifier
) {
126 BrowserThreadImpl::BrowserThreadImpl(ID identifier
,
127 base::MessageLoop
* message_loop
)
128 : Thread(message_loop
->thread_name()), identifier_(identifier
) {
129 set_message_loop(message_loop
);
134 void BrowserThreadImpl::ShutdownThreadPool() {
135 // The goal is to make it impossible for chrome to 'infinite loop' during
136 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
137 // during shutdown get run. There's nothing particularly scientific about the
139 const int kMaxNewShutdownBlockingTasks
= 1000;
140 BrowserThreadGlobals
& globals
= g_globals
.Get();
141 globals
.blocking_pool
->Shutdown(kMaxNewShutdownBlockingTasks
);
145 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
146 // We don't want to create a pool if none exists.
147 if (g_globals
== NULL
)
149 g_globals
.Get().blocking_pool
->FlushForTesting();
150 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
153 void BrowserThreadImpl::Init() {
154 BrowserThreadGlobals
& globals
= g_globals
.Get();
156 using base::subtle::AtomicWord
;
157 AtomicWord
* storage
=
158 reinterpret_cast<AtomicWord
*>(&globals
.thread_delegates
[identifier_
]);
159 AtomicWord stored_pointer
= base::subtle::NoBarrier_Load(storage
);
160 BrowserThreadDelegate
* delegate
=
161 reinterpret_cast<BrowserThreadDelegate
*>(stored_pointer
);
164 message_loop()->PostTask(FROM_HERE
,
165 base::Bind(&BrowserThreadDelegate::InitAsync
,
166 // Delegate is expected to exist for the
167 // duration of the thread's lifetime
168 base::Unretained(delegate
)));
172 // We disable optimizations for this block of functions so the compiler doesn't
173 // merge them all together.
174 MSVC_DISABLE_OPTIMIZE()
175 MSVC_PUSH_DISABLE_WARNING(4748)
177 NOINLINE
void BrowserThreadImpl::UIThreadRun(base::MessageLoop
* message_loop
) {
178 volatile int line_number
= __LINE__
;
179 Thread::Run(message_loop
);
180 CHECK_GT(line_number
, 0);
183 NOINLINE
void BrowserThreadImpl::DBThreadRun(base::MessageLoop
* message_loop
) {
184 volatile int line_number
= __LINE__
;
185 Thread::Run(message_loop
);
186 CHECK_GT(line_number
, 0);
189 NOINLINE
void BrowserThreadImpl::FileThreadRun(
190 base::MessageLoop
* message_loop
) {
191 volatile int line_number
= __LINE__
;
192 Thread::Run(message_loop
);
193 CHECK_GT(line_number
, 0);
196 NOINLINE
void BrowserThreadImpl::FileUserBlockingThreadRun(
197 base::MessageLoop
* message_loop
) {
198 volatile int line_number
= __LINE__
;
199 Thread::Run(message_loop
);
200 CHECK_GT(line_number
, 0);
203 NOINLINE
void BrowserThreadImpl::ProcessLauncherThreadRun(
204 base::MessageLoop
* message_loop
) {
205 volatile int line_number
= __LINE__
;
206 Thread::Run(message_loop
);
207 CHECK_GT(line_number
, 0);
210 NOINLINE
void BrowserThreadImpl::CacheThreadRun(
211 base::MessageLoop
* message_loop
) {
212 volatile int line_number
= __LINE__
;
213 Thread::Run(message_loop
);
214 CHECK_GT(line_number
, 0);
217 NOINLINE
void BrowserThreadImpl::IOThreadRun(base::MessageLoop
* message_loop
) {
218 volatile int line_number
= __LINE__
;
219 Thread::Run(message_loop
);
220 CHECK_GT(line_number
, 0);
224 MSVC_ENABLE_OPTIMIZE();
226 void BrowserThreadImpl::Run(base::MessageLoop
* message_loop
) {
227 #if defined(OS_ANDROID)
228 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
229 // Though it may create unnecessary VM thread objects, keeping thread name
230 // gives more benefit in debugging in the platform.
231 if (!thread_name().empty()) {
232 base::android::AttachCurrentThreadWithName(thread_name());
236 BrowserThread::ID thread_id
= ID_COUNT
;
237 if (!GetCurrentThreadIdentifier(&thread_id
))
238 return Thread::Run(message_loop
);
241 case BrowserThread::UI
:
242 return UIThreadRun(message_loop
);
243 case BrowserThread::DB
:
244 return DBThreadRun(message_loop
);
245 case BrowserThread::FILE:
246 return FileThreadRun(message_loop
);
247 case BrowserThread::FILE_USER_BLOCKING
:
248 return FileUserBlockingThreadRun(message_loop
);
249 case BrowserThread::PROCESS_LAUNCHER
:
250 return ProcessLauncherThreadRun(message_loop
);
251 case BrowserThread::CACHE
:
252 return CacheThreadRun(message_loop
);
253 case BrowserThread::IO
:
254 return IOThreadRun(message_loop
);
255 case BrowserThread::ID_COUNT
:
256 CHECK(false); // This shouldn't actually be reached!
259 Thread::Run(message_loop
);
262 void BrowserThreadImpl::CleanUp() {
263 BrowserThreadGlobals
& globals
= g_globals
.Get();
265 using base::subtle::AtomicWord
;
266 AtomicWord
* storage
=
267 reinterpret_cast<AtomicWord
*>(&globals
.thread_delegates
[identifier_
]);
268 AtomicWord stored_pointer
= base::subtle::NoBarrier_Load(storage
);
269 BrowserThreadDelegate
* delegate
=
270 reinterpret_cast<BrowserThreadDelegate
*>(stored_pointer
);
276 void BrowserThreadImpl::Initialize() {
277 BrowserThreadGlobals
& globals
= g_globals
.Get();
279 base::AutoLock
lock(globals
.lock
);
280 DCHECK(identifier_
>= 0 && identifier_
< ID_COUNT
);
281 DCHECK(globals
.threads
[identifier_
] == NULL
);
282 globals
.threads
[identifier_
] = this;
285 BrowserThreadImpl::~BrowserThreadImpl() {
286 // All Thread subclasses must call Stop() in the destructor. This is
287 // doubly important here as various bits of code check they are on
288 // the right BrowserThread.
291 BrowserThreadGlobals
& globals
= g_globals
.Get();
292 base::AutoLock
lock(globals
.lock
);
293 globals
.threads
[identifier_
] = NULL
;
295 // Double check that the threads are ordered correctly in the enumeration.
296 for (int i
= identifier_
+ 1; i
< ID_COUNT
; ++i
) {
297 DCHECK(!globals
.threads
[i
]) <<
298 "Threads must be listed in the reverse order that they die";
304 bool BrowserThreadImpl::PostTaskHelper(
305 BrowserThread::ID identifier
,
306 const tracked_objects::Location
& from_here
,
307 const base::Closure
& task
,
308 base::TimeDelta delay
,
310 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
311 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
312 // order of lifetime. So no need to lock if we know that the target thread
313 // outlives current thread.
314 // Note: since the array is so small, ok to loop instead of creating a map,
315 // which would require a lock because std::map isn't thread safe, defeating
316 // the whole purpose of this optimization.
317 BrowserThread::ID current_thread
= ID_COUNT
;
318 bool target_thread_outlives_current
=
319 GetCurrentThreadIdentifier(¤t_thread
) &&
320 current_thread
>= identifier
;
322 BrowserThreadGlobals
& globals
= g_globals
.Get();
323 if (!target_thread_outlives_current
)
324 globals
.lock
.Acquire();
326 base::MessageLoop
* message_loop
=
327 globals
.threads
[identifier
] ? globals
.threads
[identifier
]->message_loop()
331 message_loop
->PostDelayedTask(from_here
, task
, delay
);
333 message_loop
->PostNonNestableDelayedTask(from_here
, task
, delay
);
337 if (!target_thread_outlives_current
)
338 globals
.lock
.Release();
340 return !!message_loop
;
344 bool BrowserThread::PostBlockingPoolTask(
345 const tracked_objects::Location
& from_here
,
346 const base::Closure
& task
) {
347 return g_globals
.Get().blocking_pool
->PostWorkerTask(from_here
, task
);
351 bool BrowserThread::PostBlockingPoolTaskAndReply(
352 const tracked_objects::Location
& from_here
,
353 const base::Closure
& task
,
354 const base::Closure
& reply
) {
355 return g_globals
.Get().blocking_pool
->PostTaskAndReply(
356 from_here
, task
, reply
);
360 bool BrowserThread::PostBlockingPoolSequencedTask(
361 const std::string
& sequence_token_name
,
362 const tracked_objects::Location
& from_here
,
363 const base::Closure
& task
) {
364 return g_globals
.Get().blocking_pool
->PostNamedSequencedWorkerTask(
365 sequence_token_name
, from_here
, task
);
369 void BrowserThread::PostAfterStartupTask(
370 const tracked_objects::Location
& from_here
,
371 const scoped_refptr
<base::TaskRunner
>& task_runner
,
372 const base::Closure
& task
) {
373 GetContentClient()->browser()->PostAfterStartupTask(from_here
, task_runner
,
378 base::SequencedWorkerPool
* BrowserThread::GetBlockingPool() {
379 return g_globals
.Get().blocking_pool
.get();
383 bool BrowserThread::IsThreadInitialized(ID identifier
) {
384 if (g_globals
== NULL
)
387 BrowserThreadGlobals
& globals
= g_globals
.Get();
388 base::AutoLock
lock(globals
.lock
);
389 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
390 return globals
.threads
[identifier
] != NULL
;
394 bool BrowserThread::CurrentlyOn(ID identifier
) {
395 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
396 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
398 // http://crbug.com/63678
399 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton
;
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() ==
405 base::MessageLoop::current();
408 static const char* GetThreadName(BrowserThread::ID thread
) {
409 if (BrowserThread::UI
< thread
&& thread
< BrowserThread::ID_COUNT
)
410 return g_browser_thread_names
[thread
];
411 if (thread
== BrowserThread::UI
)
412 return "Chrome_UIThread";
413 return "Unknown Thread";
417 std::string
BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected
) {
418 const base::MessageLoop
* message_loop
= base::MessageLoop::current();
419 ID actual_browser_thread
;
420 const char* actual_name
= "Unknown Thread";
421 if (message_loop
&& !message_loop
->thread_name().empty()) {
422 actual_name
= message_loop
->thread_name().c_str();
423 } else if (GetCurrentThreadIdentifier(&actual_browser_thread
)) {
424 actual_name
= GetThreadName(actual_browser_thread
);
426 std::string result
= "Must be called on ";
427 result
+= GetThreadName(expected
);
428 result
+= "; actually called on ";
429 result
+= actual_name
;
435 bool BrowserThread::IsMessageLoopValid(ID identifier
) {
436 if (g_globals
== NULL
)
439 BrowserThreadGlobals
& globals
= g_globals
.Get();
440 base::AutoLock
lock(globals
.lock
);
441 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
442 return globals
.threads
[identifier
] &&
443 globals
.threads
[identifier
]->message_loop();
447 bool BrowserThread::PostTask(ID identifier
,
448 const tracked_objects::Location
& from_here
,
449 const base::Closure
& task
) {
450 return BrowserThreadImpl::PostTaskHelper(
451 identifier
, from_here
, task
, base::TimeDelta(), true);
455 bool BrowserThread::PostDelayedTask(ID identifier
,
456 const tracked_objects::Location
& from_here
,
457 const base::Closure
& task
,
458 base::TimeDelta delay
) {
459 return BrowserThreadImpl::PostTaskHelper(
460 identifier
, from_here
, task
, delay
, true);
464 bool BrowserThread::PostNonNestableTask(
466 const tracked_objects::Location
& from_here
,
467 const base::Closure
& task
) {
468 return BrowserThreadImpl::PostTaskHelper(
469 identifier
, from_here
, task
, base::TimeDelta(), false);
473 bool BrowserThread::PostNonNestableDelayedTask(
475 const tracked_objects::Location
& from_here
,
476 const base::Closure
& task
,
477 base::TimeDelta delay
) {
478 return BrowserThreadImpl::PostTaskHelper(
479 identifier
, from_here
, task
, delay
, false);
483 bool BrowserThread::PostTaskAndReply(
485 const tracked_objects::Location
& from_here
,
486 const base::Closure
& task
,
487 const base::Closure
& reply
) {
488 return GetMessageLoopProxyForThread(identifier
)->PostTaskAndReply(from_here
,
494 bool BrowserThread::GetCurrentThreadIdentifier(ID
* identifier
) {
495 if (g_globals
== NULL
)
498 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
499 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
501 // http://crbug.com/63678
502 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton
;
503 base::MessageLoop
* cur_message_loop
= base::MessageLoop::current();
504 BrowserThreadGlobals
& globals
= g_globals
.Get();
505 for (int i
= 0; i
< ID_COUNT
; ++i
) {
506 if (globals
.threads
[i
] &&
507 globals
.threads
[i
]->message_loop() == cur_message_loop
) {
508 *identifier
= globals
.threads
[i
]->identifier_
;
517 scoped_refptr
<base::MessageLoopProxy
>
518 BrowserThread::GetMessageLoopProxyForThread(ID identifier
) {
519 return g_proxies
.Get().proxies
[identifier
];
523 base::MessageLoop
* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier
) {
524 if (g_globals
== NULL
)
527 BrowserThreadGlobals
& globals
= g_globals
.Get();
528 base::AutoLock
lock(globals
.lock
);
529 base::Thread
* thread
= globals
.threads
[identifier
];
531 base::MessageLoop
* loop
= thread
->message_loop();
536 void BrowserThread::SetDelegate(ID identifier
,
537 BrowserThreadDelegate
* delegate
) {
538 using base::subtle::AtomicWord
;
539 BrowserThreadGlobals
& globals
= g_globals
.Get();
540 AtomicWord
* storage
= reinterpret_cast<AtomicWord
*>(
541 &globals
.thread_delegates
[identifier
]);
542 AtomicWord old_pointer
= base::subtle::NoBarrier_AtomicExchange(
543 storage
, reinterpret_cast<AtomicWord
>(delegate
));
545 // This catches registration when previously registered.
546 DCHECK(!delegate
|| !old_pointer
);
549 } // namespace content