bein-0.3: Bein/Daemon/SignalHandlers.hs
module Bein.Daemon.SignalHandlers (installSignalHandlers) where
import Database.HDBC ( fromSql, toSql )
import System.Exit ()
import System.Posix.Process ( ProcessStatus, getAnyProcessStatus )
import System.Posix.Process ()
import System.Posix.Signals
( installHandler,
sigALRM,
sigCHLD,
sigHUP,
sigPIPE,
sigPROF,
sigTERM,
sigUSR1,
sigUSR2,
sigVTALRM,
Handler(Ignore, Catch),
fullSignalSet,
deleteSignal )
import System.Posix.Syslog ( syslog, Priority(Notice) )
import System.Posix.Types ( ProcessID )
import System.Posix.Files ( fileExist )
import System.Directory ( removeDirectoryRecursive )
import Control.Monad.Trans ()
import Control.Monad.Reader
( when, MonadReader(ask), MonadIO(..), ReaderT(runReaderT) )
import Bein.Daemon.Commands
( exitDaemon, reconfigureDaemon, updateJobs, query, update )
import Bein.Daemon.Types ( BeinM, DaemonState )
installSignalHandlers :: BeinM DaemonState ()
installSignalHandlers = do
st <- ask
liftIO $ do
installHandler sigALRM Ignore Nothing
installHandler sigCHLD (Catch $ runReaderT (onDeadChildren cleanUpChild) st) (Just fullSignalSet)
installHandler sigHUP (Catch $ runReaderT reconfigureDaemon st) Nothing
installHandler sigPIPE Ignore Nothing
installHandler sigPROF Ignore Nothing
installHandler sigTERM (Catch $ runReaderT exitDaemon st) (Just $ deleteSignal sigCHLD fullSignalSet)
installHandler sigUSR1 (Catch $ runReaderT updateJobs st) Nothing
installHandler sigUSR2 Ignore Nothing
installHandler sigVTALRM Ignore Nothing
return ()
cleanUpChild :: ProcessID -> ProcessStatus -> BeinM DaemonState ()
cleanUpChild pid _ = do
query "select id,status,scratch_dir from current_jobs where running_as_pid = ?" [toSql $ toInteger pid] >>= \r -> case r of
[] -> liftIO $ syslog Notice ("Received SIGCHLD from unknown child with pid " ++ show pid)
[[sId,_sStatus,sSD]] -> do liftIO $ ensureDeleted (fromSql sSD)
update "delete from current_jobs where id = ?" [sId]
update "update executions set status='failed' where id = ? and status = 'running'" [sId]
_ -> error "Invalid response from database. Should have been unique."
ensureDeleted :: FilePath -> IO ()
ensureDeleted path = fileExist path >>= \b -> when b $ removeDirectoryRecursive path `catch` (const $ return ())
onDeadChildren :: (ProcessID -> ProcessStatus -> BeinM DaemonState ()) -> BeinM DaemonState ()
onDeadChildren act = do
v <- liftIO $ getAnyProcessStatus False False
case v of
Just (pid,status) -> act pid status >> onDeadChildren act
Nothing -> return ()