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 |