Commit 9316d3b9 authored by jbauman's avatar jbauman Committed by Commit bot

Process pending delayed tasks in kMsgHaveWork

With 1 win32 timer we can only get a callback every 10ms, and since the callback only processes one message, that means the queue could keep growing if delayed tasks are posted faster than that rate, even if they're processed very quickly. To prevent that, schedule a kMsgHaveWork if there's 0ms until the next delayed task should run, and run a delayed task in the kMsgHaveWork handler.

BUG=454333
TEST=chrome resizes smoothly

Review URL: https://codereview.chromium.org/918473002

Cr-Commit-Position: refs/heads/master@{#330816}
parent 07ea5387
...@@ -122,44 +122,8 @@ void MessagePumpForUI::ScheduleWork() { ...@@ -122,44 +122,8 @@ void MessagePumpForUI::ScheduleWork() {
} }
void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
//
// We would *like* to provide high resolution timers. Windows timers using
// SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
// mechanism because the application can enter modal windows loops where it
// is not running our MessageLoop; the only way to have our timers fire in
// these cases is to post messages there.
//
// To provide sub-10ms timers, we process timers directly from our run loop.
// For the common case, timers will be processed there as the run loop does
// its normal work. However, we *also* set the system timer so that WM_TIMER
// events fire. This mops up the case of timers not being able to work in
// modal message loops. It is possible for the SetTimer to pop and have no
// pending timers, because they could have already been processed by the
// run loop itself.
//
// We use a single SetTimer corresponding to the timer that will expire
// soonest. As new timers are created and destroyed, we update SetTimer.
// Getting a spurrious SetTimer event firing is benign, as we'll just be
// processing an empty timer queue.
//
delayed_work_time_ = delayed_work_time; delayed_work_time_ = delayed_work_time;
RescheduleTimer();
int delay_msec = GetCurrentDelay();
DCHECK_GE(delay_msec, 0);
if (delay_msec < USER_TIMER_MINIMUM)
delay_msec = USER_TIMER_MINIMUM;
// Create a WM_TIMER event that will wake us up to check for any pending
// timers (in case we are running within a nested, external sub-pump).
BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),
delay_msec, NULL);
if (ret)
return;
// If we can't set timers, we are in big trouble... but cross our fingers for
// now.
// TODO(jar): If we don't see this error, use a CHECK() here instead.
UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
MESSAGE_LOOP_PROBLEM_MAX);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -318,6 +282,8 @@ void MessagePumpForUI::HandleWorkMessage() { ...@@ -318,6 +282,8 @@ void MessagePumpForUI::HandleWorkMessage() {
// needs to do more work. // needs to do more work.
if (state_->delegate->DoWork()) if (state_->delegate->DoWork())
ScheduleWork(); ScheduleWork();
state_->delegate->DoDelayedWork(&delayed_work_time_);
RescheduleTimer();
} }
void MessagePumpForUI::HandleTimerMessage() { void MessagePumpForUI::HandleTimerMessage() {
...@@ -330,9 +296,51 @@ void MessagePumpForUI::HandleTimerMessage() { ...@@ -330,9 +296,51 @@ void MessagePumpForUI::HandleTimerMessage() {
return; return;
state_->delegate->DoDelayedWork(&delayed_work_time_); state_->delegate->DoDelayedWork(&delayed_work_time_);
if (!delayed_work_time_.is_null()) { RescheduleTimer();
// A bit gratuitous to set delayed_work_time_ again, but oh well. }
ScheduleDelayedWork(delayed_work_time_);
void MessagePumpForUI::RescheduleTimer() {
if (delayed_work_time_.is_null())
return;
//
// We would *like* to provide high resolution timers. Windows timers using
// SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
// mechanism because the application can enter modal windows loops where it
// is not running our MessageLoop; the only way to have our timers fire in
// these cases is to post messages there.
//
// To provide sub-10ms timers, we process timers directly from our run loop.
// For the common case, timers will be processed there as the run loop does
// its normal work. However, we *also* set the system timer so that WM_TIMER
// events fire. This mops up the case of timers not being able to work in
// modal message loops. It is possible for the SetTimer to pop and have no
// pending timers, because they could have already been processed by the
// run loop itself.
//
// We use a single SetTimer corresponding to the timer that will expire
// soonest. As new timers are created and destroyed, we update SetTimer.
// Getting a spurrious SetTimer event firing is benign, as we'll just be
// processing an empty timer queue.
//
int delay_msec = GetCurrentDelay();
DCHECK_GE(delay_msec, 0);
if (delay_msec == 0) {
ScheduleWork();
} else {
if (delay_msec < USER_TIMER_MINIMUM)
delay_msec = USER_TIMER_MINIMUM;
// Create a WM_TIMER event that will wake us up to check for any pending
// timers (in case we are running within a nested, external sub-pump).
BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),
delay_msec, NULL);
if (ret)
return;
// If we can't set timers, we are in big trouble... but cross our fingers
// for now.
// TODO(jar): If we don't see this error, use a CHECK() here instead.
UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
MESSAGE_LOOP_PROBLEM_MAX);
} }
} }
......
...@@ -130,6 +130,7 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin { ...@@ -130,6 +130,7 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
void WaitForWork(); void WaitForWork();
void HandleWorkMessage(); void HandleWorkMessage();
void HandleTimerMessage(); void HandleTimerMessage();
void RescheduleTimer();
bool ProcessNextWindowsMessage(); bool ProcessNextWindowsMessage();
bool ProcessMessageHelper(const MSG& msg); bool ProcessMessageHelper(const MSG& msg);
bool ProcessPumpReplacementMessage(); bool ProcessPumpReplacementMessage();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment