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/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 "net/disk_cache/simple/simple_backend_impl.h"
19
20 #if defined(OS_ANDROID)
21 #include "base/android/jni_android.h"
22 #endif
23
24 namespace content {
25
26 namespace {
27
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
37 };
38
39 // An implementation of MessageLoopProxy to be used in conjunction
40 // with BrowserThread.
41 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
42 public:
BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)43 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
44 : id_(identifier) {
45 }
46
47 // MessageLoopProxy implementation.
PostDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)48 virtual bool PostDelayedTask(
49 const tracked_objects::Location& from_here,
50 const base::Closure& task, base::TimeDelta delay) OVERRIDE {
51 return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
52 }
53
PostNonNestableDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)54 virtual bool PostNonNestableDelayedTask(
55 const tracked_objects::Location& from_here,
56 const base::Closure& task,
57 base::TimeDelta delay) OVERRIDE {
58 return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
59 delay);
60 }
61
RunsTasksOnCurrentThread() const62 virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
63 return BrowserThread::CurrentlyOn(id_);
64 }
65
66 protected:
~BrowserThreadMessageLoopProxy()67 virtual ~BrowserThreadMessageLoopProxy() {}
68
69 private:
70 BrowserThread::ID id_;
71 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
72 };
73
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 {
BrowserThreadProxiescontent::__anon7d5acf9f0111::BrowserThreadProxies77 BrowserThreadProxies() {
78 for (int i = 0; i < BrowserThread::ID_COUNT; ++i) {
79 proxies[i] =
80 new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID>(i));
81 }
82 }
83
84 scoped_refptr<base::MessageLoopProxy> proxies[BrowserThread::ID_COUNT];
85 };
86
87 base::LazyInstance<BrowserThreadProxies>::Leaky
88 g_proxies = LAZY_INSTANCE_INITIALIZER;
89
90 struct BrowserThreadGlobals {
BrowserThreadGlobalscontent::__anon7d5acf9f0111::BrowserThreadGlobals91 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]));
96 }
97
98 // This lock protects |threads|. Do not read or modify that array
99 // without holding this lock. Do not block while holding this lock.
100 base::Lock lock;
101
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];
107
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];
111
112 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
113 };
114
115 base::LazyInstance<BrowserThreadGlobals>::Leaky
116 g_globals = LAZY_INSTANCE_INITIALIZER;
117
118 } // namespace
119
BrowserThreadImpl(ID identifier)120 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
121 : Thread(g_browser_thread_names[identifier]),
122 identifier_(identifier) {
123 Initialize();
124 }
125
BrowserThreadImpl(ID identifier,base::MessageLoop * message_loop)126 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
127 base::MessageLoop* message_loop)
128 : Thread(message_loop->thread_name()), identifier_(identifier) {
129 set_message_loop(message_loop);
130 Initialize();
131 }
132
133 // static
ShutdownThreadPool()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
138 // number chosen.
139 const int kMaxNewShutdownBlockingTasks = 1000;
140 BrowserThreadGlobals& globals = g_globals.Get();
141 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
142 }
143
144 // static
FlushThreadPoolHelperForTesting()145 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
146 // We don't want to create a pool if none exists.
147 if (g_globals == NULL)
148 return;
149 g_globals.Get().blocking_pool->FlushForTesting();
150 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
151 }
152
Init()153 void BrowserThreadImpl::Init() {
154 BrowserThreadGlobals& globals = g_globals.Get();
155
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);
162 if (delegate) {
163 delegate->Init();
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)));
169 }
170 }
171
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)
176
UIThreadRun(base::MessageLoop * message_loop)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);
181 }
182
DBThreadRun(base::MessageLoop * message_loop)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);
187 }
188
FileThreadRun(base::MessageLoop * message_loop)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);
194 }
195
FileUserBlockingThreadRun(base::MessageLoop * message_loop)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);
201 }
202
ProcessLauncherThreadRun(base::MessageLoop * message_loop)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);
208 }
209
CacheThreadRun(base::MessageLoop * message_loop)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);
215 }
216
IOThreadRun(base::MessageLoop * message_loop)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);
221 }
222
223 MSVC_POP_WARNING()
224 MSVC_ENABLE_OPTIMIZE();
225
Run(base::MessageLoop * message_loop)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());
233 }
234 #endif
235
236 BrowserThread::ID thread_id = ID_COUNT;
237 if (!GetCurrentThreadIdentifier(&thread_id))
238 return Thread::Run(message_loop);
239
240 switch (thread_id) {
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!
257 break;
258 }
259 Thread::Run(message_loop);
260 }
261
CleanUp()262 void BrowserThreadImpl::CleanUp() {
263 BrowserThreadGlobals& globals = g_globals.Get();
264
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);
271
272 if (delegate)
273 delegate->CleanUp();
274 }
275
Initialize()276 void BrowserThreadImpl::Initialize() {
277 BrowserThreadGlobals& globals = g_globals.Get();
278
279 base::AutoLock lock(globals.lock);
280 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
281 DCHECK(globals.threads[identifier_] == NULL);
282 globals.threads[identifier_] = this;
283 }
284
~BrowserThreadImpl()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.
289 Stop();
290
291 BrowserThreadGlobals& globals = g_globals.Get();
292 base::AutoLock lock(globals.lock);
293 globals.threads[identifier_] = NULL;
294 #ifndef NDEBUG
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";
299 }
300 #endif
301 }
302
303 // static
PostTaskHelper(BrowserThread::ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay,bool nestable)304 bool BrowserThreadImpl::PostTaskHelper(
305 BrowserThread::ID identifier,
306 const tracked_objects::Location& from_here,
307 const base::Closure& task,
308 base::TimeDelta delay,
309 bool nestable) {
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;
321
322 BrowserThreadGlobals& globals = g_globals.Get();
323 if (!target_thread_outlives_current)
324 globals.lock.Acquire();
325
326 base::MessageLoop* message_loop =
327 globals.threads[identifier] ? globals.threads[identifier]->message_loop()
328 : NULL;
329 if (message_loop) {
330 if (nestable) {
331 message_loop->PostDelayedTask(from_here, task, delay);
332 } else {
333 message_loop->PostNonNestableDelayedTask(from_here, task, delay);
334 }
335 }
336
337 if (!target_thread_outlives_current)
338 globals.lock.Release();
339
340 return !!message_loop;
341 }
342
343 // static
PostBlockingPoolTask(const tracked_objects::Location & from_here,const base::Closure & task)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);
348 }
349
350 // static
PostBlockingPoolTaskAndReply(const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)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);
357 }
358
359 // static
PostBlockingPoolSequencedTask(const std::string & sequence_token_name,const tracked_objects::Location & from_here,const base::Closure & task)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);
366 }
367
368 // static
GetBlockingPool()369 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
370 return g_globals.Get().blocking_pool.get();
371 }
372
373 // static
IsThreadInitialized(ID identifier)374 bool BrowserThread::IsThreadInitialized(ID identifier) {
375 if (g_globals == NULL)
376 return false;
377
378 BrowserThreadGlobals& globals = g_globals.Get();
379 base::AutoLock lock(globals.lock);
380 DCHECK(identifier >= 0 && identifier < ID_COUNT);
381 return globals.threads[identifier] != NULL;
382 }
383
384 // static
CurrentlyOn(ID identifier)385 bool BrowserThread::CurrentlyOn(ID identifier) {
386 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
387 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
388 // function.
389 // http://crbug.com/63678
390 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
391 BrowserThreadGlobals& globals = g_globals.Get();
392 base::AutoLock lock(globals.lock);
393 DCHECK(identifier >= 0 && identifier < ID_COUNT);
394 return globals.threads[identifier] &&
395 globals.threads[identifier]->message_loop() ==
396 base::MessageLoop::current();
397 }
398
GetThreadName(BrowserThread::ID thread)399 static const char* GetThreadName(BrowserThread::ID thread) {
400 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
401 return g_browser_thread_names[thread];
402 if (thread == BrowserThread::UI)
403 return "Chrome_UIThread";
404 return "Unknown Thread";
405 }
406
407 // static
GetDCheckCurrentlyOnErrorMessage(ID expected)408 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
409 const std::string& message_loop_name =
410 base::MessageLoop::current()->thread_name();
411 ID actual_browser_thread;
412 const char* actual_name = "Unknown Thread";
413 if (!message_loop_name.empty()) {
414 actual_name = message_loop_name.c_str();
415 } else if (GetCurrentThreadIdentifier(&actual_browser_thread)) {
416 actual_name = GetThreadName(actual_browser_thread);
417 }
418 std::string result = "Must be called on ";
419 result += GetThreadName(expected);
420 result += "; actually called on ";
421 result += actual_name;
422 result += ".";
423 return result;
424 }
425
426 // static
IsMessageLoopValid(ID identifier)427 bool BrowserThread::IsMessageLoopValid(ID identifier) {
428 if (g_globals == NULL)
429 return false;
430
431 BrowserThreadGlobals& globals = g_globals.Get();
432 base::AutoLock lock(globals.lock);
433 DCHECK(identifier >= 0 && identifier < ID_COUNT);
434 return globals.threads[identifier] &&
435 globals.threads[identifier]->message_loop();
436 }
437
438 // static
PostTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)439 bool BrowserThread::PostTask(ID identifier,
440 const tracked_objects::Location& from_here,
441 const base::Closure& task) {
442 return BrowserThreadImpl::PostTaskHelper(
443 identifier, from_here, task, base::TimeDelta(), true);
444 }
445
446 // static
PostDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)447 bool BrowserThread::PostDelayedTask(ID identifier,
448 const tracked_objects::Location& from_here,
449 const base::Closure& task,
450 base::TimeDelta delay) {
451 return BrowserThreadImpl::PostTaskHelper(
452 identifier, from_here, task, delay, true);
453 }
454
455 // static
PostNonNestableTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)456 bool BrowserThread::PostNonNestableTask(
457 ID identifier,
458 const tracked_objects::Location& from_here,
459 const base::Closure& task) {
460 return BrowserThreadImpl::PostTaskHelper(
461 identifier, from_here, task, base::TimeDelta(), false);
462 }
463
464 // static
PostNonNestableDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)465 bool BrowserThread::PostNonNestableDelayedTask(
466 ID identifier,
467 const tracked_objects::Location& from_here,
468 const base::Closure& task,
469 base::TimeDelta delay) {
470 return BrowserThreadImpl::PostTaskHelper(
471 identifier, from_here, task, delay, false);
472 }
473
474 // static
PostTaskAndReply(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)475 bool BrowserThread::PostTaskAndReply(
476 ID identifier,
477 const tracked_objects::Location& from_here,
478 const base::Closure& task,
479 const base::Closure& reply) {
480 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
481 task,
482 reply);
483 }
484
485 // static
GetCurrentThreadIdentifier(ID * identifier)486 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
487 if (g_globals == NULL)
488 return false;
489
490 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
491 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
492 // function.
493 // http://crbug.com/63678
494 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
495 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
496 BrowserThreadGlobals& globals = g_globals.Get();
497 for (int i = 0; i < ID_COUNT; ++i) {
498 if (globals.threads[i] &&
499 globals.threads[i]->message_loop() == cur_message_loop) {
500 *identifier = globals.threads[i]->identifier_;
501 return true;
502 }
503 }
504
505 return false;
506 }
507
508 // static
509 scoped_refptr<base::MessageLoopProxy>
GetMessageLoopProxyForThread(ID identifier)510 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
511 return g_proxies.Get().proxies[identifier];
512 }
513
514 // static
UnsafeGetMessageLoopForThread(ID identifier)515 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
516 if (g_globals == NULL)
517 return NULL;
518
519 BrowserThreadGlobals& globals = g_globals.Get();
520 base::AutoLock lock(globals.lock);
521 base::Thread* thread = globals.threads[identifier];
522 DCHECK(thread);
523 base::MessageLoop* loop = thread->message_loop();
524 return loop;
525 }
526
527 // static
SetDelegate(ID identifier,BrowserThreadDelegate * delegate)528 void BrowserThread::SetDelegate(ID identifier,
529 BrowserThreadDelegate* delegate) {
530 using base::subtle::AtomicWord;
531 BrowserThreadGlobals& globals = g_globals.Get();
532 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
533 &globals.thread_delegates[identifier]);
534 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
535 storage, reinterpret_cast<AtomicWord>(delegate));
536
537 // This catches registration when previously registered.
538 DCHECK(!delegate || !old_pointer);
539 }
540
541 } // namespace content
542