Add ICU message format support
[chromium-blink-merge.git] / content / browser / browser_thread_impl.cc
blobb0a24ae06c0e135ef1132d93fd954f076fc5b0a8
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"
7 #include <string>
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"
22 #endif
24 namespace content {
26 namespace {
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 {
42 public:
43 explicit BrowserThreadTaskRunner(BrowserThread::ID identifier)
44 : 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,
57 delay);
60 bool RunsTasksOnCurrentThread() const override {
61 return BrowserThread::CurrentlyOn(id_);
64 protected:
65 ~BrowserThreadTaskRunner() override {}
67 private:
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) {
77 proxies[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.
98 base::Lock 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;
116 } // namespace
118 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
119 : Thread(g_browser_thread_names[identifier]),
120 identifier_(identifier) {
121 Initialize();
124 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
125 base::MessageLoop* message_loop)
126 : Thread(message_loop->thread_name()), identifier_(identifier) {
127 set_message_loop(message_loop);
128 Initialize();
131 // static
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
136 // number chosen.
137 const int kMaxNewShutdownBlockingTasks = 1000;
138 BrowserThreadGlobals& globals = g_globals.Get();
139 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
142 // static
143 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
144 // We don't want to create a pool if none exists.
145 if (g_globals == NULL)
146 return;
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);
160 if (delegate)
161 delegate->Init();
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);
215 MSVC_POP_WARNING()
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());
226 #endif
228 BrowserThread::ID thread_id = ID_COUNT;
229 if (!GetCurrentThreadIdentifier(&thread_id))
230 return Thread::Run(message_loop);
232 switch (thread_id) {
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!
249 break;
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);
264 if (delegate)
265 delegate->CleanUp();
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.
281 Stop();
283 BrowserThreadGlobals& globals = g_globals.Get();
284 base::AutoLock lock(globals.lock);
285 globals.threads[identifier_] = NULL;
286 #ifndef NDEBUG
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";
292 #endif
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);
304 // static
305 bool BrowserThreadImpl::PostTaskHelper(
306 BrowserThread::ID identifier,
307 const tracked_objects::Location& from_here,
308 const base::Closure& task,
309 base::TimeDelta delay,
310 bool nestable) {
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(&current_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()
329 : NULL;
330 if (message_loop) {
331 if (nestable) {
332 message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
333 } else {
334 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task,
335 delay);
339 if (!target_thread_outlives_current)
340 globals.lock.Release();
342 return !!message_loop;
345 // static
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);
352 // static
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);
361 // static
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);
370 // static
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,
376 task);
379 // static
380 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
381 return g_globals.Get().blocking_pool.get();
384 // static
385 bool BrowserThread::IsThreadInitialized(ID identifier) {
386 if (g_globals == NULL)
387 return false;
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;
395 // static
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
399 // function.
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";
418 // static
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;
432 result += ".";
433 return result;
436 // static
437 bool BrowserThread::IsMessageLoopValid(ID identifier) {
438 if (g_globals == NULL)
439 return false;
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();
448 // static
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);
456 // static
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);
465 // static
466 bool BrowserThread::PostNonNestableTask(
467 ID identifier,
468 const tracked_objects::Location& from_here,
469 const base::Closure& task) {
470 return BrowserThreadImpl::PostTaskHelper(
471 identifier, from_here, task, base::TimeDelta(), false);
474 // static
475 bool BrowserThread::PostNonNestableDelayedTask(
476 ID identifier,
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);
484 // static
485 bool BrowserThread::PostTaskAndReply(
486 ID identifier,
487 const tracked_objects::Location& from_here,
488 const base::Closure& task,
489 const base::Closure& reply) {
490 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
491 task,
492 reply);
495 // static
496 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
497 if (g_globals == NULL)
498 return false;
500 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
501 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
502 // function.
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_;
511 return true;
515 return false;
518 // static
519 scoped_refptr<base::SingleThreadTaskRunner>
520 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
521 return g_task_runners.Get().proxies[identifier];
524 // static
525 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
526 if (g_globals == NULL)
527 return NULL;
529 BrowserThreadGlobals& globals = g_globals.Get();
530 base::AutoLock lock(globals.lock);
531 base::Thread* thread = globals.threads[identifier];
532 DCHECK(thread);
533 base::MessageLoop* loop = thread->message_loop();
534 return loop;
537 // static
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