OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/browser_thread.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/message_loop.h" | |
9 #include "base/message_loop_proxy.h" | |
10 #include "base/threading/thread_restrictions.h" | |
11 | |
12 // Friendly names for the well-known threads. | |
13 static const char* browser_thread_names[BrowserThread::ID_COUNT] = { | |
14 "", // UI (name assembled in browser_main.cc). | |
15 "Chrome_DBThread", // DB | |
16 "Chrome_WebKitThread", // WEBKIT | |
17 "Chrome_FileThread", // FILE | |
18 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER | |
19 "Chrome_CacheThread", // CACHE | |
20 "Chrome_IOThread", // IO | |
21 #if defined(OS_CHROMEOS) | |
22 "Chrome_WebSocketproxyThread", // WEB_SOCKET_PROXY | |
23 #endif | |
24 }; | |
25 | |
26 // An implementation of MessageLoopProxy to be used in conjunction | |
27 // with BrowserThread. | |
28 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy { | |
29 public: | |
30 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier) | |
31 : id_(identifier) { | |
32 } | |
33 | |
34 // MessageLoopProxy implementation. | |
35 virtual bool PostTask(const tracked_objects::Location& from_here, | |
36 Task* task) { | |
37 return BrowserThread::PostTask(id_, from_here, task); | |
38 } | |
39 | |
40 virtual bool PostDelayedTask(const tracked_objects::Location& from_here, | |
41 Task* task, int64 delay_ms) { | |
42 return BrowserThread::PostDelayedTask(id_, from_here, task, delay_ms); | |
43 } | |
44 | |
45 virtual bool PostNonNestableTask(const tracked_objects::Location& from_here, | |
46 Task* task) { | |
47 return BrowserThread::PostNonNestableTask(id_, from_here, task); | |
48 } | |
49 | |
50 virtual bool PostNonNestableDelayedTask( | |
51 const tracked_objects::Location& from_here, | |
52 Task* task, | |
53 int64 delay_ms) { | |
54 return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task, | |
55 delay_ms); | |
56 } | |
57 | |
58 virtual bool PostTask(const tracked_objects::Location& from_here, | |
59 const base::Closure& task) { | |
60 return BrowserThread::PostTask(id_, from_here, task); | |
61 } | |
62 | |
63 virtual bool PostDelayedTask(const tracked_objects::Location& from_here, | |
64 const base::Closure& task, int64 delay_ms) { | |
65 return BrowserThread::PostDelayedTask(id_, from_here, task, delay_ms); | |
66 } | |
67 | |
68 virtual bool PostNonNestableTask(const tracked_objects::Location& from_here, | |
69 const base::Closure& task) { | |
70 return BrowserThread::PostNonNestableTask(id_, from_here, task); | |
71 } | |
72 | |
73 virtual bool PostNonNestableDelayedTask( | |
74 const tracked_objects::Location& from_here, | |
75 const base::Closure& task, | |
76 int64 delay_ms) { | |
77 return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task, | |
78 delay_ms); | |
79 } | |
80 | |
81 virtual bool BelongsToCurrentThread() { | |
82 return BrowserThread::CurrentlyOn(id_); | |
83 } | |
84 | |
85 private: | |
86 BrowserThread::ID id_; | |
87 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy); | |
88 }; | |
89 | |
90 | |
91 base::Lock BrowserThread::lock_; | |
92 | |
93 BrowserThread* BrowserThread::browser_threads_[ID_COUNT]; | |
94 | |
95 BrowserThread::BrowserThread(BrowserThread::ID identifier) | |
96 : Thread(browser_thread_names[identifier]), | |
97 identifier_(identifier) { | |
98 Initialize(); | |
99 } | |
100 | |
101 BrowserThread::BrowserThread(ID identifier, MessageLoop* message_loop) | |
102 : Thread(message_loop->thread_name().c_str()), | |
103 identifier_(identifier) { | |
104 set_message_loop(message_loop); | |
105 Initialize(); | |
106 } | |
107 | |
108 void BrowserThread::Initialize() { | |
109 base::AutoLock lock(lock_); | |
110 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT); | |
111 DCHECK(browser_threads_[identifier_] == NULL); | |
112 browser_threads_[identifier_] = this; | |
113 } | |
114 | |
115 BrowserThread::~BrowserThread() { | |
116 // Stop the thread here, instead of the parent's class destructor. This is so | |
117 // that if there are pending tasks that run, code that checks that it's on the | |
118 // correct BrowserThread succeeds. | |
119 Stop(); | |
120 | |
121 base::AutoLock lock(lock_); | |
122 browser_threads_[identifier_] = NULL; | |
123 #ifndef NDEBUG | |
124 // Double check that the threads are ordered correctly in the enumeration. | |
125 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { | |
126 DCHECK(!browser_threads_[i]) << | |
127 "Threads must be listed in the reverse order that they die"; | |
128 } | |
129 #endif | |
130 } | |
131 | |
132 // static | |
133 bool BrowserThread::IsWellKnownThread(ID identifier) { | |
134 base::AutoLock lock(lock_); | |
135 return (identifier >= 0 && identifier < ID_COUNT && | |
136 browser_threads_[identifier]); | |
137 } | |
138 | |
139 // static | |
140 bool BrowserThread::CurrentlyOn(ID identifier) { | |
141 // We shouldn't use MessageLoop::current() since it uses LazyInstance which | |
142 // may be deleted by ~AtExitManager when a WorkerPool thread calls this | |
143 // function. | |
144 // http://crbug.com/63678 | |
145 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; | |
146 base::AutoLock lock(lock_); | |
147 DCHECK(identifier >= 0 && identifier < ID_COUNT); | |
148 return browser_threads_[identifier] && | |
149 browser_threads_[identifier]->message_loop() == MessageLoop::current(); | |
150 } | |
151 | |
152 // static | |
153 bool BrowserThread::IsMessageLoopValid(ID identifier) { | |
154 base::AutoLock lock(lock_); | |
155 DCHECK(identifier >= 0 && identifier < ID_COUNT); | |
156 return browser_threads_[identifier] && | |
157 browser_threads_[identifier]->message_loop(); | |
158 } | |
159 | |
160 // static | |
161 bool BrowserThread::PostTask(ID identifier, | |
162 const tracked_objects::Location& from_here, | |
163 const base::Closure& task) { | |
164 return PostTaskHelper(identifier, from_here, task, 0, true); | |
165 } | |
166 | |
167 // static | |
168 bool BrowserThread::PostDelayedTask(ID identifier, | |
169 const tracked_objects::Location& from_here, | |
170 const base::Closure& task, | |
171 int64 delay_ms) { | |
172 return PostTaskHelper(identifier, from_here, task, delay_ms, true); | |
173 } | |
174 | |
175 // static | |
176 bool BrowserThread::PostNonNestableTask( | |
177 ID identifier, | |
178 const tracked_objects::Location& from_here, | |
179 const base::Closure& task) { | |
180 return PostTaskHelper(identifier, from_here, task, 0, false); | |
181 } | |
182 | |
183 // static | |
184 bool BrowserThread::PostNonNestableDelayedTask( | |
185 ID identifier, | |
186 const tracked_objects::Location& from_here, | |
187 const base::Closure& task, | |
188 int64 delay_ms) { | |
189 return PostTaskHelper(identifier, from_here, task, delay_ms, false); | |
190 } | |
191 | |
192 // static | |
193 bool BrowserThread::PostTask(ID identifier, | |
194 const tracked_objects::Location& from_here, | |
195 Task* task) { | |
196 return PostTaskHelper(identifier, from_here, task, 0, true); | |
197 } | |
198 | |
199 // static | |
200 bool BrowserThread::PostDelayedTask(ID identifier, | |
201 const tracked_objects::Location& from_here, | |
202 Task* task, | |
203 int64 delay_ms) { | |
204 return PostTaskHelper(identifier, from_here, task, delay_ms, true); | |
205 } | |
206 | |
207 // static | |
208 bool BrowserThread::PostNonNestableTask( | |
209 ID identifier, | |
210 const tracked_objects::Location& from_here, | |
211 Task* task) { | |
212 return PostTaskHelper(identifier, from_here, task, 0, false); | |
213 } | |
214 | |
215 // static | |
216 bool BrowserThread::PostNonNestableDelayedTask( | |
217 ID identifier, | |
218 const tracked_objects::Location& from_here, | |
219 Task* task, | |
220 int64 delay_ms) { | |
221 return PostTaskHelper(identifier, from_here, task, delay_ms, false); | |
222 } | |
223 | |
224 // static | |
225 bool BrowserThread::PostTaskAndReply( | |
226 ID identifier, | |
227 const tracked_objects::Location& from_here, | |
228 const base::Closure& task, | |
229 const base::Closure& reply) { | |
230 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here, | |
231 task, | |
232 reply); | |
233 } | |
234 | |
235 // static | |
236 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { | |
237 // We shouldn't use MessageLoop::current() since it uses LazyInstance which | |
238 // may be deleted by ~AtExitManager when a WorkerPool thread calls this | |
239 // function. | |
240 // http://crbug.com/63678 | |
241 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; | |
242 MessageLoop* cur_message_loop = MessageLoop::current(); | |
243 for (int i = 0; i < ID_COUNT; ++i) { | |
244 if (browser_threads_[i] && | |
245 browser_threads_[i]->message_loop() == cur_message_loop) { | |
246 *identifier = browser_threads_[i]->identifier_; | |
247 return true; | |
248 } | |
249 } | |
250 | |
251 return false; | |
252 } | |
253 | |
254 // static | |
255 scoped_refptr<base::MessageLoopProxy> | |
256 BrowserThread::GetMessageLoopProxyForThread( | |
257 ID identifier) { | |
258 scoped_refptr<base::MessageLoopProxy> proxy( | |
259 new BrowserThreadMessageLoopProxy(identifier)); | |
260 return proxy; | |
261 } | |
262 | |
263 // static | |
264 bool BrowserThread::PostTaskHelper( | |
265 ID identifier, | |
266 const tracked_objects::Location& from_here, | |
267 Task* task, | |
268 int64 delay_ms, | |
269 bool nestable) { | |
270 DCHECK(identifier >= 0 && identifier < ID_COUNT); | |
271 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in | |
272 // order of lifetime. So no need to lock if we know that the other thread | |
273 // outlives this one. | |
274 // Note: since the array is so small, ok to loop instead of creating a map, | |
275 // which would require a lock because std::map isn't thread safe, defeating | |
276 // the whole purpose of this optimization. | |
277 ID current_thread; | |
278 bool guaranteed_to_outlive_target_thread = | |
279 GetCurrentThreadIdentifier(¤t_thread) && | |
280 current_thread >= identifier; | |
281 | |
282 if (!guaranteed_to_outlive_target_thread) | |
283 lock_.Acquire(); | |
284 | |
285 MessageLoop* message_loop = browser_threads_[identifier] ? | |
286 browser_threads_[identifier]->message_loop() : NULL; | |
287 if (message_loop) { | |
288 if (nestable) { | |
289 message_loop->PostDelayedTask(from_here, task, delay_ms); | |
290 } else { | |
291 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); | |
292 } | |
293 } | |
294 | |
295 if (!guaranteed_to_outlive_target_thread) | |
296 lock_.Release(); | |
297 | |
298 if (!message_loop) | |
299 delete task; | |
300 | |
301 return !!message_loop; | |
302 } | |
303 | |
304 // static | |
305 bool BrowserThread::PostTaskHelper( | |
306 ID identifier, | |
307 const tracked_objects::Location& from_here, | |
308 const base::Closure& task, | |
309 int64 delay_ms, | |
310 bool nestable) { | |
311 DCHECK(identifier >= 0 && identifier < ID_COUNT); | |
312 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in | |
313 // order of lifetime. So no need to lock if we know that the other thread | |
314 // outlives this one. | |
315 // Note: since the array is so small, ok to loop instead of creating a map, | |
316 // which would require a lock because std::map isn't thread safe, defeating | |
317 // the whole purpose of this optimization. | |
318 ID current_thread; | |
319 bool guaranteed_to_outlive_target_thread = | |
320 GetCurrentThreadIdentifier(¤t_thread) && | |
321 current_thread >= identifier; | |
322 | |
323 if (!guaranteed_to_outlive_target_thread) | |
324 lock_.Acquire(); | |
325 | |
326 MessageLoop* message_loop = browser_threads_[identifier] ? | |
327 browser_threads_[identifier]->message_loop() : NULL; | |
328 if (message_loop) { | |
329 if (nestable) { | |
330 message_loop->PostDelayedTask(from_here, task, delay_ms); | |
331 } else { | |
332 message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms); | |
333 } | |
334 } | |
335 | |
336 if (!guaranteed_to_outlive_target_thread) | |
337 lock_.Release(); | |
338 | |
339 return !!message_loop; | |
340 } | |
OLD | NEW |