util.encodings: Spell out all IDNA 2008 options ICU has
[prosody.git] / util / timer.lua
blob4670e196f72f3d8546fadb31879806c0684180aa
1 -- Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 --
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
9 local indexedbheap = require "util.indexedbheap";
10 local log = require "util.logger".init("timer");
11 local server = require "net.server";
12 local get_time = require "util.time".now
13 local type = type;
14 local debug_traceback = debug.traceback;
15 local tostring = tostring;
16 local xpcall = require "util.xpcall".xpcall;
17 local math_max = math.max;
19 local _ENV = nil;
20 -- luacheck: std none
22 local _add_task = server.add_task;
24 local _server_timer;
25 local _active_timers = 0;
26 local h = indexedbheap.create();
27 local params = {};
28 local next_time = nil;
29 local function _traceback_handler(err) log("error", "Traceback[timer]: %s", debug_traceback(tostring(err), 2)); end
30 local function _on_timer(now)
31 local peek;
32 while true do
33 peek = h:peek();
34 if peek == nil or peek > now then break; end
35 local _, callback, id = h:pop();
36 local param = params[id];
37 params[id] = nil;
38 --item(now, id, _param);
39 local success, err = xpcall(callback, _traceback_handler, now, id, param);
40 if success and type(err) == "number" then
41 h:insert(callback, err + now, id); -- re-add
42 params[id] = param;
43 end
44 end
46 if peek ~= nil and _active_timers > 1 and peek == next_time then
47 -- Another instance of _on_timer already set next_time to the same value,
48 -- so it should be safe to not renew this timer event
49 peek = nil;
50 else
51 next_time = peek;
52 end
54 if peek then
55 -- peek is the time of the next event
56 return peek - now;
57 end
58 _active_timers = _active_timers - 1;
59 end
60 local function add_task(delay, callback, param)
61 local current_time = get_time();
62 local event_time = current_time + delay;
64 local id = h:insert(callback, event_time);
65 params[id] = param;
66 if next_time == nil or event_time < next_time then
67 next_time = event_time;
68 if _server_timer then
69 _server_timer:close();
70 _server_timer = nil;
71 else
72 _active_timers = _active_timers + 1;
73 end
74 _server_timer = _add_task(next_time - current_time, _on_timer);
75 end
76 return id;
77 end
78 local function stop(id)
79 params[id] = nil;
80 local result, item, result_sync = h:remove(id);
81 local peek = h:peek();
82 if peek ~= next_time and _server_timer then
83 next_time = peek;
84 _server_timer:close();
85 if next_time ~= nil then
86 _server_timer = _add_task(math_max(next_time - get_time(), 0), _on_timer);
87 end
88 end
89 return result, item, result_sync;
90 end
91 local function reschedule(id, delay)
92 local current_time = get_time();
93 local event_time = current_time + delay;
94 h:reprioritize(id, delay);
95 if next_time == nil or event_time < next_time then
96 next_time = event_time;
97 _add_task(next_time - current_time, _on_timer);
98 end
99 return id;
102 return {
103 add_task = add_task;
104 stop = stop;
105 reschedule = reschedule;