reworking signal system

This commit is contained in:
Axel Kittenberger 2018-06-04 08:54:06 +02:00
parent 5965c0ea59
commit 9fa9ea72da
18 changed files with 173 additions and 177 deletions

View File

@ -221,7 +221,8 @@ handle_event(
lua_pop( L, 1 ); lua_pop( L, 1 );
hup = 1; // FIXME report this to mantle more sensible
softreset = true;
return; return;
} }
@ -446,7 +447,7 @@ inotify_ready(
{ {
int i = 0; int i = 0;
while( i < len && !hup && !term ) while( i < len && !softreset )
{ {
struct inotify_event *event = ( struct inotify_event * ) ( readbuf + i ); struct inotify_event *event = ( struct inotify_event * ) ( readbuf + i );

View File

@ -208,27 +208,6 @@ masterloop(
lua_pop( L, 1 ); lua_pop( L, 1 );
} }
// reacts on HUP signals
if( hup )
{
load_mci( L, "hup" );
if( lua_pcall( L, 0, 0, -2 ) ) exit( -1 );
lua_pop( L, 1 );
hup = 0;
}
// reacts on TERM and INT signals
if( term == 1 )
{
load_mci( L, "term" );
lua_pushnumber( L, sigcode );
if( lua_pcall( L, 1, 0, -3 ) ) exit( -1 );
lua_pop( L, 1 );
term = 2;
}
// lets the mantle do stuff every cycle, // lets the mantle do stuff every cycle,
// like starting new processes, writing the statusfile etc. // like starting new processes, writing the statusfile etc.
load_mci( L, "cycle" ); load_mci( L, "cycle" );
@ -500,13 +479,8 @@ main( int argc, char * argv[ ] )
setlinebuf( stdout ); setlinebuf( stdout );
setlinebuf( stderr ); setlinebuf( stderr );
while( !term ) while( true ) main1( argc, argv );
{
main1( argc, argv );
}
// exits with error code responding to the signal it died for // return -1;
// FIXME this no longer holds true to systemd recommendations
return 128 + sigcode;
} }

View File

@ -410,6 +410,18 @@ l_realdir( lua_State *L )
} }
/*
| Soft resets Lsyncd.
| Typical as reaction on a HUP signal.
*/
static int
l_softreset( lua_State *L )
{
softreset = 1;
return 0;
}
/* /*
| Dumps the Lua stack. | Dumps the Lua stack.
| For debugging purposes. | For debugging purposes.
@ -490,7 +502,7 @@ l_readdir( lua_State *L )
lua_newtable( L ); lua_newtable( L );
while( !hup && !term ) while( !softreset )
{ {
struct dirent *de = readdir( d ); struct dirent *de = readdir( d );
bool isdir; bool isdir;
@ -657,6 +669,7 @@ static const luaL_Reg corelib[ ] =
{ "onsignal", l_onsignal }, { "onsignal", l_onsignal },
{ "readdir", l_readdir }, { "readdir", l_readdir },
{ "realdir", l_realdir }, { "realdir", l_realdir },
{ "sofotreset", l_softreset },
{ "stackdump", l_stackdump }, { "stackdump", l_stackdump },
{ "terminate", l_terminate }, { "terminate", l_terminate },
{ NULL, NULL } { NULL, NULL }

View File

@ -24,11 +24,19 @@
#include "mem.h" #include "mem.h"
/**
| Set to true to soft reset at earliest possilibity.
*/
bool softreset = false;
/** /**
* An observance to be called when a file descritor becomes * An observance to be called when a file descritor becomes
* read-ready or write-ready. * read-ready or write-ready.
*/ */
struct observance { struct observance
{
// The file descriptor to observe. // The file descriptor to observe.
int fd; int fd;
@ -261,14 +269,12 @@ observe_select
struct observance *obs = observances + pi; struct observance *obs = observances + pi;
int fd = obs->fd; int fd = obs->fd;
// checks for signals if( softreset ) break;
if( hup || term ) break;
// a file descriptor became read-ready // a file descriptor became read-ready
if( obs->ready && FD_ISSET( fd, &rfds ) ) obs->ready( L, fd, obs->extra ); if( obs->ready && FD_ISSET( fd, &rfds ) ) obs->ready( L, fd, obs->extra );
// Checks for signals, again, better safe than sorry if( softreset ) break;
if ( hup || term ) break;
// FIXME breaks on multiple nonobservances in one beat // FIXME breaks on multiple nonobservances in one beat
if( if(

View File

@ -33,4 +33,7 @@ extern void observe_tidy_all( );
// stops the core to observe a file descriptor // stops the core to observe a file descriptor
extern void nonobserve_fd( int fd ); extern void nonobserve_fd( int fd );
// set to true to soft reset at earliest possilibity
extern bool softreset;
#endif #endif

View File

@ -46,17 +46,6 @@ static int handlers_maxlen;
static int handlers_len; static int handlers_len;
/*
| Set by TERM or HUP signal handler
| telling Lsyncd should end or reset ASAP.
|
| FIXME remove
*/
volatile sig_atomic_t hup = 0;
volatile sig_atomic_t term = 0;
volatile sig_atomic_t sigcode = 0;
/* /*
| signal handler | signal handler
*/ */
@ -247,11 +236,27 @@ l_onsignal(
} }
/*
| Sends a signal to another process.
|
| Params on Lua stack:
| 1: process id (pid) to send a signal to
| 2: the signal to send
|
| Returns on Lua stack:
|
| nada
*/
int int
l_kill( l_kill(
lua_State *L lua_State *L
) )
{ {
int pid = luaL_checkinteger( L, 1 );
int sid = luaL_checkinteger( L, 2 );
kill( pid, sid );
return 0; return 0;
} }

View File

@ -9,11 +9,6 @@
#ifndef LSYNCD_SIGNAL_H #ifndef LSYNCD_SIGNAL_H
#define LSYNCD_SIGNAL_H #define LSYNCD_SIGNAL_H
// set to 1 on hup signal or term signal
extern volatile sig_atomic_t hup;
extern volatile sig_atomic_t term;
extern volatile sig_atomic_t sigcode;
// initializes signal handling. // initializes signal handling.
extern void signal_init( ); extern void signal_init( );

View File

@ -98,6 +98,12 @@ default.collect = function
local rc local rc
if agent.syncStopped
then
log( 'Normal', 'Sync stopped, ignoring exitcode of finished child' )
return 'ok'
end
if config.exitcodes if config.exitcodes
then then
rc = config.exitcodes[ exitcode ] rc = config.exitcodes[ exitcode ]
@ -115,9 +121,7 @@ default.collect = function
then then
log( log(
'Normal', 'Normal',
'Startup of ', 'Startup of ',agent.source, ' -> ',agent.target,' finished.'
agent.source, ' -> ', agent.target,
' finished.'
) )
return 'ok' return 'ok'
@ -133,15 +137,6 @@ default.collect = function
) )
return 'again' return 'again'
else
log(
'Error',
'Temporary or permanent failure on startup of ',
agent.source, ' -> ', agent.target,
'. Terminating since "insist" is not set.'
)
terminate( -1 )
end end
elseif rc == 'die' elseif rc == 'die'
then then

View File

@ -141,14 +141,7 @@ direct.collect = function
log( 'Normal', 'Startup of "',agent.source,'" finished: ', exitcode ) log( 'Normal', 'Startup of "',agent.source,'" finished: ', exitcode )
elseif rc == 'again' elseif rc == 'again'
then then
if settings( 'insist' ) log( 'Normal', 'Retrying startup of "',agent.source,'": ', exitcode )
then
log( 'Normal', 'Retrying startup of "',agent.source,'": ', exitcode )
else
log('Error', 'Temporary or permanent failure on startup of "',
agent.source, '". Terminating since "insist" is not set.');
terminate( -1 )
end
elseif rc == 'die' elseif rc == 'die'
then then
log( 'Error', 'Failure on startup of "',agent.source,'": ', exitcode ) log( 'Error', 'Failure on startup of "',agent.source,'": ', exitcode )

View File

@ -365,18 +365,7 @@ rsyncssh.collect = function
log( 'Normal', 'Startup of "', agent.source, '" finished: ', exitcode ) log( 'Normal', 'Startup of "', agent.source, '" finished: ', exitcode )
elseif rc == 'again' elseif rc == 'again'
then then
if settings('insist') log( 'Normal', 'Retrying startup of "', agent.source, '": ', exitcode )
then
log( 'Normal', 'Retrying startup of "', agent.source, '": ', exitcode )
else
log(
'Error',
'Temporary or permanent failure on startup of "',
agent.source, '". Terminating since "insist" is not set.'
)
terminate( -1 ) -- ERRNO
end
elseif rc == 'die' elseif rc == 'die'
then then
log( 'Error', 'Failure on startup of "', agent.source, '": ', exitcode ) log( 'Error', 'Failure on startup of "', agent.source, '": ', exitcode )

View File

@ -15,60 +15,64 @@ default.signal = { }
-- --
-- Returns a signal handler for 'signal'.
-- --
-- local function makeSignalHandler
local function onCollect
( (
sync -- the user intf to the sync a child finished for sig, -- the signal to handle
logtext, -- text to log
finish -- function to call after all child processes have been collected
) )
if( sync.processCount( ) == 0 ) then syncs.remove( sync ) end return function( )
log( 'Normal', 'Received an ',sig,' signal, ',logtext )
if #syncs == 0 then os.exit( 0 ) end local pCount = 0
end
for _, sync in ipairs( syncs )
do
sync.stop( )
local function sighup local pids = sync.pids( )
( ) local pc = #pids
print( 'GOT A HUP SIGNAL' )
os.exit( 1 ) if( pc == 0 )
end then
syncs.remove( sync )
else
pCount = pCount + pc
sync.onCollect(
function
(
sync -- the user intf to the sync a child finished for
)
if( sync.processCount( ) == 0 ) then syncs.remove( sync ) end
if #syncs == 0 then finish( ) end
end
)
local function sigint for _, pid in ipairs( pids ) do signal( pid, sig ) end
( ) end
log( 'Normal', 'Received an INT signal, terminating' )
local pCount = 0
for _, sync in ipairs( syncs )
do
sync.stop( )
local c = sync.processCount( )
if( c == 0 )
then
syncs.remove( sync )
else
pCount = pCount + c
sync.onCollect( onCollect )
end end
if #syncs == 0 then finish( ) end
log( 'Normal', 'Waiting for ', pCount, ' child processes.' )
end end
if #syncs == 0 then os.exit( 0 ) end
log( 'Normal', 'Waiting for ', pCount, ' child processes.' )
end end
local function sigterm local function finishHup( )
( ) os.exit( 0 )
print( 'GOT A TERM SIGNAL' )
os.exit( 1 )
end end
local function finishInt( )
os.exit( 0 )
end
local function finishTerm( )
os.exit( 0 )
end
-- --
-- Sets up the default HUP/INT/TERM signal handlers. -- Sets up the default HUP/INT/TERM signal handlers.
@ -82,14 +86,10 @@ init =
local int = getsignal( 'INT' ) local int = getsignal( 'INT' )
local term = getsignal( 'TERM' ) local term = getsignal( 'TERM' )
if hup ~= false then hup = sighup end if hup ~= false then hup = makeSignalHandler( 'HUP', 'resetting', finishHup ) end
if int ~= false then int = sigint end if int ~= false then int = makeSignalHandler( 'INT', 'terminating', finishInt ) end
if term ~= false then term = sigterm end if term ~= false then term = makeSignalHandler( 'TERM', 'terminating', finishTerm ) end
onsignal( onsignal( 'HUP', hup, 'INT', int, 'TERM', term )
'HUP', hup,
'INT', int,
'TERM', term
)
end end

View File

@ -54,9 +54,6 @@ OPTIONS
*-help*:: *-help*::
Show a help message. Show a help message.
*-insist*::
Continues start up even if rsync cannot connect.
*-log* 'LEVEL':: *-log* 'LEVEL'::
Controls which kind of events are logged. By default Lsyncd logs 'Normal' Controls which kind of events are logged. By default Lsyncd logs 'Normal'
and 'Error' Messages. *-log scarce* will make Lsyncd log Error messages and 'Error' Messages. *-log scarce* will make Lsyncd log Error messages

View File

@ -95,24 +95,6 @@ mt.__ipairs = function
end end
--
-- Creates a new counter.
--
local function new
( )
-- k_nt is a native table, private to this object.
local o =
{
[ k_size ] = 0,
[ k_nt ] = { }
}
setmetatable( o, mt )
return o
end
-- --
-- Creates a copy of the counter -- Creates a copy of the counter
-- --
@ -132,8 +114,27 @@ local function copy
return copy return copy
end end
--
-- Creates a new counter.
--
local function new
( )
-- k_nt is a native table, private to this object.
local o =
{
[ k_size ] = 0,
[ k_nt ] = { }
}
setmetatable( o, mt )
return o
end
-- --
-- Exported interface. -- Exported interface.
-- --
Counter = { new = new } Counter = { new = new, copy = copy }

View File

@ -268,6 +268,17 @@ local eventFields =
return e2d[ event ].sync.source .. cutSlash( getPath( event ) ) return e2d[ event ].sync.source .. cutSlash( getPath( event ) )
end, end,
--
-- Returns true if the sync this event belongs
-- to is stopped
--
syncStopped = function
(
event
)
return e2d[ event ].sync.stopped
end,
-- --
-- Returns the configured target. -- Returns the configured target.
-- --
@ -411,15 +422,9 @@ local eventListMeta =
elist, elist,
func func
) )
if func == 'isList' if func == 'isList' then return true end
then
return true
end
if func == 'config' if func == 'config' then return e2d[ elist ].sync.config end
then
return e2d[ elist ].sync.config
end
local f = eventListFuncs[ func ] local f = eventListFuncs[ func ]

View File

@ -563,6 +563,7 @@ end
-- --
mci.inotifyEvent = Inotify.event mci.inotifyEvent = Inotify.event
-- --
-- Collector for every child process that finished in startup phase -- Collector for every child process that finished in startup phase
-- --
@ -593,6 +594,7 @@ end
-- --
-- Called by core on a hup signal. -- Called by core on a hup signal.
-- FIXME remove
-- --
function mci.hup function mci.hup
( ) ( )
@ -601,8 +603,10 @@ function mci.hup
lsyncdStatus = 'fade' lsyncdStatus = 'fade'
end end
-- --
-- Called by core on a term signal. -- Called by core on a term signal.
-- FIXME remove
-- --
function mci.term function mci.term
( (

View File

@ -43,7 +43,7 @@ local sigHandlerCount = 0
-- --
-- In case of a invalid signal specifie an error is raised. -- In case of a invalid signal specifie an error is raised.
-- --
local function toSignum function signum
( (
signal signal
) )
@ -59,14 +59,9 @@ local function toSignum
return signal return signal
elseif type( signal ) == 'string' elseif type( signal ) == 'string'
then then
signum = signums[ signal ] local sn = signums[ signal ]
if sn == nil then error( 'signal "' .. signal .. '" unknown.' , 3 ) end
if signum == nil return sn
then
error( 'signal "' .. signal .. '" unknown.' , 3 )
end
return signum
elseif signal == false elseif signal == false
then then
return false return false
@ -102,10 +97,8 @@ function onsignal
do do
local signal = arg[ a ] local signal = arg[ a ]
local handler = arg[ a + 1 ] local handler = arg[ a + 1 ]
local sn = signum( signal )
local signum = toSignum( signal ) sigHandlers[ sn ] = handler
sigHandlers[ signum ] = handler
end end
core.onsignal( sigHandlers ) core.onsignal( sigHandlers )
@ -131,16 +124,29 @@ mci.signalEvent =
( (
sigtable sigtable
) )
for _, signum in ipairs( sigtable ) for _, sn in ipairs( sigtable )
do do
local handler = sigHandlers[ signum ] local handler = sigHandlers[ sn ]
if not handler if not handler
then then
log( 'Error', 'Received signal '..signnum..' without a handler.' ) log( 'Error', 'Received signal ',sn,' without a handler.' )
end end
handler( ) handler( )
end end
end end
--
-- Sends a signal to another process.
--
function signal
(
pid, -- process to send the signal to
signal -- the signal to send
)
core.kill( pid, signum( signal ) )
end

View File

@ -766,7 +766,14 @@ local function getUserIntf
-- processes -- processes
pids = function pids = function
( ) ( )
return self.processes:copy( ) local c = 1
local pids = { }
for pid, delay in pairs( self.processes )
do
pids[ c ] = pid
c = c + 1
end
return pids
end, end,
processCount = function processCount = function

View File

@ -43,6 +43,7 @@ userenv =
require = require, require = require,
select = select, select = select,
setmetatable = setmetatable, setmetatable = setmetatable,
signum = signum,
string = string, string = string,
table = table, table = table,
type = type, type = type,
@ -57,6 +58,7 @@ userenv =
nonobservefs = user.nonobserfd, nonobservefs = user.nonobserfd,
observefd = user.observefd, observefd = user.observefd,
settings = user.settings, settings = user.settings,
signal = signal,
spawn = user.spawn, spawn = user.spawn,
spawnShell = user.spawnShell, spawnShell = user.spawnShell,
sync = user.sync, sync = user.sync,