| 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 |