OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "base/message_loop/message_loop.h" | 5 #include "base/message_loop/message_loop.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 MessageLoop::~MessageLoop() { | 90 MessageLoop::~MessageLoop() { |
91 // If |pump_| is non-null, this message loop has been bound and should be the | 91 // If |pump_| is non-null, this message loop has been bound and should be the |
92 // current one on this thread. Otherwise, this loop is being destructed before | 92 // current one on this thread. Otherwise, this loop is being destructed before |
93 // it was bound to a thread, so a different message loop (or no loop at all) | 93 // it was bound to a thread, so a different message loop (or no loop at all) |
94 // may be current. | 94 // may be current. |
95 DCHECK((pump_ && current() == this) || (!pump_ && current() != this)); | 95 DCHECK((pump_ && current() == this) || (!pump_ && current() != this)); |
96 | 96 |
97 // iOS just attaches to the loop, it doesn't Run it. | 97 // iOS just attaches to the loop, it doesn't Run it. |
98 // TODO(stuartmorgan): Consider wiring up a Detach(). | 98 // TODO(stuartmorgan): Consider wiring up a Detach(). |
99 #if !defined(OS_IOS) | 99 #if !defined(OS_IOS) |
100 DCHECK(!run_loop_); | 100 // There should be no active RunLoops on this thread, unless this MessageLoop |
| 101 // isn't bound to the current thread (see other condition at the top of this |
| 102 // method). |
| 103 DCHECK((!pump_ && current() != this) || !GetTopMostRunLoop()); |
101 #endif | 104 #endif |
102 | 105 |
103 #if defined(OS_WIN) | 106 #if defined(OS_WIN) |
104 if (in_high_res_mode_) | 107 if (in_high_res_mode_) |
105 Time::ActivateHighResolutionTimer(false); | 108 Time::ActivateHighResolutionTimer(false); |
106 #endif | 109 #endif |
107 // Clean up any unprocessed tasks, but take care: deleting a task could | 110 // Clean up any unprocessed tasks, but take care: deleting a task could |
108 // result in the addition of more tasks (e.g., via DeleteSoon). We set a | 111 // result in the addition of more tasks (e.g., via DeleteSoon). We set a |
109 // limit on the number of times we will allow a deleted task to generate more | 112 // limit on the number of times we will allow a deleted task to generate more |
110 // tasks. Normally, we should only pass through this loop once or twice. If | 113 // tasks. Normally, we should only pass through this loop once or twice. If |
(...skipping 18 matching lines...) Expand all Loading... |
129 | 132 |
130 // Tell the incoming queue that we are dying. | 133 // Tell the incoming queue that we are dying. |
131 incoming_task_queue_->WillDestroyCurrentMessageLoop(); | 134 incoming_task_queue_->WillDestroyCurrentMessageLoop(); |
132 incoming_task_queue_ = NULL; | 135 incoming_task_queue_ = NULL; |
133 unbound_task_runner_ = NULL; | 136 unbound_task_runner_ = NULL; |
134 task_runner_ = NULL; | 137 task_runner_ = NULL; |
135 | 138 |
136 // OK, now make it so that no one can find us. | 139 // OK, now make it so that no one can find us. |
137 if (current() == this) | 140 if (current() == this) |
138 GetTLSMessageLoop()->Set(nullptr); | 141 GetTLSMessageLoop()->Set(nullptr); |
139 | |
140 RunLoop::ResetTLSState(); | |
141 } | 142 } |
142 | 143 |
143 // static | 144 // static |
144 MessageLoop* MessageLoop::current() { | 145 MessageLoop* MessageLoop::current() { |
145 // TODO(darin): sadly, we cannot enable this yet since people call us even | 146 // TODO(darin): sadly, we cannot enable this yet since people call us even |
146 // when they have no intention of using us. | 147 // when they have no intention of using us. |
147 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; | 148 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; |
148 return GetTLSMessageLoop()->Get(); | 149 return GetTLSMessageLoop()->Get(); |
149 } | 150 } |
150 | 151 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 } | 210 } |
210 | 211 |
211 void MessageLoop::RemoveDestructionObserver( | 212 void MessageLoop::RemoveDestructionObserver( |
212 DestructionObserver* destruction_observer) { | 213 DestructionObserver* destruction_observer) { |
213 DCHECK_EQ(this, current()); | 214 DCHECK_EQ(this, current()); |
214 destruction_observers_.RemoveObserver(destruction_observer); | 215 destruction_observers_.RemoveObserver(destruction_observer); |
215 } | 216 } |
216 | 217 |
217 void MessageLoop::QuitWhenIdle() { | 218 void MessageLoop::QuitWhenIdle() { |
218 DCHECK_EQ(this, current()); | 219 DCHECK_EQ(this, current()); |
219 if (run_loop_) { | 220 DCHECK(GetTopMostRunLoop()) << "Must be inside Run to call QuitWhenIdle"; |
220 run_loop_->QuitWhenIdle(); | 221 GetTopMostRunLoop()->QuitWhenIdle(); |
221 } else { | |
222 NOTREACHED() << "Must be inside Run to call QuitWhenIdle"; | |
223 } | |
224 } | 222 } |
225 | 223 |
226 void MessageLoop::QuitNow() { | 224 void MessageLoop::QuitNow() { |
227 DCHECK_EQ(this, current()); | 225 DCHECK_EQ(this, current()); |
228 if (run_loop_) { | 226 DCHECK(GetTopMostRunLoop()) << "Must be inside Run to call Quit"; |
229 pump_->Quit(); | 227 pump_->Quit(); |
230 } else { | |
231 NOTREACHED() << "Must be inside Run to call Quit"; | |
232 } | |
233 } | 228 } |
234 | 229 |
235 bool MessageLoop::IsType(Type type) const { | 230 bool MessageLoop::IsType(Type type) const { |
236 return type_ == type; | 231 return type_ == type; |
237 } | 232 } |
238 | 233 |
239 static void QuitCurrentWhenIdle() { | 234 static void QuitCurrentWhenIdle() { |
240 MessageLoop::current()->QuitWhenIdle(); | 235 MessageLoop::current()->QuitWhenIdle(); |
241 } | 236 } |
242 | 237 |
243 // static | 238 // static |
244 Closure MessageLoop::QuitWhenIdleClosure() { | 239 Closure MessageLoop::QuitWhenIdleClosure() { |
245 return Bind(&QuitCurrentWhenIdle); | 240 return Bind(&QuitCurrentWhenIdle); |
246 } | 241 } |
247 | 242 |
248 void MessageLoop::SetNestableTasksAllowed(bool allowed) { | 243 void MessageLoop::SetNestableTasksAllowed(bool allowed) { |
249 if (allowed) { | 244 if (allowed) { |
250 CHECK(base::RunLoop::IsNestingAllowedOnCurrentThread()); | 245 CHECK(RunLoop::IsNestingAllowedOnCurrentThread()); |
251 | 246 |
252 // Kick the native pump just in case we enter a OS-driven nested message | 247 // Kick the native pump just in case we enter a OS-driven nested message |
253 // loop. | 248 // loop. |
254 pump_->ScheduleWork(); | 249 pump_->ScheduleWork(); |
255 } | 250 } |
256 nestable_tasks_allowed_ = allowed; | 251 nestable_tasks_allowed_ = allowed; |
257 } | 252 } |
258 | 253 |
259 bool MessageLoop::NestableTasksAllowed() const { | 254 bool MessageLoop::NestableTasksAllowed() const { |
260 return nestable_tasks_allowed_; | 255 return nestable_tasks_allowed_; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 } | 290 } |
296 | 291 |
297 MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) | 292 MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory) |
298 : type_(type), | 293 : type_(type), |
299 #if defined(OS_WIN) | 294 #if defined(OS_WIN) |
300 pending_high_res_tasks_(0), | 295 pending_high_res_tasks_(0), |
301 in_high_res_mode_(false), | 296 in_high_res_mode_(false), |
302 #endif | 297 #endif |
303 nestable_tasks_allowed_(true), | 298 nestable_tasks_allowed_(true), |
304 pump_factory_(std::move(pump_factory)), | 299 pump_factory_(std::move(pump_factory)), |
305 run_loop_(nullptr), | |
306 current_pending_task_(nullptr), | 300 current_pending_task_(nullptr), |
307 incoming_task_queue_(new internal::IncomingTaskQueue(this)), | 301 incoming_task_queue_(new internal::IncomingTaskQueue(this)), |
308 unbound_task_runner_( | 302 unbound_task_runner_( |
309 new internal::MessageLoopTaskRunner(incoming_task_queue_)), | 303 new internal::MessageLoopTaskRunner(incoming_task_queue_)), |
310 task_runner_(unbound_task_runner_), | 304 task_runner_(unbound_task_runner_), |
311 thread_id_(kInvalidThreadId) { | 305 thread_id_(kInvalidThreadId) { |
312 // If type is TYPE_CUSTOM non-null pump_factory must be given. | 306 // If type is TYPE_CUSTOM non-null pump_factory must be given. |
313 DCHECK(type_ != TYPE_CUSTOM || !pump_factory_.is_null()); | 307 DCHECK(type_ != TYPE_CUSTOM || !pump_factory_.is_null()); |
314 } | 308 } |
315 | 309 |
316 void MessageLoop::BindToCurrentThread() { | |
317 DCHECK(!pump_); | |
318 if (!pump_factory_.is_null()) | |
319 pump_ = std::move(pump_factory_).Run(); | |
320 else | |
321 pump_ = CreateMessagePumpForType(type_); | |
322 | |
323 DCHECK(!current()) << "should only have one message loop per thread"; | |
324 GetTLSMessageLoop()->Set(this); | |
325 | |
326 incoming_task_queue_->StartScheduling(); | |
327 unbound_task_runner_->BindToCurrentThread(); | |
328 unbound_task_runner_ = nullptr; | |
329 SetThreadTaskRunnerHandle(); | |
330 thread_id_ = PlatformThread::CurrentId(); | |
331 } | |
332 | |
333 std::string MessageLoop::GetThreadName() const { | 310 std::string MessageLoop::GetThreadName() const { |
334 DCHECK_NE(kInvalidThreadId, thread_id_) | 311 DCHECK_NE(kInvalidThreadId, thread_id_) |
335 << "GetThreadName() must only be called after BindToCurrentThread()'s " | 312 << "GetThreadName() must only be called after BindToCurrentThread()'s " |
336 << "side-effects have been synchronized with this thread."; | 313 << "side-effects have been synchronized with this thread."; |
337 return ThreadIdNameManager::GetInstance()->GetName(thread_id_); | 314 return ThreadIdNameManager::GetInstance()->GetName(thread_id_); |
338 } | 315 } |
339 | 316 |
340 void MessageLoop::SetTaskRunner( | 317 void MessageLoop::SetTaskRunner( |
341 scoped_refptr<SingleThreadTaskRunner> task_runner) { | 318 scoped_refptr<SingleThreadTaskRunner> task_runner) { |
342 DCHECK_EQ(this, current()); | 319 DCHECK_EQ(this, current()); |
343 DCHECK(task_runner); | 320 DCHECK(task_runner); |
344 DCHECK(task_runner->BelongsToCurrentThread()); | 321 DCHECK(task_runner->BelongsToCurrentThread()); |
345 DCHECK(!unbound_task_runner_); | 322 DCHECK(!unbound_task_runner_); |
346 task_runner_ = std::move(task_runner); | 323 task_runner_ = std::move(task_runner); |
347 SetThreadTaskRunnerHandle(); | 324 SetThreadTaskRunnerHandle(); |
348 } | 325 } |
349 | 326 |
350 void MessageLoop::ClearTaskRunnerForTesting() { | 327 void MessageLoop::ClearTaskRunnerForTesting() { |
351 DCHECK_EQ(this, current()); | 328 DCHECK_EQ(this, current()); |
352 DCHECK(!unbound_task_runner_); | 329 DCHECK(!unbound_task_runner_); |
353 task_runner_ = nullptr; | 330 task_runner_ = nullptr; |
354 thread_task_runner_handle_.reset(); | 331 thread_task_runner_handle_.reset(); |
355 } | 332 } |
356 | 333 |
| 334 void MessageLoop::BindToCurrentThread() { |
| 335 RunLoop::Delegate::BindToCurrentThread(); |
| 336 |
| 337 DCHECK(!pump_); |
| 338 if (!pump_factory_.is_null()) |
| 339 pump_ = std::move(pump_factory_).Run(); |
| 340 else |
| 341 pump_ = CreateMessagePumpForType(type_); |
| 342 |
| 343 DCHECK(!current()) << "should only have one message loop per thread"; |
| 344 GetTLSMessageLoop()->Set(this); |
| 345 |
| 346 incoming_task_queue_->StartScheduling(); |
| 347 unbound_task_runner_->BindToCurrentThread(); |
| 348 unbound_task_runner_ = nullptr; |
| 349 SetThreadTaskRunnerHandle(); |
| 350 thread_id_ = PlatformThread::CurrentId(); |
| 351 } |
| 352 |
| 353 void MessageLoop::Run() { |
| 354 DCHECK_EQ(this, current()); |
| 355 pump_->Run(this); |
| 356 } |
| 357 |
| 358 void MessageLoop::Quit() { |
| 359 DCHECK_EQ(this, current()); |
| 360 QuitNow(); |
| 361 } |
| 362 |
357 void MessageLoop::SetThreadTaskRunnerHandle() { | 363 void MessageLoop::SetThreadTaskRunnerHandle() { |
358 DCHECK_EQ(this, current()); | 364 DCHECK_EQ(this, current()); |
359 // Clear the previous thread task runner first, because only one can exist at | 365 // Clear the previous thread task runner first, because only one can exist at |
360 // a time. | 366 // a time. |
361 thread_task_runner_handle_.reset(); | 367 thread_task_runner_handle_.reset(); |
362 thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_)); | 368 thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_)); |
363 } | 369 } |
364 | 370 |
365 void MessageLoop::RunHandler() { | |
366 DCHECK_EQ(this, current()); | |
367 DCHECK(run_loop_); | |
368 pump_->Run(this); | |
369 } | |
370 | |
371 bool MessageLoop::ProcessNextDelayedNonNestableTask() { | 371 bool MessageLoop::ProcessNextDelayedNonNestableTask() { |
372 if (is_nested_) | 372 if (IsNested()) |
373 return false; | 373 return false; |
374 | 374 |
375 if (deferred_non_nestable_work_queue_.empty()) | 375 if (deferred_non_nestable_work_queue_.empty()) |
376 return false; | 376 return false; |
377 | 377 |
378 PendingTask pending_task = | 378 PendingTask pending_task = |
379 std::move(deferred_non_nestable_work_queue_.front()); | 379 std::move(deferred_non_nestable_work_queue_.front()); |
380 deferred_non_nestable_work_queue_.pop(); | 380 deferred_non_nestable_work_queue_.pop(); |
381 | 381 |
382 RunTask(&pending_task); | 382 RunTask(&pending_task); |
(...skipping 21 matching lines...) Expand all Loading... |
404 task_annotator_.RunTask("MessageLoop::PostTask", pending_task); | 404 task_annotator_.RunTask("MessageLoop::PostTask", pending_task); |
405 for (auto& observer : task_observers_) | 405 for (auto& observer : task_observers_) |
406 observer.DidProcessTask(*pending_task); | 406 observer.DidProcessTask(*pending_task); |
407 | 407 |
408 nestable_tasks_allowed_ = true; | 408 nestable_tasks_allowed_ = true; |
409 | 409 |
410 current_pending_task_ = nullptr; | 410 current_pending_task_ = nullptr; |
411 } | 411 } |
412 | 412 |
413 bool MessageLoop::DeferOrRunPendingTask(PendingTask pending_task) { | 413 bool MessageLoop::DeferOrRunPendingTask(PendingTask pending_task) { |
414 if (pending_task.nestable || !is_nested_) { | 414 if (pending_task.nestable || !IsNested()) { |
415 RunTask(&pending_task); | 415 RunTask(&pending_task); |
416 // Show that we ran a task (Note: a new one might arrive as a | 416 // Show that we ran a task (Note: a new one might arrive as a |
417 // consequence!). | 417 // consequence!). |
418 return true; | 418 return true; |
419 } | 419 } |
420 | 420 |
421 // We couldn't run the task now because we're in a nested run loop | 421 // We couldn't run the task now because we're in a nested run loop |
422 // and the task isn't nestable. | 422 // and the task isn't nestable. |
423 deferred_non_nestable_work_queue_.push(std::move(pending_task)); | 423 deferred_non_nestable_work_queue_.push(std::move(pending_task)); |
424 return false; | 424 return false; |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 if (!delayed_work_queue_.empty()) | 539 if (!delayed_work_queue_.empty()) |
540 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; | 540 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; |
541 | 541 |
542 return DeferOrRunPendingTask(std::move(pending_task)); | 542 return DeferOrRunPendingTask(std::move(pending_task)); |
543 } | 543 } |
544 | 544 |
545 bool MessageLoop::DoIdleWork() { | 545 bool MessageLoop::DoIdleWork() { |
546 if (ProcessNextDelayedNonNestableTask()) | 546 if (ProcessNextDelayedNonNestableTask()) |
547 return true; | 547 return true; |
548 | 548 |
549 if (run_loop_->quit_when_idle_received_) | 549 if (GetTopMostRunLoop()->quit_when_idle_received_) |
550 pump_->Quit(); | 550 pump_->Quit(); |
551 | 551 |
552 // When we return we will do a kernel wait for more tasks. | 552 // When we return we will do a kernel wait for more tasks. |
553 #if defined(OS_WIN) | 553 #if defined(OS_WIN) |
554 // On Windows we activate the high resolution timer so that the wait | 554 // On Windows we activate the high resolution timer so that the wait |
555 // _if_ triggered by the timer happens with good resolution. If we don't | 555 // _if_ triggered by the timer happens with good resolution. If we don't |
556 // do this the default resolution is 15ms which might not be acceptable | 556 // do this the default resolution is 15ms which might not be acceptable |
557 // for some tasks. | 557 // for some tasks. |
558 bool high_res = pending_high_res_tasks_ > 0; | 558 bool high_res = pending_high_res_tasks_ > 0; |
559 if (high_res != in_high_res_mode_) { | 559 if (high_res != in_high_res_mode_) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 persistent, | 642 persistent, |
643 mode, | 643 mode, |
644 controller, | 644 controller, |
645 delegate); | 645 delegate); |
646 } | 646 } |
647 #endif | 647 #endif |
648 | 648 |
649 #endif // !defined(OS_NACL_SFI) | 649 #endif // !defined(OS_NACL_SFI) |
650 | 650 |
651 } // namespace base | 651 } // namespace base |
OLD | NEW |