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/single_thread_task_runner.h"
14 #include "base/threading/sequenced_worker_pool.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "content/public/browser/browser_thread_delegate.h"
17 #include "content/public/browser/content_browser_client.h"
18 #include "net/disk_cache/simple/simple_backend_impl.h"
20 #if defined(OS_ANDROID)
21 #include "base/android/jni_android.h"
28 // Friendly names for the well-known threads.
29 static const char* g_browser_thread_names
[BrowserThread::ID_COUNT
] = {
30 "", // UI (name assembled in browser_main.cc).
31 "Chrome_DBThread", // DB
32 "Chrome_FileThread", // FILE
33 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING
34 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER
35 "Chrome_CacheThread", // CACHE
36 "Chrome_IOThread", // IO
39 // An implementation of SingleThreadTaskRunner to be used in conjunction
40 // with BrowserThread.
41 class BrowserThreadTaskRunner
: public base::SingleThreadTaskRunner
{
43 explicit BrowserThreadTaskRunner(BrowserThread::ID identifier
)
46 // SingleThreadTaskRunner implementation.
47 bool PostDelayedTask(const tracked_objects::Location
& from_here
,
48 const base::Closure
& task
,
49 base::TimeDelta delay
) override
{
50 return BrowserThread::PostDelayedTask(id_
, from_here
, task
, delay
);
53 bool PostNonNestableDelayedTask(const tracked_objects::Location
& from_here
,
54 const base::Closure
& task
,
55 base::TimeDelta delay
) override
{
56 return BrowserThread::PostNonNestableDelayedTask(id_
, from_here
, task
,
60 bool RunsTasksOnCurrentThread() const override
{
61 return BrowserThread::CurrentlyOn(id_
);
65 ~BrowserThreadTaskRunner() override
{}
68 BrowserThread::ID id_
;
69 DISALLOW_COPY_AND_ASSIGN(BrowserThreadTaskRunner
);
72 // A separate helper is used just for the task runners, in order to avoid
73 // needing to initialize the globals to create a task runner.
74 struct BrowserThreadTaskRunners
{
75 BrowserThreadTaskRunners() {
76 for (int i
= 0; i
< BrowserThread::ID_COUNT
; ++i
) {
78 new BrowserThreadTaskRunner(static_cast<BrowserThread::ID
>(i
));
82 scoped_refptr
<base::SingleThreadTaskRunner
> proxies
[BrowserThread::ID_COUNT
];
85 base::LazyInstance
<BrowserThreadTaskRunners
>::Leaky g_task_runners
=
86 LAZY_INSTANCE_INITIALIZER
;
88 struct BrowserThreadGlobals
{
89 BrowserThreadGlobals()
90 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
91 memset(threads
, 0, BrowserThread::ID_COUNT
* sizeof(threads
[0]));
92 memset(thread_delegates
, 0,
93 BrowserThread::ID_COUNT
* sizeof(thread_delegates
[0]));
96 // This lock protects |threads|. Do not read or modify that array
97 // without holding this lock. Do not block while holding this lock.
100 // This array is protected by |lock|. The threads are not owned by this
101 // array. Typically, the threads are owned on the UI thread by
102 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
103 // array upon destruction.
104 BrowserThreadImpl
* threads
[BrowserThread::ID_COUNT
];
106 // Only atomic operations are used on this array. The delegates are not owned
107 // by this array, rather by whoever calls BrowserThread::SetDelegate.
108 BrowserThreadDelegate
* thread_delegates
[BrowserThread::ID_COUNT
];
110 const scoped_refptr
<base::SequencedWorkerPool
> blocking_pool
;
113 base::LazyInstance
<BrowserThreadGlobals
>::Leaky
114 g_globals
= LAZY_INSTANCE_INITIALIZER
;
118 BrowserThreadImpl::BrowserThreadImpl(ID identifier
)
119 : Thread(g_browser_thread_names
[identifier
]),
120 identifier_(identifier
) {
124 BrowserThreadImpl::BrowserThreadImpl(ID identifier
,
125 base::MessageLoop
* message_loop
)
126 : Thread(message_loop
->thread_name()), identifier_(identifier
) {
127 set_message_loop(message_loop
);
132 void BrowserThreadImpl::ShutdownThreadPool() {
133 // The goal is to make it impossible for chrome to 'infinite loop' during
134 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
135 // during shutdown get run. There's nothing particularly scientific about the
137 const int kMaxNewShutdownBlockingTasks
= 1000;
138 BrowserThreadGlobals
& globals
= g_globals
.Get();
139 globals
.blocking_pool
->Shutdown(kMaxNewShutdownBlockingTasks
);
143 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
144 // We don't want to create a pool if none exists.
145 if (g_globals
== NULL
)
147 g_globals
.Get().blocking_pool
->FlushForTesting();
148 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
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
);
164 // We disable optimizations for this block of functions so the compiler doesn't
165 // merge them all together.
166 MSVC_DISABLE_OPTIMIZE()
167 MSVC_PUSH_DISABLE_WARNING(4748)
169 NOINLINE
void BrowserThreadImpl::UIThreadRun(base::MessageLoop
* message_loop
) {
170 volatile int line_number
= __LINE__
;
171 Thread::Run(message_loop
);
172 CHECK_GT(line_number
, 0);
175 NOINLINE
void BrowserThreadImpl::DBThreadRun(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::FileThreadRun(
182 base::MessageLoop
* message_loop
) {
183 volatile int line_number
= __LINE__
;
184 Thread::Run(message_loop
);
185 CHECK_GT(line_number
, 0);
188 NOINLINE
void BrowserThreadImpl::FileUserBlockingThreadRun(
189 base::MessageLoop
* message_loop
) {
190 volatile int line_number
= __LINE__
;
191 Thread::Run(message_loop
);
192 CHECK_GT(line_number
, 0);
195 NOINLINE
void BrowserThreadImpl::ProcessLauncherThreadRun(
196 base::MessageLoop
* message_loop
) {
197 volatile int line_number
= __LINE__
;
198 Thread::Run(message_loop
);
199 CHECK_GT(line_number
, 0);
202 NOINLINE
void BrowserThreadImpl::CacheThreadRun(
203 base::MessageLoop
* message_loop
) {
204 volatile int line_number
= __LINE__
;
205 Thread::Run(message_loop
);
206 CHECK_GT(line_number
, 0);
209 NOINLINE
void BrowserThreadImpl::IOThreadRun(base::MessageLoop
* message_loop
) {
210 volatile int line_number
= __LINE__
;
211 Thread::Run(message_loop
);
212 CHECK_GT(line_number
, 0);
216 MSVC_ENABLE_OPTIMIZE();
218 void BrowserThreadImpl::Run(base::MessageLoop
* message_loop
) {
219 #if defined(OS_ANDROID)
220 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
221 // Though it may create unnecessary VM thread objects, keeping thread name
222 // gives more benefit in debugging in the platform.
223 if (!thread_name().empty()) {
224 base::android::AttachCurrentThreadWithName(thread_name());
228 BrowserThread::ID thread_id
= ID_COUNT
;
229 if (!GetCurrentThreadIdentifier(&thread_id
))
230 return Thread::Run(message_loop
);
233 case BrowserThread::UI
:
234 return UIThreadRun(message_loop
);
235 case BrowserThread::DB
:
236 return DBThreadRun(message_loop
);
237 case BrowserThread::FILE:
238 return FileThreadRun(message_loop
);
239 case BrowserThread::FILE_USER_BLOCKING
:
240 return FileUserBlockingThreadRun(message_loop
);
241 case BrowserThread::PROCESS_LAUNCHER
:
242 return ProcessLauncherThreadRun(message_loop
);
243 case BrowserThread::CACHE
:
244 return CacheThreadRun(message_loop
);
245 case BrowserThread::IO
:
246 return IOThreadRun(message_loop
);
247 case BrowserThread::ID_COUNT
:
248 CHECK(false); // This shouldn't actually be reached!
251 Thread::Run(message_loop
);
254 void BrowserThreadImpl::CleanUp() {
255 BrowserThreadGlobals
& globals
= g_globals
.Get();
257 using base::subtle::AtomicWord
;
258 AtomicWord
* storage
=
259 reinterpret_cast<AtomicWord
*>(&globals
.thread_delegates
[identifier_
]);
260 AtomicWord stored_pointer
= base::subtle::NoBarrier_Load(storage
);
261 BrowserThreadDelegate
* delegate
=
262 reinterpret_cast<BrowserThreadDelegate
*>(stored_pointer
);
268 void BrowserThreadImpl::Initialize() {
269 BrowserThreadGlobals
& globals
= g_globals
.Get();
271 base::AutoLock
lock(globals
.lock
);
272 DCHECK(identifier_
>= 0 && identifier_
< ID_COUNT
);
273 DCHECK(globals
.threads
[identifier_
] == NULL
);
274 globals
.threads
[identifier_
] = this;
277 BrowserThreadImpl::~BrowserThreadImpl() {
278 // All Thread subclasses must call Stop() in the destructor. This is
279 // doubly important here as various bits of code check they are on
280 // the right BrowserThread.
283 BrowserThreadGlobals
& globals
= g_globals
.Get();
284 base::AutoLock
lock(globals
.lock
);
285 globals
.threads
[identifier_
] = NULL
;
287 // Double check that the threads are ordered correctly in the enumeration.
288 for (int i
= identifier_
+ 1; i
< ID_COUNT
; ++i
) {
289 DCHECK(!globals
.threads
[i
]) <<
290 "Threads must be listed in the reverse order that they die";
295 bool BrowserThreadImpl::StartWithOptions(const Options
& options
) {
296 // The global thread table needs to be locked while a new thread is
297 // starting, as the new thread can asynchronously start touching the
298 // table (and other thread's message_loop).
299 BrowserThreadGlobals
& globals
= g_globals
.Get();
300 base::AutoLock
lock(globals
.lock
);
301 return Thread::StartWithOptions(options
);
305 bool BrowserThreadImpl::PostTaskHelper(
306 BrowserThread::ID identifier
,
307 const tracked_objects::Location
& from_here
,
308 const base::Closure
& task
,
309 base::TimeDelta delay
,
311 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
312 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
313 // order of lifetime. So no need to lock if we know that the target thread
314 // outlives current thread.
315 // Note: since the array is so small, ok to loop instead of creating a map,
316 // which would require a lock because std::map isn't thread safe, defeating
317 // the whole purpose of this optimization.
318 BrowserThread::ID current_thread
= ID_COUNT
;
319 bool target_thread_outlives_current
=
320 GetCurrentThreadIdentifier(¤t_thread
) &&
321 current_thread
>= identifier
;
323 BrowserThreadGlobals
& globals
= g_globals
.Get();
324 if (!target_thread_outlives_current
)
325 globals
.lock
.Acquire();
327 base::MessageLoop
* message_loop
=
328 globals
.threads
[identifier
] ? globals
.threads
[identifier
]->message_loop()
332 message_loop
->task_runner()->PostDelayedTask(from_here
, task
, delay
);
334 message_loop
->task_runner()->PostNonNestableDelayedTask(from_here
, task
,
339 if (!target_thread_outlives_current
)
340 globals
.lock
.Release();
342 return !!message_loop
;
346 bool BrowserThread::PostBlockingPoolTask(
347 const tracked_objects::Location
& from_here
,
348 const base::Closure
& task
) {
349 return g_globals
.Get().blocking_pool
->PostWorkerTask(from_here
, task
);
353 bool BrowserThread::PostBlockingPoolTaskAndReply(
354 const tracked_objects::Location
& from_here
,
355 const base::Closure
& task
,
356 const base::Closure
& reply
) {
357 return g_globals
.Get().blocking_pool
->PostTaskAndReply(
358 from_here
, task
, reply
);
362 bool BrowserThread::PostBlockingPoolSequencedTask(
363 const std::string
& sequence_token_name
,
364 const tracked_objects::Location
& from_here
,
365 const base::Closure
& task
) {
366 return g_globals
.Get().blocking_pool
->PostNamedSequencedWorkerTask(
367 sequence_token_name
, from_here
, task
);
371 void BrowserThread::PostAfterStartupTask(
372 const tracked_objects::Location
& from_here
,
373 const scoped_refptr
<base::TaskRunner
>& task_runner
,
374 const base::Closure
& task
) {
375 GetContentClient()->browser()->PostAfterStartupTask(from_here
, task_runner
,
380 base::SequencedWorkerPool
* BrowserThread::GetBlockingPool() {
381 return g_globals
.Get().blocking_pool
.get();
385 bool BrowserThread::IsThreadInitialized(ID identifier
) {
386 if (g_globals
== NULL
)
389 BrowserThreadGlobals
& globals
= g_globals
.Get();
390 base::AutoLock
lock(globals
.lock
);
391 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
392 return globals
.threads
[identifier
] != NULL
;
396 bool BrowserThread::CurrentlyOn(ID identifier
) {
397 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
398 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
400 // http://crbug.com/63678
401 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton
;
402 BrowserThreadGlobals
& globals
= g_globals
.Get();
403 base::AutoLock
lock(globals
.lock
);
404 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
405 return globals
.threads
[identifier
] &&
406 globals
.threads
[identifier
]->message_loop() ==
407 base::MessageLoop::current();
410 static const char* GetThreadName(BrowserThread::ID thread
) {
411 if (BrowserThread::UI
< thread
&& thread
< BrowserThread::ID_COUNT
)
412 return g_browser_thread_names
[thread
];
413 if (thread
== BrowserThread::UI
)
414 return "Chrome_UIThread";
415 return "Unknown Thread";
419 std::string
BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected
) {
420 const base::MessageLoop
* message_loop
= base::MessageLoop::current();
421 ID actual_browser_thread
;
422 const char* actual_name
= "Unknown Thread";
423 if (message_loop
&& !message_loop
->thread_name().empty()) {
424 actual_name
= message_loop
->thread_name().c_str();
425 } else if (GetCurrentThreadIdentifier(&actual_browser_thread
)) {
426 actual_name
= GetThreadName(actual_browser_thread
);
428 std::string result
= "Must be called on ";
429 result
+= GetThreadName(expected
);
430 result
+= "; actually called on ";
431 result
+= actual_name
;
437 bool BrowserThread::IsMessageLoopValid(ID identifier
) {
438 if (g_globals
== NULL
)
441 BrowserThreadGlobals
& globals
= g_globals
.Get();
442 base::AutoLock
lock(globals
.lock
);
443 DCHECK(identifier
>= 0 && identifier
< ID_COUNT
);
444 return globals
.threads
[identifier
] &&
445 globals
.threads
[identifier
]->message_loop();
449 bool BrowserThread::PostTask(ID identifier
,
450 const tracked_objects::Location
& from_here
,
451 const base::Closure
& task
) {
452 return BrowserThreadImpl::PostTaskHelper(
453 identifier
, from_here
, task
, base::TimeDelta(), true);
457 bool BrowserThread::PostDelayedTask(ID identifier
,
458 const tracked_objects::Location
& from_here
,
459 const base::Closure
& task
,
460 base::TimeDelta delay
) {
461 return BrowserThreadImpl::PostTaskHelper(
462 identifier
, from_here
, task
, delay
, true);
466 bool BrowserThread::PostNonNestableTask(
468 const tracked_objects::Location
& from_here
,
469 const base::Closure
& task
) {
470 return BrowserThreadImpl::PostTaskHelper(
471 identifier
, from_here
, task
, base::TimeDelta(), false);
475 bool BrowserThread::PostNonNestableDelayedTask(
477 const tracked_objects::Location
& from_here
,
478 const base::Closure
& task
,
479 base::TimeDelta delay
) {
480 return BrowserThreadImpl::PostTaskHelper(
481 identifier
, from_here
, task
, delay
, false);
485 bool BrowserThread::PostTaskAndReply(
487 const tracked_objects::Location
& from_here
,
488 const base::Closure
& task
,
489 const base::Closure
& reply
) {
490 return GetMessageLoopProxyForThread(identifier
)->PostTaskAndReply(from_here
,
496 bool BrowserThread::GetCurrentThreadIdentifier(ID
* identifier
) {
497 if (g_globals
== NULL
)
500 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
501 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
503 // http://crbug.com/63678
504 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton
;
505 base::MessageLoop
* cur_message_loop
= base::MessageLoop::current();
506 BrowserThreadGlobals
& globals
= g_globals
.Get();
507 for (int i
= 0; i
< ID_COUNT
; ++i
) {
508 if (globals
.threads
[i
] &&
509 globals
.threads
[i
]->message_loop() == cur_message_loop
) {
510 *identifier
= globals
.threads
[i
]->identifier_
;
519 scoped_refptr
<base::SingleThreadTaskRunner
>
520 BrowserThread::GetMessageLoopProxyForThread(ID identifier
) {
521 return g_task_runners
.Get().proxies
[identifier
];
525 base::MessageLoop
* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier
) {
526 if (g_globals
== NULL
)
529 BrowserThreadGlobals
& globals
= g_globals
.Get();
530 base::AutoLock
lock(globals
.lock
);
531 base::Thread
* thread
= globals
.threads
[identifier
];
533 base::MessageLoop
* loop
= thread
->message_loop();
538 void BrowserThread::SetDelegate(ID identifier
,
539 BrowserThreadDelegate
* delegate
) {
540 using base::subtle::AtomicWord
;
541 BrowserThreadGlobals
& globals
= g_globals
.Get();
542 AtomicWord
* storage
= reinterpret_cast<AtomicWord
*>(
543 &globals
.thread_delegates
[identifier
]);
544 AtomicWord old_pointer
= base::subtle::NoBarrier_AtomicExchange(
545 storage
, reinterpret_cast<AtomicWord
>(delegate
));
547 // This catches registration when previously registered.
548 DCHECK(!delegate
|| !old_pointer
);
551 } // namespace content