Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/browser_thread_impl.h" | 5 #include "content/browser/browser_thread_impl.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| 11 #include "base/atomicops.h" | 11 #include "base/atomicops.h" |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
| 17 #include "base/threading/sequenced_worker_pool.h" | 17 #include "base/threading/sequenced_worker_pool.h" |
| 18 #include "base/threading/thread_restrictions.h" | 18 #include "base/threading/thread_local.h" |
| 19 #include "build/build_config.h" | 19 #include "build/build_config.h" |
| 20 #include "content/public/browser/browser_thread_delegate.h" | 20 #include "content/public/browser/browser_thread_delegate.h" |
| 21 #include "content/public/browser/content_browser_client.h" | 21 #include "content/public/browser/content_browser_client.h" |
| 22 #include "net/disk_cache/simple/simple_backend_impl.h" | 22 #include "net/disk_cache/simple/simple_backend_impl.h" |
| 23 | 23 |
| 24 #if defined(OS_ANDROID) | 24 #if defined(OS_ANDROID) |
| 25 #include "base/android/jni_android.h" | 25 #include "base/android/jni_android.h" |
| 26 #endif | 26 #endif |
| 27 | 27 |
| 28 namespace content { | 28 namespace content { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 // Only atomic operations are used on this array. The delegates are not owned | 110 // Only atomic operations are used on this array. The delegates are not owned |
| 111 // by this array, rather by whoever calls BrowserThread::SetDelegate. | 111 // by this array, rather by whoever calls BrowserThread::SetDelegate. |
| 112 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; | 112 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; |
| 113 | 113 |
| 114 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; | 114 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; |
| 115 }; | 115 }; |
| 116 | 116 |
| 117 base::LazyInstance<BrowserThreadGlobals>::Leaky | 117 base::LazyInstance<BrowserThreadGlobals>::Leaky |
| 118 g_globals = LAZY_INSTANCE_INITIALIZER; | 118 g_globals = LAZY_INSTANCE_INITIALIZER; |
| 119 | 119 |
| 120 base::LazyInstance<base::ThreadLocalPointer<BrowserThreadImpl>>::Leaky | |
| 121 g_browser_thread = LAZY_INSTANCE_INITIALIZER; | |
| 122 | |
| 120 } // namespace | 123 } // namespace |
| 121 | 124 |
| 122 BrowserThreadImpl::BrowserThreadImpl(ID identifier) | 125 BrowserThreadImpl::BrowserThreadImpl(ID identifier) |
| 123 : Thread(g_browser_thread_names[identifier]), | 126 : Thread(g_browser_thread_names[identifier]), |
| 124 identifier_(identifier) { | 127 identifier_(identifier) { |
| 125 Initialize(); | 128 Initialize(); |
| 126 } | 129 } |
| 127 | 130 |
| 128 BrowserThreadImpl::BrowserThreadImpl(ID identifier, | 131 BrowserThreadImpl::BrowserThreadImpl(ID identifier, |
| 129 base::MessageLoop* message_loop) | 132 base::MessageLoop* message_loop) |
| 130 : Thread(message_loop->thread_name()), identifier_(identifier) { | 133 : Thread(message_loop->thread_name()), identifier_(identifier) { |
| 131 set_message_loop(message_loop); | 134 set_message_loop(message_loop); |
| 132 Initialize(); | 135 Initialize(); |
| 136 | |
| 137 if (message_loop == base::MessageLoop::current()) { | |
| 138 // In tests, it's possible for the same current MessageLoop to be assigned | |
| 139 // to multiple BrowserThreadImpls. | |
| 140 if (!g_browser_thread.Get().Get()) | |
| 141 g_browser_thread.Get().Set(this); | |
| 142 } | |
| 133 } | 143 } |
| 134 | 144 |
| 135 // static | 145 // static |
| 136 void BrowserThreadImpl::ShutdownThreadPool() { | 146 void BrowserThreadImpl::ShutdownThreadPool() { |
| 137 // The goal is to make it impossible for chrome to 'infinite loop' during | 147 // The goal is to make it impossible for chrome to 'infinite loop' during |
| 138 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued | 148 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued |
| 139 // during shutdown get run. There's nothing particularly scientific about the | 149 // during shutdown get run. There's nothing particularly scientific about the |
| 140 // number chosen. | 150 // number chosen. |
| 141 const int kMaxNewShutdownBlockingTasks = 1000; | 151 const int kMaxNewShutdownBlockingTasks = 1000; |
| 142 BrowserThreadGlobals& globals = g_globals.Get(); | 152 BrowserThreadGlobals& globals = g_globals.Get(); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 void BrowserThreadImpl::Run(base::MessageLoop* message_loop) { | 232 void BrowserThreadImpl::Run(base::MessageLoop* message_loop) { |
| 223 #if defined(OS_ANDROID) | 233 #if defined(OS_ANDROID) |
| 224 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name. | 234 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name. |
| 225 // Though it may create unnecessary VM thread objects, keeping thread name | 235 // Though it may create unnecessary VM thread objects, keeping thread name |
| 226 // gives more benefit in debugging in the platform. | 236 // gives more benefit in debugging in the platform. |
| 227 if (!thread_name().empty()) { | 237 if (!thread_name().empty()) { |
| 228 base::android::AttachCurrentThreadWithName(thread_name()); | 238 base::android::AttachCurrentThreadWithName(thread_name()); |
| 229 } | 239 } |
| 230 #endif | 240 #endif |
| 231 | 241 |
| 232 BrowserThread::ID thread_id = ID_COUNT; | 242 DCHECK(!g_browser_thread.Get().Get()); |
| 233 if (!GetCurrentThreadIdentifier(&thread_id)) | 243 g_browser_thread.Get().Set(this); |
| 234 return Thread::Run(message_loop); | 244 CHECK_EQ(Thread::message_loop(), message_loop); |
| 235 | 245 |
| 236 switch (thread_id) { | 246 switch (identifier_) { |
| 237 case BrowserThread::UI: | 247 case BrowserThread::UI: |
| 238 return UIThreadRun(message_loop); | 248 return UIThreadRun(message_loop); |
| 239 case BrowserThread::DB: | 249 case BrowserThread::DB: |
| 240 return DBThreadRun(message_loop); | 250 return DBThreadRun(message_loop); |
| 241 case BrowserThread::FILE: | 251 case BrowserThread::FILE: |
| 242 return FileThreadRun(message_loop); | 252 return FileThreadRun(message_loop); |
| 243 case BrowserThread::FILE_USER_BLOCKING: | 253 case BrowserThread::FILE_USER_BLOCKING: |
| 244 return FileUserBlockingThreadRun(message_loop); | 254 return FileUserBlockingThreadRun(message_loop); |
| 245 case BrowserThread::PROCESS_LAUNCHER: | 255 case BrowserThread::PROCESS_LAUNCHER: |
| 246 return ProcessLauncherThreadRun(message_loop); | 256 return ProcessLauncherThreadRun(message_loop); |
| 247 case BrowserThread::CACHE: | 257 case BrowserThread::CACHE: |
| 248 return CacheThreadRun(message_loop); | 258 return CacheThreadRun(message_loop); |
| 249 case BrowserThread::IO: | 259 case BrowserThread::IO: |
| 250 return IOThreadRun(message_loop); | 260 return IOThreadRun(message_loop); |
| 251 case BrowserThread::ID_COUNT: | 261 case BrowserThread::ID_COUNT: |
| 252 CHECK(false); // This shouldn't actually be reached! | 262 CHECK(false); // This shouldn't actually be reached! |
| 253 break; | 263 break; |
| 254 } | 264 } |
| 255 Thread::Run(message_loop); | 265 |
| 266 // |identifier_| must be set to a valid enum value in the constructor, so it | |
| 267 // should be impossible to reach here. | |
| 268 CHECK(false); | |
| 256 } | 269 } |
| 257 | 270 |
| 258 void BrowserThreadImpl::CleanUp() { | 271 void BrowserThreadImpl::CleanUp() { |
| 259 BrowserThreadGlobals& globals = g_globals.Get(); | 272 BrowserThreadGlobals& globals = g_globals.Get(); |
| 260 | 273 |
| 261 using base::subtle::AtomicWord; | 274 using base::subtle::AtomicWord; |
| 262 AtomicWord* storage = | 275 AtomicWord* storage = |
| 263 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); | 276 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); |
| 264 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); | 277 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); |
| 265 BrowserThreadDelegate* delegate = | 278 BrowserThreadDelegate* delegate = |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 287 BrowserThreadGlobals& globals = g_globals.Get(); | 300 BrowserThreadGlobals& globals = g_globals.Get(); |
| 288 base::AutoLock lock(globals.lock); | 301 base::AutoLock lock(globals.lock); |
| 289 globals.threads[identifier_] = NULL; | 302 globals.threads[identifier_] = NULL; |
| 290 #ifndef NDEBUG | 303 #ifndef NDEBUG |
| 291 // Double check that the threads are ordered correctly in the enumeration. | 304 // Double check that the threads are ordered correctly in the enumeration. |
| 292 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { | 305 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { |
| 293 DCHECK(!globals.threads[i]) << | 306 DCHECK(!globals.threads[i]) << |
| 294 "Threads must be listed in the reverse order that they die"; | 307 "Threads must be listed in the reverse order that they die"; |
| 295 } | 308 } |
| 296 #endif | 309 #endif |
| 310 | |
| 311 if (g_browser_thread.Get().Get() == this) | |
|
kinuko
2016/01/08 11:35:50
Is this condition for tests?
Anand Mistry (off Chromium)
2016/01/10 23:18:28
This is for the main/UI thread, where a BrowserThr
kinuko
2016/01/11 03:52:22
I see thanks, could we add a short comment about t
| |
| 312 g_browser_thread.Get().Set(nullptr); | |
| 297 } | 313 } |
| 298 | 314 |
| 299 bool BrowserThreadImpl::StartWithOptions(const Options& options) { | 315 bool BrowserThreadImpl::StartWithOptions(const Options& options) { |
| 300 // The global thread table needs to be locked while a new thread is | 316 // The global thread table needs to be locked while a new thread is |
| 301 // starting, as the new thread can asynchronously start touching the | 317 // starting, as the new thread can asynchronously start touching the |
| 302 // table (and other thread's message_loop). | 318 // table (and other thread's message_loop). |
| 303 BrowserThreadGlobals& globals = g_globals.Get(); | 319 BrowserThreadGlobals& globals = g_globals.Get(); |
| 304 base::AutoLock lock(globals.lock); | 320 base::AutoLock lock(globals.lock); |
| 305 return Thread::StartWithOptions(options); | 321 return Thread::StartWithOptions(options); |
| 306 } | 322 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 return false; | 407 return false; |
| 392 | 408 |
| 393 BrowserThreadGlobals& globals = g_globals.Get(); | 409 BrowserThreadGlobals& globals = g_globals.Get(); |
| 394 base::AutoLock lock(globals.lock); | 410 base::AutoLock lock(globals.lock); |
| 395 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 411 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 396 return globals.threads[identifier] != NULL; | 412 return globals.threads[identifier] != NULL; |
| 397 } | 413 } |
| 398 | 414 |
| 399 // static | 415 // static |
| 400 bool BrowserThread::CurrentlyOn(ID identifier) { | 416 bool BrowserThread::CurrentlyOn(ID identifier) { |
| 401 // We shouldn't use MessageLoop::current() since it uses LazyInstance which | |
| 402 // may be deleted by ~AtExitManager when a WorkerPool thread calls this | |
| 403 // function. | |
| 404 // http://crbug.com/63678 | |
| 405 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; | |
| 406 BrowserThreadGlobals& globals = g_globals.Get(); | 417 BrowserThreadGlobals& globals = g_globals.Get(); |
| 407 base::AutoLock lock(globals.lock); | 418 base::AutoLock lock(globals.lock); |
| 408 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 419 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 409 return globals.threads[identifier] && | 420 return globals.threads[identifier] && |
| 410 globals.threads[identifier]->message_loop() == | 421 globals.threads[identifier]->message_loop() == |
| 411 base::MessageLoop::current(); | 422 base::MessageLoop::current(); |
| 412 } | 423 } |
| 413 | 424 |
| 414 static const char* GetThreadName(BrowserThread::ID thread) { | 425 static const char* GetThreadName(BrowserThread::ID thread) { |
| 415 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) | 426 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 492 const base::Closure& task, | 503 const base::Closure& task, |
| 493 const base::Closure& reply) { | 504 const base::Closure& reply) { |
| 494 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, | 505 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, |
| 495 task, | 506 task, |
| 496 reply); | 507 reply); |
| 497 } | 508 } |
| 498 | 509 |
| 499 // static | 510 // static |
| 500 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { | 511 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { |
| 501 if (g_globals == NULL) | 512 if (g_globals == NULL) |
| 502 return false; | 513 return false; |
|
kinuko
2016/01/08 11:35:50
Do we still need to check this?
Anand Mistry (off Chromium)
2016/01/10 23:18:28
Nope. Removed.
| |
| 503 | 514 |
| 504 // We shouldn't use MessageLoop::current() since it uses LazyInstance which | 515 BrowserThreadImpl* browser_thread = g_browser_thread.Get().Get(); |
| 505 // may be deleted by ~AtExitManager when a WorkerPool thread calls this | 516 if (!browser_thread) |
| 506 // function. | 517 return false; |
| 507 // http://crbug.com/63678 | |
| 508 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; | |
| 509 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); | |
| 510 BrowserThreadGlobals& globals = g_globals.Get(); | |
| 511 for (int i = 0; i < ID_COUNT; ++i) { | |
| 512 if (globals.threads[i] && | |
| 513 globals.threads[i]->message_loop() == cur_message_loop) { | |
| 514 *identifier = globals.threads[i]->identifier_; | |
| 515 return true; | |
| 516 } | |
| 517 } | |
| 518 | 518 |
| 519 return false; | 519 *identifier = browser_thread->identifier_; |
| 520 return true; | |
| 520 } | 521 } |
| 521 | 522 |
| 522 // static | 523 // static |
| 523 scoped_refptr<base::SingleThreadTaskRunner> | 524 scoped_refptr<base::SingleThreadTaskRunner> |
| 524 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { | 525 BrowserThread::GetMessageLoopProxyForThread(ID identifier) { |
| 525 return g_task_runners.Get().proxies[identifier]; | 526 return g_task_runners.Get().proxies[identifier]; |
| 526 } | 527 } |
| 527 | 528 |
| 528 // static | 529 // static |
| 529 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { | 530 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 546 AtomicWord* storage = reinterpret_cast<AtomicWord*>( | 547 AtomicWord* storage = reinterpret_cast<AtomicWord*>( |
| 547 &globals.thread_delegates[identifier]); | 548 &globals.thread_delegates[identifier]); |
| 548 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( | 549 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( |
| 549 storage, reinterpret_cast<AtomicWord>(delegate)); | 550 storage, reinterpret_cast<AtomicWord>(delegate)); |
| 550 | 551 |
| 551 // This catches registration when previously registered. | 552 // This catches registration when previously registered. |
| 552 DCHECK(!delegate || !old_pointer); | 553 DCHECK(!delegate || !old_pointer); |
| 553 } | 554 } |
| 554 | 555 |
| 555 } // namespace content | 556 } // namespace content |
| OLD | NEW |