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 |