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 |