| 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/profiler/scoped_tracker.h" |
| 16 #include "base/single_thread_task_runner.h" | 17 #include "base/single_thread_task_runner.h" |
| 17 #include "base/threading/sequenced_worker_pool.h" | 18 #include "base/threading/sequenced_worker_pool.h" |
| 18 #include "base/threading/thread_restrictions.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 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 #if defined(OS_ANDROID) | 223 #if defined(OS_ANDROID) |
| 224 // Not to reset thread name to "Thread-???" by VM, attach VM with thread name. | 224 // 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 | 225 // Though it may create unnecessary VM thread objects, keeping thread name |
| 226 // gives more benefit in debugging in the platform. | 226 // gives more benefit in debugging in the platform. |
| 227 if (!thread_name().empty()) { | 227 if (!thread_name().empty()) { |
| 228 base::android::AttachCurrentThreadWithName(thread_name()); | 228 base::android::AttachCurrentThreadWithName(thread_name()); |
| 229 } | 229 } |
| 230 #endif | 230 #endif |
| 231 | 231 |
| 232 BrowserThread::ID thread_id = ID_COUNT; | 232 BrowserThread::ID thread_id = ID_COUNT; |
| 233 if (!GetCurrentThreadIdentifier(&thread_id)) | 233 CHECK(GetCurrentThreadIdentifier(&thread_id)); |
| 234 return Thread::Run(message_loop); | 234 CHECK_EQ(identifier_, thread_id); |
| 235 CHECK_EQ(Thread::message_loop(), message_loop); |
| 235 | 236 |
| 236 switch (thread_id) { | 237 switch (identifier_) { |
| 237 case BrowserThread::UI: | 238 case BrowserThread::UI: |
| 238 return UIThreadRun(message_loop); | 239 return UIThreadRun(message_loop); |
| 239 case BrowserThread::DB: | 240 case BrowserThread::DB: |
| 240 return DBThreadRun(message_loop); | 241 return DBThreadRun(message_loop); |
| 241 case BrowserThread::FILE: | 242 case BrowserThread::FILE: |
| 242 return FileThreadRun(message_loop); | 243 return FileThreadRun(message_loop); |
| 243 case BrowserThread::FILE_USER_BLOCKING: | 244 case BrowserThread::FILE_USER_BLOCKING: |
| 244 return FileUserBlockingThreadRun(message_loop); | 245 return FileUserBlockingThreadRun(message_loop); |
| 245 case BrowserThread::PROCESS_LAUNCHER: | 246 case BrowserThread::PROCESS_LAUNCHER: |
| 246 return ProcessLauncherThreadRun(message_loop); | 247 return ProcessLauncherThreadRun(message_loop); |
| 247 case BrowserThread::CACHE: | 248 case BrowserThread::CACHE: |
| 248 return CacheThreadRun(message_loop); | 249 return CacheThreadRun(message_loop); |
| 249 case BrowserThread::IO: | 250 case BrowserThread::IO: |
| 250 return IOThreadRun(message_loop); | 251 return IOThreadRun(message_loop); |
| 251 case BrowserThread::ID_COUNT: | 252 case BrowserThread::ID_COUNT: |
| 252 CHECK(false); // This shouldn't actually be reached! | 253 CHECK(false); // This shouldn't actually be reached! |
| 253 break; | 254 break; |
| 254 } | 255 } |
| 255 Thread::Run(message_loop); | 256 |
| 257 // |identifier_| must be set to a valid enum value in the constructor, so it |
| 258 // should be impossible to reach here. |
| 259 CHECK(false); |
| 256 } | 260 } |
| 257 | 261 |
| 258 void BrowserThreadImpl::CleanUp() { | 262 void BrowserThreadImpl::CleanUp() { |
| 259 BrowserThreadGlobals& globals = g_globals.Get(); | 263 BrowserThreadGlobals& globals = g_globals.Get(); |
| 260 | 264 |
| 261 using base::subtle::AtomicWord; | 265 using base::subtle::AtomicWord; |
| 262 AtomicWord* storage = | 266 AtomicWord* storage = |
| 263 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); | 267 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); |
| 264 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); | 268 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); |
| 265 BrowserThreadDelegate* delegate = | 269 BrowserThreadDelegate* delegate = |
| 266 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); | 270 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); |
| 267 | 271 |
| 268 if (delegate) | 272 if (delegate) |
| 269 delegate->CleanUp(); | 273 delegate->CleanUp(); |
| 274 |
| 275 // PostTaskHelper() accesses the message loop while holding this lock. |
| 276 // However, the message loop will soon be destructed without any locking. So |
| 277 // to prevent a race with accessing the message loop in PostTaskHelper(), |
| 278 // remove this thread from the global array now. |
| 279 base::AutoLock lock(globals.lock); |
| 280 globals.threads[identifier_] = NULL; |
| 270 } | 281 } |
| 271 | 282 |
| 272 void BrowserThreadImpl::Initialize() { | 283 void BrowserThreadImpl::Initialize() { |
| 273 BrowserThreadGlobals& globals = g_globals.Get(); | 284 BrowserThreadGlobals& globals = g_globals.Get(); |
| 274 | 285 |
| 275 base::AutoLock lock(globals.lock); | 286 base::AutoLock lock(globals.lock); |
| 276 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); | 287 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); |
| 277 DCHECK(globals.threads[identifier_] == NULL); | 288 DCHECK(globals.threads[identifier_] == NULL); |
| 278 globals.threads[identifier_] = this; | 289 globals.threads[identifier_] = this; |
| 279 } | 290 } |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 return false; | 402 return false; |
| 392 | 403 |
| 393 BrowserThreadGlobals& globals = g_globals.Get(); | 404 BrowserThreadGlobals& globals = g_globals.Get(); |
| 394 base::AutoLock lock(globals.lock); | 405 base::AutoLock lock(globals.lock); |
| 395 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 406 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 396 return globals.threads[identifier] != NULL; | 407 return globals.threads[identifier] != NULL; |
| 397 } | 408 } |
| 398 | 409 |
| 399 // static | 410 // static |
| 400 bool BrowserThread::CurrentlyOn(ID identifier) { | 411 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(); | 412 BrowserThreadGlobals& globals = g_globals.Get(); |
| 407 base::AutoLock lock(globals.lock); | 413 base::AutoLock lock(globals.lock); |
| 408 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 414 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 409 return globals.threads[identifier] && | 415 return globals.threads[identifier] && |
| 410 globals.threads[identifier]->message_loop() == | 416 globals.threads[identifier]->message_loop() == |
| 411 base::MessageLoop::current(); | 417 base::MessageLoop::current(); |
| 412 } | 418 } |
| 413 | 419 |
| 414 static const char* GetThreadName(BrowserThread::ID thread) { | 420 static const char* GetThreadName(BrowserThread::ID thread) { |
| 415 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) | 421 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 494 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, | 500 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, |
| 495 task, | 501 task, |
| 496 reply); | 502 reply); |
| 497 } | 503 } |
| 498 | 504 |
| 499 // static | 505 // static |
| 500 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { | 506 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { |
| 501 if (g_globals == NULL) | 507 if (g_globals == NULL) |
| 502 return false; | 508 return false; |
| 503 | 509 |
| 504 // We shouldn't use MessageLoop::current() since it uses LazyInstance which | |
| 505 // may be deleted by ~AtExitManager when a WorkerPool thread calls this | |
| 506 // function. | |
| 507 // http://crbug.com/63678 | |
| 508 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; | |
| 509 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); | 510 base::MessageLoop* cur_message_loop = base::MessageLoop::current(); |
| 510 BrowserThreadGlobals& globals = g_globals.Get(); | 511 BrowserThreadGlobals& globals = g_globals.Get(); |
| 512 // Profiler to track potential contention on |globals.lock|. This only does |
| 513 // real work on canary and local dev builds, so the cost of having this here |
| 514 // should be minimal. |
| 515 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); |
| 516 base::AutoLock lock(globals.lock); |
| 511 for (int i = 0; i < ID_COUNT; ++i) { | 517 for (int i = 0; i < ID_COUNT; ++i) { |
| 512 if (globals.threads[i] && | 518 if (globals.threads[i] && |
| 513 globals.threads[i]->message_loop() == cur_message_loop) { | 519 globals.threads[i]->message_loop() == cur_message_loop) { |
| 514 *identifier = globals.threads[i]->identifier_; | 520 *identifier = globals.threads[i]->identifier_; |
| 515 return true; | 521 return true; |
| 516 } | 522 } |
| 517 } | 523 } |
| 518 | 524 |
| 519 return false; | 525 return false; |
| 520 } | 526 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 546 AtomicWord* storage = reinterpret_cast<AtomicWord*>( | 552 AtomicWord* storage = reinterpret_cast<AtomicWord*>( |
| 547 &globals.thread_delegates[identifier]); | 553 &globals.thread_delegates[identifier]); |
| 548 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( | 554 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( |
| 549 storage, reinterpret_cast<AtomicWord>(delegate)); | 555 storage, reinterpret_cast<AtomicWord>(delegate)); |
| 550 | 556 |
| 551 // This catches registration when previously registered. | 557 // This catches registration when previously registered. |
| 552 DCHECK(!delegate || !old_pointer); | 558 DCHECK(!delegate || !old_pointer); |
| 553 } | 559 } |
| 554 | 560 |
| 555 } // namespace content | 561 } // namespace content |
| OLD | NEW |