Diff

util/timer.lua @ 5877:615a0774e4cc

util.timer: Updated to use util.indexedbheap to provide a more complete API. Timers can now be stopped or rescheduled. Callbacks are now pcall'd. Adding/removing timers from within timer callbacks works better. Optional parameter can be passed when creating timer which gets passed to callback, eliminating the need for closures in various timer uses. Timers are now much more lightweight.
author Waqas Hussain <waqas20@gmail.com>
date Wed, 30 Oct 2013 17:44:42 -0400
parent 5776:bd0ff8ae98a8
child 5878:2b1c0c0a2ea6
line wrap: on
line diff
--- a/util/timer.lua	Wed Oct 30 17:30:35 2013 -0400
+++ b/util/timer.lua	Wed Oct 30 17:44:42 2013 -0400
@@ -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
@@ -78,6 +80,60 @@
 	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", 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
+		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;