Bug 1964039 - Avoid to use SetDelay in namedTimer. r=sync-reviewers,markh

Using SetDelay on an existing ONE_SHOT timer is a convenient way to re-schedule a timer that did not yet fire.

However, if the timer fired already but the callback did not yet fully execute and the caller still thinks
to have a pending timer, our internal book-keeping will already have removed the timer from the list and
SetDelay will not re-activate the timer for us.

namedTimer instead seems to expect to always have activated a timer when called. We can still reuse the existing
timer object but need to always call initWithCallback which takes care of all the book-keeping details for us.
Note that this does not change much in terms of effort, as also SetDelay removes and then re-adds the timer from
and to the active timers list.

Differential Revision: https://phabricator.services.mozilla.com/D247440
This commit is contained in:
Jens Stutte
2025-05-15 16:34:30 +00:00
committed by jstutte@mozilla.com
parent 6dde4e5cbf
commit ddeb6c7c01

View File

@@ -132,6 +132,14 @@ export var CommonUtils = {
* Return a timer that is scheduled to call the callback after waiting the
* provided time or as soon as possible. The timer will be set as a property
* of the provided object with the given timer name.
*
* Note that an existing timer with the same name on the same object will be
* canceled and rescheduled with the new callback if you call this function
* before it fired.
* This may race with the imminent firing of the existing timer, so be
* prepared to see it firing twice once in a while if called multiple times
* for the same timer (the alternative would be to see it firing once right
* now and to see nothing happen after the expected delay).
*/
namedTimer: function namedTimer(callback, wait, thisObj, name) {
if (!thisObj || !name) {
@@ -140,22 +148,23 @@ export var CommonUtils = {
);
}
// Delay an existing timer if it exists
let timer = null;
// Take an existing timer if it exists
if (name in thisObj && thisObj[name] instanceof Ci.nsITimer) {
thisObj[name].delay = wait;
return thisObj[name];
}
// Setting just the delay on an existing but inactive timer will not
// schedule the timer again. Let's go through initWithCallback always.
timer = thisObj[name];
} else {
// Create a special timer that we can add extra properties
let timer = Object.create(
timer = Object.create(
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
);
// Provide an easy way to clear out the timer
timer.clear = function () {
thisObj[name] = null;
timer.cancel();
};
}
// Initialize the timer with a smart callback
timer.initWithCallback(