aboutsummaryrefslogtreecommitdiffstats
path: root/util/timer.lua
diff options
context:
space:
mode:
Diffstat (limited to 'util/timer.lua')
-rw-r--r--util/timer.lua62
1 files changed, 61 insertions, 1 deletions
diff --git a/util/timer.lua b/util/timer.lua
index 0e10e144..23bd6a37 100644
--- a/util/timer.lua
+++ b/util/timer.lua
@@ -6,6 +6,8 @@
-- COPYING file in the source package for more information.
--
+local indexedbheap = require "util.indexedbheap";
+local log = require "util.logger".init("timer");
local server = require "net.server";
local math_min = math.min
local math_huge = math.huge
@@ -13,6 +15,9 @@ local get_time = require "socket".gettime;
local t_insert = table.insert;
local pairs = pairs;
local type = type;
+local debug_traceback = debug.traceback;
+local tostring = tostring;
+local xpcall = xpcall;
local data = {};
local new_data = {};
@@ -78,6 +83,61 @@ else
end
end
-add_task = _add_task;
+--add_task = _add_task;
+
+local h = indexedbheap.create();
+local params = {};
+local next_time = nil;
+local _id, _callback, _now, _param;
+local function _call() return _callback(_now, _id, _param); end
+local function _traceback_handler(err) log("error", "Traceback[timer]: %s", debug_traceback(tostring(err), 2)); end
+local function _on_timer(now)
+ local peek;
+ while true do
+ peek = h:peek();
+ if peek == nil or peek > now then break; end
+ local _;
+ _, _callback, _id = h:pop();
+ _now = now;
+ _param = params[_id];
+ params[_id] = nil;
+ --item(now, id, _param); -- FIXME pcall
+ local success, err = xpcall(_call, _traceback_handler);
+ 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
+ return peek - now;
+ end
+end
+function add_task(delay, callback, param)
+ 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;
+ _add_task(next_time - current_time, _on_timer);
+ end
+ return id;
+end
+function stop(id)
+ params[id] = nil;
+ return h:remove(id);
+end
+function reschedule(id, delay)
+ local current_time = get_time();
+ local event_time = current_time + delay;
+ h:reprioritize(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
+ return id;
+end
return _M;