mirror of
https://github.com/octoleo/lsyncd.git
synced 2024-12-04 19:03:17 +00:00
reworking signal system
This commit is contained in:
parent
5965c0ea59
commit
9fa9ea72da
@ -221,7 +221,8 @@ handle_event(
|
||||
|
||||
lua_pop( L, 1 );
|
||||
|
||||
hup = 1;
|
||||
// FIXME report this to mantle more sensible
|
||||
softreset = true;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -446,7 +447,7 @@ inotify_ready(
|
||||
|
||||
{
|
||||
int i = 0;
|
||||
while( i < len && !hup && !term )
|
||||
while( i < len && !softreset )
|
||||
{
|
||||
struct inotify_event *event = ( struct inotify_event * ) ( readbuf + i );
|
||||
|
||||
|
30
core/main.c
30
core/main.c
@ -208,27 +208,6 @@ masterloop(
|
||||
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,
|
||||
// like starting new processes, writing the statusfile etc.
|
||||
load_mci( L, "cycle" );
|
||||
@ -500,13 +479,8 @@ main( int argc, char * argv[ ] )
|
||||
setlinebuf( stdout );
|
||||
setlinebuf( stderr );
|
||||
|
||||
while( !term )
|
||||
{
|
||||
main1( argc, argv );
|
||||
}
|
||||
while( true ) main1( argc, argv );
|
||||
|
||||
// exits with error code responding to the signal it died for
|
||||
// FIXME this no longer holds true to systemd recommendations
|
||||
return 128 + sigcode;
|
||||
// return -1;
|
||||
}
|
||||
|
||||
|
15
core/mci.c
15
core/mci.c
@ -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.
|
||||
| For debugging purposes.
|
||||
@ -490,7 +502,7 @@ l_readdir( lua_State *L )
|
||||
|
||||
lua_newtable( L );
|
||||
|
||||
while( !hup && !term )
|
||||
while( !softreset )
|
||||
{
|
||||
struct dirent *de = readdir( d );
|
||||
bool isdir;
|
||||
@ -657,6 +669,7 @@ static const luaL_Reg corelib[ ] =
|
||||
{ "onsignal", l_onsignal },
|
||||
{ "readdir", l_readdir },
|
||||
{ "realdir", l_realdir },
|
||||
{ "sofotreset", l_softreset },
|
||||
{ "stackdump", l_stackdump },
|
||||
{ "terminate", l_terminate },
|
||||
{ NULL, NULL }
|
||||
|
@ -24,11 +24,19 @@
|
||||
#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
|
||||
* read-ready or write-ready.
|
||||
*/
|
||||
struct observance {
|
||||
struct observance
|
||||
{
|
||||
// The file descriptor to observe.
|
||||
int fd;
|
||||
|
||||
@ -261,14 +269,12 @@ observe_select
|
||||
struct observance *obs = observances + pi;
|
||||
int fd = obs->fd;
|
||||
|
||||
// checks for signals
|
||||
if( hup || term ) break;
|
||||
if( softreset ) break;
|
||||
|
||||
// a file descriptor became read-ready
|
||||
if( obs->ready && FD_ISSET( fd, &rfds ) ) obs->ready( L, fd, obs->extra );
|
||||
|
||||
// Checks for signals, again, better safe than sorry
|
||||
if ( hup || term ) break;
|
||||
if( softreset ) break;
|
||||
|
||||
// FIXME breaks on multiple nonobservances in one beat
|
||||
if(
|
||||
|
@ -33,4 +33,7 @@ extern void observe_tidy_all( );
|
||||
// stops the core to observe a file descriptor
|
||||
extern void nonobserve_fd( int fd );
|
||||
|
||||
// set to true to soft reset at earliest possilibity
|
||||
extern bool softreset;
|
||||
|
||||
#endif
|
||||
|
@ -46,17 +46,6 @@ static int handlers_maxlen;
|
||||
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
|
||||
*/
|
||||
@ -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
|
||||
l_kill(
|
||||
lua_State *L
|
||||
)
|
||||
{
|
||||
int pid = luaL_checkinteger( L, 1 );
|
||||
int sid = luaL_checkinteger( L, 2 );
|
||||
|
||||
kill( pid, sid );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,6 @@
|
||||
#ifndef 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.
|
||||
extern void signal_init( );
|
||||
|
@ -98,6 +98,12 @@ default.collect = function
|
||||
|
||||
local rc
|
||||
|
||||
if agent.syncStopped
|
||||
then
|
||||
log( 'Normal', 'Sync stopped, ignoring exitcode of finished child' )
|
||||
return 'ok'
|
||||
end
|
||||
|
||||
if config.exitcodes
|
||||
then
|
||||
rc = config.exitcodes[ exitcode ]
|
||||
@ -115,9 +121,7 @@ default.collect = function
|
||||
then
|
||||
log(
|
||||
'Normal',
|
||||
'Startup of ',
|
||||
agent.source, ' -> ', agent.target,
|
||||
' finished.'
|
||||
'Startup of ',agent.source, ' -> ',agent.target,' finished.'
|
||||
)
|
||||
|
||||
return 'ok'
|
||||
@ -133,15 +137,6 @@ default.collect = function
|
||||
)
|
||||
|
||||
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
|
||||
elseif rc == 'die'
|
||||
then
|
||||
|
@ -141,14 +141,7 @@ direct.collect = function
|
||||
log( 'Normal', 'Startup of "',agent.source,'" finished: ', exitcode )
|
||||
elseif rc == 'again'
|
||||
then
|
||||
if settings( 'insist' )
|
||||
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
|
||||
log( 'Normal', 'Retrying startup of "',agent.source,'": ', exitcode )
|
||||
elseif rc == 'die'
|
||||
then
|
||||
log( 'Error', 'Failure on startup of "',agent.source,'": ', exitcode )
|
||||
|
@ -365,18 +365,7 @@ rsyncssh.collect = function
|
||||
log( 'Normal', 'Startup of "', agent.source, '" finished: ', exitcode )
|
||||
elseif rc == 'again'
|
||||
then
|
||||
if settings('insist')
|
||||
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
|
||||
log( 'Normal', 'Retrying startup of "', agent.source, '": ', exitcode )
|
||||
elseif rc == 'die'
|
||||
then
|
||||
log( 'Error', 'Failure on startup of "', agent.source, '": ', exitcode )
|
||||
|
@ -15,60 +15,64 @@ default.signal = { }
|
||||
|
||||
|
||||
--
|
||||
-- Returns a signal handler for 'signal'.
|
||||
--
|
||||
--
|
||||
local function onCollect
|
||||
local function makeSignalHandler
|
||||
(
|
||||
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
|
||||
end
|
||||
local pCount = 0
|
||||
|
||||
for _, sync in ipairs( syncs )
|
||||
do
|
||||
sync.stop( )
|
||||
|
||||
local function sighup
|
||||
( )
|
||||
print( 'GOT A HUP SIGNAL' )
|
||||
local pids = sync.pids( )
|
||||
local pc = #pids
|
||||
|
||||
os.exit( 1 )
|
||||
end
|
||||
if( pc == 0 )
|
||||
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
|
||||
( )
|
||||
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 )
|
||||
for _, pid in ipairs( pids ) do signal( pid, sig ) end
|
||||
end
|
||||
end
|
||||
|
||||
if #syncs == 0 then finish( ) end
|
||||
|
||||
log( 'Normal', 'Waiting for ', pCount, ' child processes.' )
|
||||
end
|
||||
|
||||
if #syncs == 0 then os.exit( 0 ) end
|
||||
|
||||
log( 'Normal', 'Waiting for ', pCount, ' child processes.' )
|
||||
end
|
||||
|
||||
|
||||
local function sigterm
|
||||
( )
|
||||
print( 'GOT A TERM SIGNAL' )
|
||||
|
||||
os.exit( 1 )
|
||||
local function finishHup( )
|
||||
os.exit( 0 )
|
||||
end
|
||||
|
||||
local function finishInt( )
|
||||
os.exit( 0 )
|
||||
end
|
||||
|
||||
local function finishTerm( )
|
||||
os.exit( 0 )
|
||||
end
|
||||
|
||||
--
|
||||
-- Sets up the default HUP/INT/TERM signal handlers.
|
||||
@ -82,14 +86,10 @@ init =
|
||||
local int = getsignal( 'INT' )
|
||||
local term = getsignal( 'TERM' )
|
||||
|
||||
if hup ~= false then hup = sighup end
|
||||
if int ~= false then int = sigint end
|
||||
if term ~= false then term = sigterm end
|
||||
if hup ~= false then hup = makeSignalHandler( 'HUP', 'resetting', finishHup ) end
|
||||
if int ~= false then int = makeSignalHandler( 'INT', 'terminating', finishInt ) end
|
||||
if term ~= false then term = makeSignalHandler( 'TERM', 'terminating', finishTerm ) end
|
||||
|
||||
onsignal(
|
||||
'HUP', hup,
|
||||
'INT', int,
|
||||
'TERM', term
|
||||
)
|
||||
onsignal( 'HUP', hup, 'INT', int, 'TERM', term )
|
||||
end
|
||||
|
||||
|
@ -54,9 +54,6 @@ OPTIONS
|
||||
*-help*::
|
||||
Show a help message.
|
||||
|
||||
*-insist*::
|
||||
Continues start up even if rsync cannot connect.
|
||||
|
||||
*-log* 'LEVEL'::
|
||||
Controls which kind of events are logged. By default Lsyncd logs 'Normal'
|
||||
and 'Error' Messages. *-log scarce* will make Lsyncd log Error messages
|
||||
|
@ -95,24 +95,6 @@ mt.__ipairs = function
|
||||
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
|
||||
--
|
||||
@ -132,8 +114,27 @@ local function copy
|
||||
return copy
|
||||
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.
|
||||
--
|
||||
Counter = { new = new }
|
||||
Counter = { new = new, copy = copy }
|
||||
|
||||
|
@ -268,6 +268,17 @@ local eventFields =
|
||||
return e2d[ event ].sync.source .. cutSlash( getPath( event ) )
|
||||
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.
|
||||
--
|
||||
@ -411,15 +422,9 @@ local eventListMeta =
|
||||
elist,
|
||||
func
|
||||
)
|
||||
if func == 'isList'
|
||||
then
|
||||
return true
|
||||
end
|
||||
if func == 'isList' then return true end
|
||||
|
||||
if func == 'config'
|
||||
then
|
||||
return e2d[ elist ].sync.config
|
||||
end
|
||||
if func == 'config' then return e2d[ elist ].sync.config end
|
||||
|
||||
local f = eventListFuncs[ func ]
|
||||
|
||||
|
@ -563,6 +563,7 @@ end
|
||||
--
|
||||
mci.inotifyEvent = Inotify.event
|
||||
|
||||
|
||||
--
|
||||
-- Collector for every child process that finished in startup phase
|
||||
--
|
||||
@ -593,6 +594,7 @@ end
|
||||
|
||||
--
|
||||
-- Called by core on a hup signal.
|
||||
-- FIXME remove
|
||||
--
|
||||
function mci.hup
|
||||
( )
|
||||
@ -601,8 +603,10 @@ function mci.hup
|
||||
lsyncdStatus = 'fade'
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Called by core on a term signal.
|
||||
-- FIXME remove
|
||||
--
|
||||
function mci.term
|
||||
(
|
||||
|
@ -43,7 +43,7 @@ local sigHandlerCount = 0
|
||||
--
|
||||
-- In case of a invalid signal specifie an error is raised.
|
||||
--
|
||||
local function toSignum
|
||||
function signum
|
||||
(
|
||||
signal
|
||||
)
|
||||
@ -59,14 +59,9 @@ local function toSignum
|
||||
return signal
|
||||
elseif type( signal ) == 'string'
|
||||
then
|
||||
signum = signums[ signal ]
|
||||
|
||||
if signum == nil
|
||||
then
|
||||
error( 'signal "' .. signal .. '" unknown.' , 3 )
|
||||
end
|
||||
|
||||
return signum
|
||||
local sn = signums[ signal ]
|
||||
if sn == nil then error( 'signal "' .. signal .. '" unknown.' , 3 ) end
|
||||
return sn
|
||||
elseif signal == false
|
||||
then
|
||||
return false
|
||||
@ -102,10 +97,8 @@ function onsignal
|
||||
do
|
||||
local signal = arg[ a ]
|
||||
local handler = arg[ a + 1 ]
|
||||
|
||||
local signum = toSignum( signal )
|
||||
|
||||
sigHandlers[ signum ] = handler
|
||||
local sn = signum( signal )
|
||||
sigHandlers[ sn ] = handler
|
||||
end
|
||||
|
||||
core.onsignal( sigHandlers )
|
||||
@ -131,16 +124,29 @@ mci.signalEvent =
|
||||
(
|
||||
sigtable
|
||||
)
|
||||
for _, signum in ipairs( sigtable )
|
||||
for _, sn in ipairs( sigtable )
|
||||
do
|
||||
local handler = sigHandlers[ signum ]
|
||||
local handler = sigHandlers[ sn ]
|
||||
|
||||
if not handler
|
||||
then
|
||||
log( 'Error', 'Received signal '..signnum..' without a handler.' )
|
||||
log( 'Error', 'Received signal ',sn,' without a handler.' )
|
||||
end
|
||||
|
||||
handler( )
|
||||
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
|
||||
|
||||
|
||||
|
@ -766,7 +766,14 @@ local function getUserIntf
|
||||
-- processes
|
||||
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,
|
||||
|
||||
processCount = function
|
||||
|
@ -43,6 +43,7 @@ userenv =
|
||||
require = require,
|
||||
select = select,
|
||||
setmetatable = setmetatable,
|
||||
signum = signum,
|
||||
string = string,
|
||||
table = table,
|
||||
type = type,
|
||||
@ -57,6 +58,7 @@ userenv =
|
||||
nonobservefs = user.nonobserfd,
|
||||
observefd = user.observefd,
|
||||
settings = user.settings,
|
||||
signal = signal,
|
||||
spawn = user.spawn,
|
||||
spawnShell = user.spawnShell,
|
||||
sync = user.sync,
|
||||
|
Loading…
Reference in New Issue
Block a user