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 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
160 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() | 160 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() |
161 #elif defined(OS_MACOSX) | 161 #elif defined(OS_MACOSX) |
162 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | 162 #define MESSAGE_PUMP_UI MessagePumpMac::Create() |
163 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 163 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
164 #elif defined(OS_NACL) | 164 #elif defined(OS_NACL) |
165 // Currently NaCl doesn't have a UI MessageLoop. | 165 // Currently NaCl doesn't have a UI MessageLoop. |
166 // TODO(abarth): Figure out if we need this. | 166 // TODO(abarth): Figure out if we need this. |
167 #define MESSAGE_PUMP_UI NULL | 167 #define MESSAGE_PUMP_UI NULL |
168 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and | 168 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and |
169 // doesn't require extra support for watching file descriptors. | 169 // doesn't require extra support for watching file descriptors. |
170 #define MESSAGE_PUMP_IO new MessagePumpDefault(); | 170 #define MESSAGE_PUMP_IO new MessagePumpDefault() |
171 #elif defined(OS_POSIX) // POSIX but not MACOSX. | 171 #elif defined(OS_POSIX) // POSIX but not MACOSX. |
172 #define MESSAGE_PUMP_UI new MessagePumpForUI() | 172 #define MESSAGE_PUMP_UI new MessagePumpForUI() |
173 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 173 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
174 #else | 174 #else |
175 #error Not implemented | 175 #error Not implemented |
176 #endif | 176 #endif |
177 | 177 |
178 if (type_ == TYPE_UI) { | 178 if (type_ == TYPE_UI) { |
179 if (message_pump_for_ui_factory_) | 179 if (message_pump_for_ui_factory_) |
180 pump_ = message_pump_for_ui_factory_(); | 180 pump_.reset(message_pump_for_ui_factory_()); |
181 else | 181 else |
182 pump_ = MESSAGE_PUMP_UI; | 182 pump_.reset(MESSAGE_PUMP_UI); |
183 } else if (type_ == TYPE_IO) { | 183 } else if (type_ == TYPE_IO) { |
184 pump_ = MESSAGE_PUMP_IO; | 184 pump_.reset(MESSAGE_PUMP_IO); |
185 } else { | 185 } else { |
186 DCHECK_EQ(TYPE_DEFAULT, type_); | 186 DCHECK_EQ(TYPE_DEFAULT, type_); |
187 pump_ = new MessagePumpDefault(); | 187 pump_.reset(new MessagePumpDefault()); |
188 } | 188 } |
189 } | 189 } |
190 | 190 |
191 MessageLoop::~MessageLoop() { | 191 MessageLoop::~MessageLoop() { |
192 DCHECK_EQ(this, current()); | 192 DCHECK_EQ(this, current()); |
193 | 193 |
194 DCHECK(!run_loop_); | 194 DCHECK(!run_loop_); |
195 | 195 |
196 // Clean up any unprocessed tasks, but take care: deleting a task could | 196 // Clean up any unprocessed tasks, but take care: deleting a task could |
197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a | 197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
266 void MessageLoop::RemoveDestructionObserver( | 266 void MessageLoop::RemoveDestructionObserver( |
267 DestructionObserver* destruction_observer) { | 267 DestructionObserver* destruction_observer) { |
268 DCHECK_EQ(this, current()); | 268 DCHECK_EQ(this, current()); |
269 destruction_observers_.RemoveObserver(destruction_observer); | 269 destruction_observers_.RemoveObserver(destruction_observer); |
270 } | 270 } |
271 | 271 |
272 void MessageLoop::PostTask( | 272 void MessageLoop::PostTask( |
273 const tracked_objects::Location& from_here, | 273 const tracked_objects::Location& from_here, |
274 const Closure& task) { | 274 const Closure& task) { |
275 DCHECK(!task.is_null()) << from_here.ToString(); | 275 DCHECK(!task.is_null()) << from_here.ToString(); |
276 PendingTask pending_task( | 276 message_loop_proxy_->AddToIncomingQueue(from_here, task, TimeDelta(), true); |
277 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
278 AddToIncomingQueue(&pending_task, false); | |
279 } | 277 } |
280 | 278 |
281 bool MessageLoop::TryPostTask( | 279 bool MessageLoop::TryPostTask( |
282 const tracked_objects::Location& from_here, | 280 const tracked_objects::Location& from_here, |
283 const Closure& task) { | 281 const Closure& task) { |
284 DCHECK(!task.is_null()) << from_here.ToString(); | 282 DCHECK(!task.is_null()) << from_here.ToString(); |
285 PendingTask pending_task( | 283 return message_loop_proxy_->TryAddToIncomingQueue(from_here, task); |
286 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
287 return AddToIncomingQueue(&pending_task, true); | |
288 } | 284 } |
289 | 285 |
290 void MessageLoop::PostDelayedTask( | 286 void MessageLoop::PostDelayedTask( |
291 const tracked_objects::Location& from_here, | 287 const tracked_objects::Location& from_here, |
292 const Closure& task, | 288 const Closure& task, |
293 TimeDelta delay) { | 289 TimeDelta delay) { |
294 DCHECK(!task.is_null()) << from_here.ToString(); | 290 DCHECK(!task.is_null()) << from_here.ToString(); |
295 PendingTask pending_task( | 291 message_loop_proxy_->AddToIncomingQueue(from_here, task, delay, true); |
296 from_here, task, CalculateDelayedRuntime(delay), true); | |
297 AddToIncomingQueue(&pending_task, false); | |
298 } | 292 } |
299 | 293 |
300 void MessageLoop::PostNonNestableTask( | 294 void MessageLoop::PostNonNestableTask( |
301 const tracked_objects::Location& from_here, | 295 const tracked_objects::Location& from_here, |
302 const Closure& task) { | 296 const Closure& task) { |
303 DCHECK(!task.is_null()) << from_here.ToString(); | 297 DCHECK(!task.is_null()) << from_here.ToString(); |
304 PendingTask pending_task( | 298 message_loop_proxy_->AddToIncomingQueue(from_here, task, TimeDelta(), false); |
305 from_here, task, CalculateDelayedRuntime(TimeDelta()), false); | |
306 AddToIncomingQueue(&pending_task, false); | |
307 } | 299 } |
308 | 300 |
309 void MessageLoop::PostNonNestableDelayedTask( | 301 void MessageLoop::PostNonNestableDelayedTask( |
310 const tracked_objects::Location& from_here, | 302 const tracked_objects::Location& from_here, |
311 const Closure& task, | 303 const Closure& task, |
312 TimeDelta delay) { | 304 TimeDelta delay) { |
313 DCHECK(!task.is_null()) << from_here.ToString(); | 305 DCHECK(!task.is_null()) << from_here.ToString(); |
314 PendingTask pending_task( | 306 message_loop_proxy_->AddToIncomingQueue(from_here, task, delay, false); |
315 from_here, task, CalculateDelayedRuntime(delay), false); | |
316 AddToIncomingQueue(&pending_task, false); | |
317 } | 307 } |
318 | 308 |
319 void MessageLoop::Run() { | 309 void MessageLoop::Run() { |
320 RunLoop run_loop; | 310 RunLoop run_loop; |
321 run_loop.Run(); | 311 run_loop.Run(); |
322 } | 312 } |
323 | 313 |
324 void MessageLoop::RunUntilIdle() { | 314 void MessageLoop::RunUntilIdle() { |
325 RunLoop run_loop; | 315 RunLoop run_loop; |
326 run_loop.RunUntilIdle(); | 316 run_loop.RunUntilIdle(); |
(...skipping 23 matching lines...) Expand all Loading... | |
350 | 340 |
351 static void QuitCurrentWhenIdle() { | 341 static void QuitCurrentWhenIdle() { |
352 MessageLoop::current()->QuitWhenIdle(); | 342 MessageLoop::current()->QuitWhenIdle(); |
353 } | 343 } |
354 | 344 |
355 // static | 345 // static |
356 Closure MessageLoop::QuitWhenIdleClosure() { | 346 Closure MessageLoop::QuitWhenIdleClosure() { |
357 return Bind(&QuitCurrentWhenIdle); | 347 return Bind(&QuitCurrentWhenIdle); |
358 } | 348 } |
359 | 349 |
350 scoped_refptr<MessageLoopProxy> MessageLoop::message_loop_proxy() { | |
rvargas (doing something else)
2013/06/28 03:00:51
why de-inline this?
alexeypa (please no reviews)
2013/06/28 17:00:57
"base/message_loop/message_loop_proxy_impl.h" cann
| |
351 return message_loop_proxy_; | |
352 } | |
353 | |
360 void MessageLoop::SetNestableTasksAllowed(bool allowed) { | 354 void MessageLoop::SetNestableTasksAllowed(bool allowed) { |
361 if (nestable_tasks_allowed_ != allowed) { | 355 if (nestable_tasks_allowed_ != allowed) { |
362 nestable_tasks_allowed_ = allowed; | 356 nestable_tasks_allowed_ = allowed; |
363 if (!nestable_tasks_allowed_) | 357 if (!nestable_tasks_allowed_) |
364 return; | 358 return; |
365 // Start the native pump if we are not already pumping. | 359 // Start the native pump if we are not already pumping. |
366 pump_->ScheduleWork(); | 360 pump_->ScheduleWork(); |
367 } | 361 } |
368 } | 362 } |
369 | 363 |
370 bool MessageLoop::NestableTasksAllowed() const { | 364 bool MessageLoop::NestableTasksAllowed() const { |
371 return nestable_tasks_allowed_; | 365 return nestable_tasks_allowed_; |
372 } | 366 } |
373 | 367 |
374 bool MessageLoop::IsNested() { | 368 bool MessageLoop::IsNested() { |
375 return run_loop_->run_depth_ > 1; | 369 return run_loop_->run_depth_ > 1; |
376 } | 370 } |
377 | 371 |
378 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { | 372 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { |
379 DCHECK_EQ(this, current()); | 373 DCHECK_EQ(this, current()); |
380 task_observers_.AddObserver(task_observer); | 374 task_observers_.AddObserver(task_observer); |
381 } | 375 } |
382 | 376 |
383 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { | 377 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { |
384 DCHECK_EQ(this, current()); | 378 DCHECK_EQ(this, current()); |
385 task_observers_.RemoveObserver(task_observer); | 379 task_observers_.RemoveObserver(task_observer); |
386 } | 380 } |
387 | 381 |
388 void MessageLoop::AssertIdle() const { | 382 void MessageLoop::AssertIdle() const { |
rvargas (doing something else)
2013/06/28 03:00:51
This should probably be a ForTest method.
alexeypa (please no reviews)
2013/06/28 17:00:57
Done.
| |
389 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. | 383 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. |
390 AutoLock lock(incoming_queue_lock_); | 384 AutoLock lock(message_loop_proxy_->message_loop_lock_); |
rvargas (doing something else)
2013/06/28 03:00:51
we should do something to avoid grabbing this lock
alexeypa (please no reviews)
2013/06/28 17:00:57
Done.
| |
391 DCHECK(incoming_queue_.empty()); | 385 DCHECK(incoming_queue_.empty()); |
392 } | 386 } |
393 | 387 |
394 bool MessageLoop::is_running() const { | 388 bool MessageLoop::is_running() const { |
395 DCHECK_EQ(this, current()); | 389 DCHECK_EQ(this, current()); |
396 return run_loop_ != NULL; | 390 return run_loop_ != NULL; |
397 } | 391 } |
398 | 392 |
399 //------------------------------------------------------------------------------ | 393 //------------------------------------------------------------------------------ |
400 | 394 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
513 void MessageLoop::ReloadWorkQueue() { | 507 void MessageLoop::ReloadWorkQueue() { |
514 // We can improve performance of our loading tasks from incoming_queue_ to | 508 // We can improve performance of our loading tasks from incoming_queue_ to |
515 // work_queue_ by waiting until the last minute (work_queue_ is empty) to | 509 // work_queue_ by waiting until the last minute (work_queue_ is empty) to |
516 // load. That reduces the number of locks-per-task significantly when our | 510 // load. That reduces the number of locks-per-task significantly when our |
517 // queues get large. | 511 // queues get large. |
518 if (!work_queue_.empty()) | 512 if (!work_queue_.empty()) |
519 return; // Wait till we *really* need to lock and load. | 513 return; // Wait till we *really* need to lock and load. |
520 | 514 |
521 // Acquire all we can from the inter-thread queue with one lock acquisition. | 515 // Acquire all we can from the inter-thread queue with one lock acquisition. |
522 { | 516 { |
523 AutoLock lock(incoming_queue_lock_); | 517 AutoLock lock(message_loop_proxy_->message_loop_lock_); |
rvargas (doing something else)
2013/06/28 03:00:51
Maybe
message_loop_proxy_->LoadPendingTasks();
M
alexeypa (please no reviews)
2013/06/28 17:00:57
Done.
| |
524 if (incoming_queue_.empty()) | 518 if (incoming_queue_.empty()) |
525 return; | 519 return; |
526 incoming_queue_.Swap(&work_queue_); // Constant time | 520 incoming_queue_.Swap(&work_queue_); // Constant time |
527 DCHECK(incoming_queue_.empty()); | 521 DCHECK(incoming_queue_.empty()); |
528 } | 522 } |
529 } | 523 } |
530 | 524 |
531 bool MessageLoop::DeletePendingTasks() { | 525 bool MessageLoop::DeletePendingTasks() { |
532 bool did_work = !work_queue_.empty(); | 526 bool did_work = !work_queue_.empty(); |
533 while (!work_queue_.empty()) { | 527 while (!work_queue_.empty()) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
589 Time::ActivateHighResolutionTimer(false); | 583 Time::ActivateHighResolutionTimer(false); |
590 high_resolution_timer_expiration_ = TimeTicks(); | 584 high_resolution_timer_expiration_ = TimeTicks(); |
591 } | 585 } |
592 } | 586 } |
593 #endif | 587 #endif |
594 | 588 |
595 return delayed_run_time; | 589 return delayed_run_time; |
596 } | 590 } |
597 | 591 |
598 // Possibly called on a background thread! | 592 // Possibly called on a background thread! |
599 bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, | 593 void MessageLoop::AddToIncomingQueue(const tracked_objects::Location& from_here, |
600 bool use_try_lock) { | 594 const Closure& task, |
595 TimeDelta delay, | |
596 bool nestable) { | |
601 // Warning: Don't try to short-circuit, and handle this thread's tasks more | 597 // Warning: Don't try to short-circuit, and handle this thread's tasks more |
602 // directly, as it could starve handling of foreign threads. Put every task | 598 // directly, as it could starve handling of foreign threads. Put every task |
603 // into this queue. | 599 // into this queue. |
604 | 600 |
605 scoped_refptr<MessagePump> pump; | 601 // This should only be called while the lock is taken. |
606 { | 602 message_loop_proxy_->message_loop_lock_.AssertAcquired(); |
607 if (use_try_lock) { | |
608 if (!incoming_queue_lock_.Try()) { | |
609 pending_task->task.Reset(); | |
610 return false; | |
611 } | |
612 } else { | |
613 incoming_queue_lock_.Acquire(); | |
614 } | |
615 AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); | |
616 // Initialize the sequence number. The sequence number is used for delayed | |
617 // tasks (to faciliate FIFO sorting when two tasks have the same | |
618 // delayed_run_time value) and for identifying the task in about:tracing. | |
619 pending_task->sequence_num = next_sequence_num_++; | |
620 | 603 |
621 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", | 604 PendingTask pending_task( |
622 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this))); | 605 from_here, task, CalculateDelayedRuntime(delay), nestable); |
623 | 606 |
624 bool was_empty = incoming_queue_.empty(); | 607 // Initialize the sequence number. The sequence number is used for delayed |
625 incoming_queue_.push(*pending_task); | 608 // tasks (to faciliate FIFO sorting when two tasks have the same |
626 pending_task->task.Reset(); | 609 // delayed_run_time value) and for identifying the task in about:tracing. |
627 if (!was_empty) | 610 pending_task.sequence_num = next_sequence_num_++; |
628 return true; // Someone else should have started the sub-pump. | |
629 | 611 |
630 pump = pump_; | 612 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", |
631 } | 613 TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this))); |
632 // Since the incoming_queue_ may contain a task that destroys this message | |
633 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. | |
634 // We use a stack-based reference to the message pump so that we can call | |
635 // ScheduleWork outside of incoming_queue_lock_. | |
636 | 614 |
637 pump->ScheduleWork(); | 615 bool was_empty = incoming_queue_.empty(); |
638 return true; | 616 incoming_queue_.push(pending_task); |
617 pending_task.task.Reset(); | |
618 | |
619 // Wake up the pump. | |
620 if (was_empty) | |
621 pump_->ScheduleWork(); | |
639 } | 622 } |
640 | 623 |
641 //------------------------------------------------------------------------------ | 624 //------------------------------------------------------------------------------ |
642 // Method and data for histogramming events and actions taken by each instance | 625 // Method and data for histogramming events and actions taken by each instance |
643 // on each thread. | 626 // on each thread. |
644 | 627 |
645 void MessageLoop::StartHistogrammer() { | 628 void MessageLoop::StartHistogrammer() { |
646 #if !defined(OS_NACL) // NaCl build has no metrics code. | 629 #if !defined(OS_NACL) // NaCl build has no metrics code. |
647 if (enable_histogrammer_ && !message_histogram_ | 630 if (enable_histogrammer_ && !message_histogram_ |
648 && StatisticsRecorder::IsActive()) { | 631 && StatisticsRecorder::IsActive()) { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
825 fd, | 808 fd, |
826 persistent, | 809 persistent, |
827 mode, | 810 mode, |
828 controller, | 811 controller, |
829 delegate); | 812 delegate); |
830 } | 813 } |
831 | 814 |
832 #endif | 815 #endif |
833 | 816 |
834 } // namespace base | 817 } // namespace base |
OLD | NEW |