| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/lazy_instance.h" |
| 8 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 9 #include "base/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
| 10 #include "base/threading/thread_restrictions.h" | 11 #include "base/threading/thread_restrictions.h" |
| 11 | 12 |
| 12 namespace { | 13 namespace { |
| 13 | 14 |
| 14 // Friendly names for the well-known threads. | 15 // Friendly names for the well-known threads. |
| 15 static const char* browser_thread_names[content::BrowserThread::ID_COUNT] = { | 16 static const char* browser_thread_names[content::BrowserThread::ID_COUNT] = { |
| 16 "", // UI (name assembled in browser_main.cc). | 17 "", // UI (name assembled in browser_main.cc). |
| 17 "Chrome_DBThread", // DB | 18 "Chrome_DBThread", // DB |
| 18 "Chrome_WebKitThread", // WEBKIT | 19 "Chrome_WebKitThread", // WEBKIT |
| 19 "Chrome_FileThread", // FILE | 20 "Chrome_FileThread", // FILE |
| 20 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER | 21 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER |
| 21 "Chrome_CacheThread", // CACHE | 22 "Chrome_CacheThread", // CACHE |
| 22 "Chrome_IOThread", // IO | 23 "Chrome_IOThread", // IO |
| 23 #if defined(OS_CHROMEOS) | 24 #if defined(OS_CHROMEOS) |
| 24 "Chrome_WebSocketproxyThread", // WEB_SOCKET_PROXY | 25 "Chrome_WebSocketproxyThread", // WEB_SOCKET_PROXY |
| 25 #endif | 26 #endif |
| 26 }; | 27 }; |
| 27 | 28 |
| 28 } // namespace | 29 } // namespace |
| 29 | 30 |
| 30 namespace content { | 31 namespace content { |
| 31 | 32 |
| 32 base::Lock BrowserThreadImpl::lock_; | 33 namespace { |
| 33 | 34 |
| 34 BrowserThread* BrowserThreadImpl::browser_threads_[ID_COUNT]; | 35 // This lock protects |g_browser_threads|. Do not read or modify that array |
| 36 // without holding this lock. Do not block while holding this lock. |
| 37 base::LazyInstance<base::Lock, |
| 38 base::LeakyLazyInstanceTraits<base::Lock> > |
| 39 g_lock(base::LINKER_INITIALIZED); |
| 40 |
| 41 |
| 42 // An array of the BrowserThread objects. This array is protected by |g_lock|. |
| 43 // The threads are not owned by this array. Typically, the threads are owned |
| 44 // on the UI thread by the g_browser_process object. BrowserThreads remove |
| 45 // themselves from this array upon destruction. |
| 46 BrowserThread* g_browser_threads[BrowserThread::ID_COUNT]; |
| 47 |
| 48 } // namespace |
| 35 | 49 |
| 36 BrowserThreadImpl::BrowserThreadImpl(BrowserThread::ID identifier) | 50 BrowserThreadImpl::BrowserThreadImpl(BrowserThread::ID identifier) |
| 37 : BrowserThread(identifier) { | 51 : BrowserThread(identifier) { |
| 38 } | 52 } |
| 39 | 53 |
| 40 BrowserThreadImpl::BrowserThreadImpl(BrowserThread::ID identifier, | 54 BrowserThreadImpl::BrowserThreadImpl(BrowserThread::ID identifier, |
| 41 MessageLoop* message_loop) | 55 MessageLoop* message_loop) |
| 42 : BrowserThread(identifier, message_loop) { | 56 : BrowserThread(identifier, message_loop) { |
| 43 } | 57 } |
| 44 | 58 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 59 // outlives this one. | 73 // outlives this one. |
| 60 // Note: since the array is so small, ok to loop instead of creating a map, | 74 // Note: since the array is so small, ok to loop instead of creating a map, |
| 61 // which would require a lock because std::map isn't thread safe, defeating | 75 // which would require a lock because std::map isn't thread safe, defeating |
| 62 // the whole purpose of this optimization. | 76 // the whole purpose of this optimization. |
| 63 BrowserThread::ID current_thread; | 77 BrowserThread::ID current_thread; |
| 64 bool guaranteed_to_outlive_target_thread = | 78 bool guaranteed_to_outlive_target_thread = |
| 65 GetCurrentThreadIdentifier(¤t_thread) && | 79 GetCurrentThreadIdentifier(¤t_thread) && |
| 66 current_thread >= identifier; | 80 current_thread >= identifier; |
| 67 | 81 |
| 68 if (!guaranteed_to_outlive_target_thread) | 82 if (!guaranteed_to_outlive_target_thread) |
| 69 BrowserThreadImpl::lock_.Acquire(); | 83 g_lock.Get().Acquire(); |
| 70 | 84 |
| 71 MessageLoop* message_loop = BrowserThreadImpl::browser_threads_[identifier] ? | 85 MessageLoop* message_loop = g_browser_threads[identifier] ? |
| 72 BrowserThreadImpl::browser_threads_[identifier]->message_loop() : NULL; | 86 g_browser_threads[identifier]->message_loop() : NULL; |
| 73 if (message_loop) { | 87 if (message_loop) { |
| 74 if (nestable) { | 88 if (nestable) { |
| 75 message_loop->PostDelayedTask(from_here, task, delay_ms); | 89 message_loop->PostDelayedTask(from_here, task, delay_ms); |
| 76 } else { | 90 } else { |
| 77 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); | 91 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); |
| 78 } | 92 } |
| 79 } | 93 } |
| 80 | 94 |
| 81 if (!guaranteed_to_outlive_target_thread) | 95 if (!guaranteed_to_outlive_target_thread) |
| 82 BrowserThreadImpl::lock_.Release(); | 96 g_lock.Get().Release(); |
| 83 | 97 |
| 84 if (!message_loop) | 98 if (!message_loop) |
| 85 delete task; | 99 delete task; |
| 86 | 100 |
| 87 return !!message_loop; | 101 return !!message_loop; |
| 88 } | 102 } |
| 89 | 103 |
| 90 // static | 104 // static |
| 91 bool BrowserThreadImpl::PostTaskHelper( | 105 bool BrowserThreadImpl::PostTaskHelper( |
| 92 BrowserThread::ID identifier, | 106 BrowserThread::ID identifier, |
| 93 const tracked_objects::Location& from_here, | 107 const tracked_objects::Location& from_here, |
| 94 const base::Closure& task, | 108 const base::Closure& task, |
| 95 int64 delay_ms, | 109 int64 delay_ms, |
| 96 bool nestable) { | 110 bool nestable) { |
| 97 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 111 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 98 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in | 112 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in |
| 99 // order of lifetime. So no need to lock if we know that the other thread | 113 // order of lifetime. So no need to lock if we know that the other thread |
| 100 // outlives this one. | 114 // outlives this one. |
| 101 // Note: since the array is so small, ok to loop instead of creating a map, | 115 // Note: since the array is so small, ok to loop instead of creating a map, |
| 102 // which would require a lock because std::map isn't thread safe, defeating | 116 // which would require a lock because std::map isn't thread safe, defeating |
| 103 // the whole purpose of this optimization. | 117 // the whole purpose of this optimization. |
| 104 BrowserThread::ID current_thread; | 118 BrowserThread::ID current_thread; |
| 105 bool guaranteed_to_outlive_target_thread = | 119 bool guaranteed_to_outlive_target_thread = |
| 106 GetCurrentThreadIdentifier(¤t_thread) && | 120 GetCurrentThreadIdentifier(¤t_thread) && |
| 107 current_thread >= identifier; | 121 current_thread >= identifier; |
| 108 | 122 |
| 109 if (!guaranteed_to_outlive_target_thread) | 123 if (!guaranteed_to_outlive_target_thread) |
| 110 lock_.Acquire(); | 124 g_lock.Get().Acquire(); |
| 111 | 125 |
| 112 MessageLoop* message_loop = browser_threads_[identifier] ? | 126 MessageLoop* message_loop = g_browser_threads[identifier] ? |
| 113 browser_threads_[identifier]->message_loop() : NULL; | 127 g_browser_threads[identifier]->message_loop() : NULL; |
| 114 if (message_loop) { | 128 if (message_loop) { |
| 115 if (nestable) { | 129 if (nestable) { |
| 116 message_loop->PostDelayedTask(from_here, task, delay_ms); | 130 message_loop->PostDelayedTask(from_here, task, delay_ms); |
| 117 } else { | 131 } else { |
| 118 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); | 132 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); |
| 119 } | 133 } |
| 120 } | 134 } |
| 121 | 135 |
| 122 if (!guaranteed_to_outlive_target_thread) | 136 if (!guaranteed_to_outlive_target_thread) |
| 123 lock_.Release(); | 137 g_lock.Get().Release(); |
| 124 | 138 |
| 125 return !!message_loop; | 139 return !!message_loop; |
| 126 } | 140 } |
| 127 | 141 |
| 128 // TODO(joi): Remove | 142 // TODO(joi): Remove |
| 129 DeprecatedBrowserThread::DeprecatedBrowserThread(BrowserThread::ID identifier) | 143 DeprecatedBrowserThread::DeprecatedBrowserThread(BrowserThread::ID identifier) |
| 130 : BrowserThread(identifier) { | 144 : BrowserThread(identifier) { |
| 131 } | 145 } |
| 132 DeprecatedBrowserThread::DeprecatedBrowserThread(BrowserThread::ID identifier, | 146 DeprecatedBrowserThread::DeprecatedBrowserThread(BrowserThread::ID identifier, |
| 133 MessageLoop* message_loop) | 147 MessageLoop* message_loop) |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 | 223 |
| 210 BrowserThread::BrowserThread(ID identifier, | 224 BrowserThread::BrowserThread(ID identifier, |
| 211 MessageLoop* message_loop) | 225 MessageLoop* message_loop) |
| 212 : Thread(message_loop->thread_name().c_str()), | 226 : Thread(message_loop->thread_name().c_str()), |
| 213 identifier_(identifier) { | 227 identifier_(identifier) { |
| 214 set_message_loop(message_loop); | 228 set_message_loop(message_loop); |
| 215 Initialize(); | 229 Initialize(); |
| 216 } | 230 } |
| 217 | 231 |
| 218 void BrowserThread::Initialize() { | 232 void BrowserThread::Initialize() { |
| 219 base::AutoLock lock(BrowserThreadImpl::lock_); | 233 base::AutoLock lock(g_lock.Get()); |
| 220 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); | 234 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); |
| 221 DCHECK(BrowserThreadImpl::browser_threads_[identifier_] == NULL); | 235 DCHECK(g_browser_threads[identifier_] == NULL); |
| 222 BrowserThreadImpl::browser_threads_[identifier_] = this; | 236 g_browser_threads[identifier_] = this; |
| 223 } | 237 } |
| 224 | 238 |
| 225 BrowserThread::~BrowserThread() { | 239 BrowserThread::~BrowserThread() { |
| 226 // Stop the thread here, instead of the parent's class destructor. This is so | 240 // Stop the thread here, instead of the parent's class destructor. This is so |
| 227 // that if there are pending tasks that run, code that checks that it's on the | 241 // that if there are pending tasks that run, code that checks that it's on the |
| 228 // correct BrowserThread succeeds. | 242 // correct BrowserThread succeeds. |
| 229 Stop(); | 243 Stop(); |
| 230 | 244 |
| 231 base::AutoLock lock(BrowserThreadImpl::lock_); | 245 base::AutoLock lock(g_lock.Get()); |
| 232 BrowserThreadImpl::browser_threads_[identifier_] = NULL; | 246 g_browser_threads[identifier_] = NULL; |
| 233 #ifndef NDEBUG | 247 #ifndef NDEBUG |
| 234 // Double check that the threads are ordered correctly in the enumeration. | 248 // Double check that the threads are ordered correctly in the enumeration. |
| 235 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { | 249 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { |
| 236 DCHECK(!BrowserThreadImpl::browser_threads_[i]) << | 250 DCHECK(!g_browser_threads[i]) << |
| 237 "Threads must be listed in the reverse order that they die"; | 251 "Threads must be listed in the reverse order that they die"; |
| 238 } | 252 } |
| 239 #endif | 253 #endif |
| 240 } | 254 } |
| 241 | 255 |
| 242 // static | 256 // static |
| 243 bool BrowserThread::IsWellKnownThread(ID identifier) { | 257 bool BrowserThread::IsWellKnownThread(ID identifier) { |
| 244 base::AutoLock lock(BrowserThreadImpl::lock_); | 258 base::AutoLock lock(g_lock.Get()); |
| 245 return (identifier >= 0 && identifier < ID_COUNT && | 259 return (identifier >= 0 && identifier < ID_COUNT && |
| 246 BrowserThreadImpl::browser_threads_[identifier]); | 260 g_browser_threads[identifier]); |
| 247 } | 261 } |
| 248 | 262 |
| 249 // static | 263 // static |
| 250 bool BrowserThread::CurrentlyOn(ID identifier) { | 264 bool BrowserThread::CurrentlyOn(ID identifier) { |
| 251 // We shouldn't use MessageLoop::current() since it uses LazyInstance which | 265 // We shouldn't use MessageLoop::current() since it uses LazyInstance which |
| 252 // may be deleted by ~AtExitManager when a WorkerPool thread calls this | 266 // may be deleted by ~AtExitManager when a WorkerPool thread calls this |
| 253 // function. | 267 // function. |
| 254 // http://crbug.com/63678 | 268 // http://crbug.com/63678 |
| 255 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; | 269 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; |
| 256 base::AutoLock lock(BrowserThreadImpl::lock_); | 270 base::AutoLock lock(g_lock.Get()); |
| 257 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 271 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 258 return BrowserThreadImpl::browser_threads_[identifier] && | 272 return g_browser_threads[identifier] && |
| 259 BrowserThreadImpl::browser_threads_[identifier]->message_loop() == | 273 g_browser_threads[identifier]->message_loop() == |
| 260 MessageLoop::current(); | 274 MessageLoop::current(); |
| 261 } | 275 } |
| 262 | 276 |
| 263 // static | 277 // static |
| 264 bool BrowserThread::IsMessageLoopValid(ID identifier) { | 278 bool BrowserThread::IsMessageLoopValid(ID identifier) { |
| 265 base::AutoLock lock(BrowserThreadImpl::lock_); | 279 base::AutoLock lock(g_lock.Get()); |
| 266 DCHECK(identifier >= 0 && identifier < ID_COUNT); | 280 DCHECK(identifier >= 0 && identifier < ID_COUNT); |
| 267 return BrowserThreadImpl::browser_threads_[identifier] && | 281 return g_browser_threads[identifier] && |
| 268 BrowserThreadImpl::browser_threads_[identifier]->message_loop(); | 282 g_browser_threads[identifier]->message_loop(); |
| 269 } | 283 } |
| 270 | 284 |
| 271 // static | 285 // static |
| 272 bool BrowserThread::PostTask(ID identifier, | 286 bool BrowserThread::PostTask(ID identifier, |
| 273 const tracked_objects::Location& from_here, | 287 const tracked_objects::Location& from_here, |
| 274 const base::Closure& task) { | 288 const base::Closure& task) { |
| 275 return BrowserThreadImpl::PostTaskHelper( | 289 return BrowserThreadImpl::PostTaskHelper( |
| 276 identifier, from_here, task, 0, true); | 290 identifier, from_here, task, 0, true); |
| 277 } | 291 } |
| 278 | 292 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 | 367 |
| 354 // static | 368 // static |
| 355 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { | 369 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { |
| 356 // We shouldn't use MessageLoop::current() since it uses LazyInstance which | 370 // We shouldn't use MessageLoop::current() since it uses LazyInstance which |
| 357 // may be deleted by ~AtExitManager when a WorkerPool thread calls this | 371 // may be deleted by ~AtExitManager when a WorkerPool thread calls this |
| 358 // function. | 372 // function. |
| 359 // http://crbug.com/63678 | 373 // http://crbug.com/63678 |
| 360 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; | 374 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; |
| 361 MessageLoop* cur_message_loop = MessageLoop::current(); | 375 MessageLoop* cur_message_loop = MessageLoop::current(); |
| 362 for (int i = 0; i < ID_COUNT; ++i) { | 376 for (int i = 0; i < ID_COUNT; ++i) { |
| 363 if (BrowserThreadImpl::browser_threads_[i] && | 377 if (g_browser_threads[i] && |
| 364 BrowserThreadImpl::browser_threads_[i]->message_loop() == | 378 g_browser_threads[i]->message_loop() == cur_message_loop) { |
| 365 cur_message_loop) { | 379 *identifier = g_browser_threads[i]->identifier_; |
| 366 *identifier = BrowserThreadImpl::browser_threads_[i]->identifier_; | |
| 367 return true; | 380 return true; |
| 368 } | 381 } |
| 369 } | 382 } |
| 370 | 383 |
| 371 return false; | 384 return false; |
| 372 } | 385 } |
| 373 | 386 |
| 374 // static | 387 // static |
| 375 scoped_refptr<base::MessageLoopProxy> | 388 scoped_refptr<base::MessageLoopProxy> |
| 376 BrowserThread::GetMessageLoopProxyForThread( | 389 BrowserThread::GetMessageLoopProxyForThread( |
| 377 ID identifier) { | 390 ID identifier) { |
| 378 scoped_refptr<base::MessageLoopProxy> proxy( | 391 scoped_refptr<base::MessageLoopProxy> proxy( |
| 379 new BrowserThreadMessageLoopProxy(identifier)); | 392 new BrowserThreadMessageLoopProxy(identifier)); |
| 380 return proxy; | 393 return proxy; |
| 381 } | 394 } |
| 382 | 395 |
| 383 } // namespace content | 396 } // namespace content |
| OLD | NEW |