mod_posix: Move everything to util.startup
This allows greater control over the order of events.
Notably, the internal ordering between daemonization, initialization of
libunbound and setup of signal handling is sensitive.
libunbound starts a separate thread for processing DNS requests.
If this thread is started before signal handling has been set up, it
will not inherit the signal handlers and instead behave as it would have
before signal handlers were set up, i.e. cause the whole process to
immediately exit.
libunbound is usually initialized on the first DNS request, usually
triggered by an outgoing s2s connection attempt.
If daemonization happens before signals have been set up, signals may
not be processed at all.
-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local indexedbheap = require "prosody.util.indexedbheap";
local log = require "prosody.util.logger".init("timer");
local server = require "prosody.net.server";
local get_time = require "prosody.util.time".now
local type = type;
local debug_traceback = debug.traceback;
local tostring = tostring;
local xpcall = require "prosody.util.xpcall".xpcall;
local math_max = math.max;
local pairs = pairs;
if server.timer then
-- The selected net.server implements this API, so defer to that
return server.timer;
end
local _ENV = nil;
-- luacheck: std none
local _add_task = server.add_task;
local _server_timer;
local _active_timers = 0;
local h = indexedbheap.create();
local params = {};
local next_time = nil;
local function _traceback_handler(err) log("error", "Traceback[timer]: %s", debug_traceback(tostring(err), 2)); end
local function _on_timer(now)
local peek;
local readd;
while true do
peek = h:peek();
if peek == nil or peek > now then break; end
local _, callback, id = h:pop();
local param = params[id];
params[id] = nil;
--item(now, id, _param);
local success, err = xpcall(callback, _traceback_handler, now, id, param);
if success and type(err) == "number" then
if readd then
readd[id] = { callback, err + now };
else
readd = { [id] = { callback, err + now } };
end
params[id] = param;
end
end
if readd then
for id,timer in pairs(readd) do
h:insert(timer[1], timer[2], id);
end
peek = h:peek();
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 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;
if _server_timer then
_server_timer:close();
_server_timer = nil;
else
_active_timers = _active_timers + 1;
end
_server_timer = _add_task(next_time - current_time, _on_timer);
end
return id;
end
local function stop(id)
params[id] = nil;
local result, item, result_sync = h:remove(id);
local peek = h:peek();
if peek ~= next_time and _server_timer then
next_time = peek;
_server_timer:close();
if next_time ~= nil then
_server_timer = _add_task(math_max(next_time - get_time(), 0), _on_timer);
end
end
return result, item, result_sync;
end
local 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 {
add_task = add_task;
stop = stop;
reschedule = reschedule;
};