[webkit-reviews] review granted: [Bug 23865] Safari can be frozen by rapidly adding timers : [Attachment 38952] Updated patch.

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Fri Sep 4 18:06:17 PDT 2009


David Levin <levin at chromium.org> has granted Dmitry Titov
<dimich at chromium.org>'s request for review:
Bug 23865: Safari can be frozen by rapidly adding timers
https://bugs.webkit.org/show_bug.cgi?id=23865

Attachment 38952: Updated patch.
https://bugs.webkit.org/attachment.cgi?id=38952&action=review

------- Additional Comments from David Levin <levin at chromium.org>
This is basically equivalent to what was there before with the addition of a
maximum amount of time to process the timers.

The removal of m_timersReadyToFire may cause a newly added timer to callback
nearly immediately, but this should only happen for at most a millisecond
(depending on the resolution of currentTime is that low) until currentTime()
advances, so that seems fine.

A few nits below to fix on landing.

> diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
> +2009-09-02  Dmitry Titov  <dimich at chromium.org>
> +
> +	   Reviewed by NOBODY (OOPS!).
> +

> +	   https://bugs.webkit.org/show_bug.cgi?id=23865
> +
> +	   Prevent UI freeze in case when too many timers are in the timer
queue.
> +	   The fix measures the elapsed time while executing timers. If we have
too many

> +	   timers and it take significant time to fire, quit the loop and
reschedule.
"timers and it take*s*"

> +	   This lets run loop to process user input (close the window for
example).

This lets the run loop process user input (close the window for example).

> +	   (WebCore::TimerBase::setNextFireTime):
> +	   Since timers are now fired one by one, there is no need to keep
track of updated timers.
> +	   * manual-tests/input-starved-by-timers.html: manual test that
attempts to freeze browser by
*M*anual test that...


> diff --git a/WebCore/manual-tests/input-starved-by-timers.html
b/WebCore/manual-tests/input-starved-by-timers.html
> +var targetLatency = 10000; // multiply timers until it takes this much to
fire all their callbacks.
*M*ultiply


> +    // Create more timers, capture the current time so when callbacks are
fired,
Create more timers. Capture the ...


> +function runTest() {
> +  log("Freezing UI...");
> +  setTimeout(function() { timerCallback(new Date().getTime()); }, 0);
> +  setTimeout("multiplyFactor = 0; log('Finishing. Started to drain
timers.');", 10000);

It would be nice to stick with the 4 space indent that you did above.

> diff --git a/WebCore/platform/ThreadTimers.cpp
b/WebCore/platform/ThreadTimers.cpp
>  namespace WebCore {
>  
> +// Fire timers until this time, then quit to let the run loop to process
user input events.

Consider:
  Fire timers for this length of time, and then quit to let the run loop
process user input events.

> +// 100ms is about perceptable delay in UI, have a half of ot as a threshold.


Consider:
  100ms is about a perceptible delay in UI, so use have a half of that as a
threshold.

> +// This is to prevent UI freeze when there are too much timers or machine
performance is low.

s/much/many/

> +    while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <=
fireTime) {
...
> +	   // Catch the case where the timer asked timers to fire in a nested
event loop, or we are over time limit.
> +	   if (!m_firingTimers || timeToQuit < currentTime())

Consider making this part of the "while" condition (of course that means the
loop would never execute if timeToQuit > currentTime() at the beginning of the
loop. 

On further consideration, I think this should remain here because that way we
ensure that at least one timer got fired. (I had a hard time seeing how that
could happen but maybe there is a slow/loaded machine...)


More information about the webkit-reviews mailing list