Index: base/message_loop/message_pump_mac.mm |
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm |
index 0ab9ab7c467de5128be33444db018ce73d369f7d..205bd3e2f229c6c424fe55bc584fb21a3bfbfc06 100644 |
--- a/base/message_loop/message_pump_mac.mm |
+++ b/base/message_loop/message_pump_mac.mm |
@@ -553,10 +553,40 @@ bool MessagePumpCFRunLoopBase::RunWork() { |
// released promptly even in the absence of UI events. |
MessagePumpScopedAutoreleasePool autorelease_pool(this); |
- // Call DoWork and DoDelayedWork once, and if something was done, arrange to |
- // come back here again as long as the loop is still running. |
- bool did_work = delegate_->DoWork(); |
- bool resignal_work_source = did_work; |
+ // Allocate a time slice in which as many tasks as possible will be run. |
+ // Performing only one task per run loop tick is potentially inefficient in |
+ // the face of a large backlog of pending tasks. https://crbug.com/264886 |
+ base::TimeTicks now = base::TimeTicks::Now(); |
+ base::TimeTicks time_slice_end = now + base::TimeDelta::FromMilliseconds(50); |
+ int ran_task_count = 0; |
+ bool did_work = false, did_work_last_slice = true; |
+ for ( ; |
+ now < time_slice_end && did_work_last_slice; |
+ now = base::TimeTicks::Now()) { |
+ quit_was_called_ = false; |
+ did_work_last_slice = delegate_->DoWork(); |
+ did_work |= did_work_last_slice; |
+ if (quit_was_called_) |
+ break; |
+ if (did_work_last_slice) |
+ ++ran_task_count; |
+ } |
+ |
+ // Record how many tasks were accomplished in the time slice, and by how |
+ // much the work overran the time slice deadline. |
+ UMA_HISTOGRAM_CUSTOM_TIMES("MessagePumpMac.TimeSliceOverRun", |
+ time_slice_end - base::TimeTicks::Now(), |
+ base::TimeDelta::FromMilliseconds(1), |
+ base::TimeDelta::FromSeconds(5), |
+ 100); |
+ UMA_HISTOGRAM_COUNTS("MessagePumpMac.TimeSliceTaskCount", ran_task_count); |
+ |
+ if (quit_was_called_) |
+ return false; |
+ |
+ // If the time slice expired and work was done in the last fraction of the |
+ // time slice, arrange to come back here to execute more tasks. |
+ bool resignal_work_source = did_work_last_slice; |
TimeTicks next_time; |
delegate_->DoDelayedWork(&next_time); |
@@ -795,6 +825,7 @@ void MessagePumpCFRunLoop::DoRun(Delegate* delegate) { |
// Must be called on the run loop thread. |
void MessagePumpCFRunLoop::Quit() { |
+ quit_was_called_ = true; |
// Stop the innermost run loop managed by this MessagePumpCFRunLoop object. |
if (nesting_level() == run_nesting_level()) { |
// This object is running the innermost loop, just stop it. |
@@ -849,6 +880,7 @@ void MessagePumpNSRunLoop::DoRun(Delegate* delegate) { |
} |
void MessagePumpNSRunLoop::Quit() { |
+ quit_was_called_ = true; |
keep_running_ = false; |
CFRunLoopSourceSignal(quit_source_); |
CFRunLoopWakeUp(run_loop()); |
@@ -923,6 +955,7 @@ void MessagePumpNSApplication::DoRun(Delegate* delegate) { |
} |
void MessagePumpNSApplication::Quit() { |
+ quit_was_called_ = true; |
if (!running_own_loop_) { |
[[NSApplication sharedApplication] stop:nil]; |
} else { |