util.timer: Expire timer instance if another instance is already set to take care...
[prosody.git] / util / timer.lua
index 7ac4b616dd4a1222c819e138537fad0903f53797..78b4dbd71b46ce634073879eb74de7d9d0b0e1d5 100644 (file)
@@ -19,6 +19,7 @@ local _ENV = nil;
 
 local _add_task = server.add_task;
 
+local _active_timers = 0;
 local h = indexedbheap.create();
 local params = {};
 local next_time = nil;
@@ -40,29 +41,40 @@ local function _on_timer(now)
                if success and type(err) == "number" then
                        h:insert(_callback, err + now, _id); -- re-add
                        params[_id] = _param;
-                       end
                end
-       next_time = peek;
-       if peek ~= nil then
+       end
+
+       if peek ~= nil and _active_timers > 1 and peek == next_time then
+               -- Another instance of _on_timer already set next_time to the same value,
+               -- so it should be safe to not renew this timer event
+               peek = nil;
+       else
+               next_time = peek;
+       end
+
+       if peek then
+               -- peek is the time of the next event
                return peek - now;
        end
+       _active_timers = _active_timers - 1;
 end
 local function add_task(delay, callback, param)
-               local current_time = get_time();
+       local current_time = get_time();
        local event_time = current_time + delay;
 
        local id = h:insert(callback, event_time);
        params[id] = param;
        if next_time == nil or event_time < next_time then
                next_time = event_time;
+               _active_timers = _active_timers + 1;
                _add_task(next_time - current_time, _on_timer);
-                               end
+       end
        return id;
-                       end
+end
 local function stop(id)
        params[id] = nil;
        return h:remove(id);
-               end
+end
 local function reschedule(id, delay)
        local current_time = get_time();
        local event_time = current_time + delay;
@@ -70,7 +82,7 @@ local function reschedule(id, delay)
        if next_time == nil or event_time < next_time then
                next_time = event_time;
                _add_task(next_time - current_time, _on_timer);
-                       end
+       end
        return id;
 end