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
19 #if defined(OS_ANDROID)
20 #include "base/android/jni_android.h"
21 #endif
22
23 namespace content {
24
25 namespace {
26
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
36 };
37
38 // An implementation of MessageLoopProxy to be used in conjunction
39 // with BrowserThread.
40 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
41 public:
BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)42 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
43 : id_(identifier) {
44 }
45
46 // MessageLoopProxy implementation.
PostDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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);
51 }
52
PostNonNestableDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta 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,
58 delay);
59 }
60
RunsTasksOnCurrentThread() const61 virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
62 return BrowserThread::CurrentlyOn(id_);
63 }
64
65 protected:
~BrowserThreadMessageLoopProxy()66 virtual ~BrowserThreadMessageLoopProxy() {}
67
68 private:
69 BrowserThread::ID id_;
70 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
71 };
72
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 {
BrowserThreadProxiescontent::__anonbf31eb0c0111::BrowserThreadProxies76 BrowserThreadProxies() {
77 for (int i = 0; i < BrowserThread::ID_COUNT; ++i) {
78 proxies[i] =
79 new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID>(i));
80 }
81 }
82
83 scoped_refptr<base::MessageLoopProxy> proxies[BrowserThread::ID_COUNT];
84 };
85
86 base::LazyInstance<BrowserThreadProxies>::Leaky
87 g_proxies = LAZY_INSTANCE_INITIALIZER;
88
89 struct BrowserThreadGlobals {
BrowserThreadGlobalscontent::__anonbf31eb0c0111::BrowserThreadGlobals90 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]));
95 }
96
97 // This lock protects |threads|. Do not read or modify that array
98 // without holding this lock. Do not block while holding this lock.
99 base::Lock lock;
100
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];
106
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];
110
111 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
112 };
113
114 base::LazyInstance<BrowserThreadGlobals>::Leaky
115 g_globals = LAZY_INSTANCE_INITIALIZER;
116
117 } // namespace
118
BrowserThreadImpl(ID identifier)119 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
120 : Thread(g_browser_thread_names[identifier]),
121 identifier_(identifier) {
122 Initialize();
123 }
124
BrowserThreadImpl(ID identifier,base::MessageLoop * message_loop)125 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
126 base::MessageLoop* message_loop)
127 : Thread(message_loop->thread_name()), identifier_(identifier) {
128 set_message_loop(message_loop);
129 Initialize();
130 }
131
132 // static
ShutdownThreadPool()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
137 // number chosen.
138 const int kMaxNewShutdownBlockingTasks = 1000;
139 BrowserThreadGlobals& globals = g_globals.Get();
140 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
141 }
142
143 // static
FlushThreadPoolHelper()144 void BrowserThreadImpl::FlushThreadPoolHelper() {
145 // We don't want to create a pool if none exists.
146 if (g_globals == NULL)
147 return;
148 g_globals.Get().blocking_pool->FlushForTesting();
149 }
150
Init()151 void BrowserThreadImpl::Init() {
152 BrowserThreadGlobals& globals = g_globals.Get();
153
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);
160 if (delegate) {
161 delegate->Init();
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)));
167 }
168 }
169
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)
174
UIThreadRun(base::MessageLoop * message_loop)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);
179 }
180
DBThreadRun(base::MessageLoop * message_loop)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);
185 }
186
FileThreadRun(base::MessageLoop * message_loop)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);
192 }
193
FileUserBlockingThreadRun(base::MessageLoop * message_loop)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);
199 }
200
ProcessLauncherThreadRun(base::MessageLoop * message_loop)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);
206 }
207
CacheThreadRun(base::MessageLoop * message_loop)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);
213 }
214
IOThreadRun(base::MessageLoop * message_loop)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);
219 }
220
221 MSVC_POP_WARNING()
222 MSVC_ENABLE_OPTIMIZE();
223
Run(base::MessageLoop * message_loop)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());
231 }
232 #endif
233
234 BrowserThread::ID thread_id = ID_COUNT;
235 if (!GetCurrentThreadIdentifier(&thread_id))
236 return Thread::Run(message_loop);
237
238 switch (thread_id) {
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!
255 break;
256 }
257 Thread::Run(message_loop);
258 }
259
CleanUp()260 void BrowserThreadImpl::CleanUp() {
261 BrowserThreadGlobals& globals = g_globals.Get();
262
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);
269
270 if (delegate)
271 delegate->CleanUp();
272 }
273
Initialize()274 void BrowserThreadImpl::Initialize() {
275 BrowserThreadGlobals& globals = g_globals.Get();
276
277 base::AutoLock lock(globals.lock);
278 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
279 DCHECK(globals.threads[identifier_] == NULL);
280 globals.threads[identifier_] = this;
281 }
282
~BrowserThreadImpl()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.
287 Stop();
288
289 BrowserThreadGlobals& globals = g_globals.Get();
290 base::AutoLock lock(globals.lock);
291 globals.threads[identifier_] = NULL;
292 #ifndef NDEBUG
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";
297 }
298 #endif
299 }
300
301 // static
PostTaskHelper(BrowserThread::ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay,bool nestable)302 bool BrowserThreadImpl::PostTaskHelper(
303 BrowserThread::ID identifier,
304 const tracked_objects::Location& from_here,
305 const base::Closure& task,
306 base::TimeDelta delay,
307 bool nestable) {
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;
319
320 BrowserThreadGlobals& globals = g_globals.Get();
321 if (!target_thread_outlives_current)
322 globals.lock.Acquire();
323
324 base::MessageLoop* message_loop =
325 globals.threads[identifier] ? globals.threads[identifier]->message_loop()
326 : NULL;
327 if (message_loop) {
328 if (nestable) {
329 message_loop->PostDelayedTask(from_here, task, delay);
330 } else {
331 message_loop->PostNonNestableDelayedTask(from_here, task, delay);
332 }
333 }
334
335 if (!target_thread_outlives_current)
336 globals.lock.Release();
337
338 return !!message_loop;
339 }
340
341 // static
PostBlockingPoolTask(const tracked_objects::Location & from_here,const base::Closure & task)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);
346 }
347
348 // static
PostBlockingPoolTaskAndReply(const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)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);
355 }
356
357 // static
PostBlockingPoolSequencedTask(const std::string & sequence_token_name,const tracked_objects::Location & from_here,const base::Closure & task)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);
364 }
365
366 // static
GetBlockingPool()367 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
368 return g_globals.Get().blocking_pool.get();
369 }
370
371 // static
IsThreadInitialized(ID identifier)372 bool BrowserThread::IsThreadInitialized(ID identifier) {
373 if (g_globals == NULL)
374 return false;
375
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;
380 }
381
382 // static
CurrentlyOn(ID identifier)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
386 // function.
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();
395 }
396
GetThreadName(BrowserThread::ID thread)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";
403 }
404
405 // static
GetDCheckCurrentlyOnErrorMessage(ID expected)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);
415 }
416 std::string result = "Must be called on ";
417 result += GetThreadName(expected);
418 result += "; actually called on ";
419 result += actual_name;
420 result += ".";
421 return result;
422 }
423
424 // static
IsMessageLoopValid(ID identifier)425 bool BrowserThread::IsMessageLoopValid(ID identifier) {
426 if (g_globals == NULL)
427 return false;
428
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();
434 }
435
436 // static
PostTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)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);
442 }
443
444 // static
PostDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)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);
451 }
452
453 // static
PostNonNestableTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task)454 bool BrowserThread::PostNonNestableTask(
455 ID identifier,
456 const tracked_objects::Location& from_here,
457 const base::Closure& task) {
458 return BrowserThreadImpl::PostTaskHelper(
459 identifier, from_here, task, base::TimeDelta(), false);
460 }
461
462 // static
PostNonNestableDelayedTask(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)463 bool BrowserThread::PostNonNestableDelayedTask(
464 ID identifier,
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);
470 }
471
472 // static
PostTaskAndReply(ID identifier,const tracked_objects::Location & from_here,const base::Closure & task,const base::Closure & reply)473 bool BrowserThread::PostTaskAndReply(
474 ID identifier,
475 const tracked_objects::Location& from_here,
476 const base::Closure& task,
477 const base::Closure& reply) {
478 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
479 task,
480 reply);
481 }
482
483 // static
GetCurrentThreadIdentifier(ID * identifier)484 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
485 if (g_globals == NULL)
486 return false;
487
488 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
489 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
490 // function.
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_;
499 return true;
500 }
501 }
502
503 return false;
504 }
505
506 // static
507 scoped_refptr<base::MessageLoopProxy>
GetMessageLoopProxyForThread(ID identifier)508 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
509 return g_proxies.Get().proxies[identifier];
510 }
511
512 // static
UnsafeGetMessageLoopForThread(ID identifier)513 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
514 if (g_globals == NULL)
515 return NULL;
516
517 BrowserThreadGlobals& globals = g_globals.Get();
518 base::AutoLock lock(globals.lock);
519 base::Thread* thread = globals.threads[identifier];
520 DCHECK(thread);
521 base::MessageLoop* loop = thread->message_loop();
522 return loop;
523 }
524
525 // static
SetDelegate(ID identifier,BrowserThreadDelegate * delegate)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));
534
535 // This catches registration when previously registered.
536 DCHECK(!delegate || !old_pointer);
537 }
538
539 } // namespace content
540