Commit 6362be43 authored by Bas Lijnse's avatar Bas Lijnse

Merge branch 'signals' into 'master'

Catch sigint and sigterm to properly close connections

See merge request !242
parents f3ddd5ee 17ec1445
Pipeline #20784 passed with stage
in 4 minutes and 44 seconds
......@@ -158,6 +158,7 @@ createClientIWorld serverURL currentInstance
,ioTasks = {done=[],todo=[]}
,ioStates = 'Data.Map'.newMap
,world = world
,signalHandlers = []
,resources = []
,onClient = True
}
......
......@@ -21,6 +21,7 @@ from iTasks.Internal.SDS import :: SDSNotifyRequest, :: DeferredWrite, :: SDSIde
from iTasks.SDS.Definition import :: SDSSource, :: SDSLens, :: SDSParallel, class RWShared, class Registrable, class Modifiable, class Identifiable, class Readable, class Writeable
from iTasks.Extensions.DateTime import :: Time, :: Date, :: DateTime
from System.Signal import :: SigHandler
from Sapl.Linker.LazyLinker import :: LoaderState
from Sapl.Linker.SaplLinkerShared import :: LineType, :: FuncTypeMap
from Sapl.Target.Flavour import :: Flavour
......@@ -29,30 +30,32 @@ from TCPIP import :: TCP_Listener, :: TCP_Listener_, :: TCP_RChannel_, :: TCP_SC
CLEAN_HOME_VAR :== "CLEAN_HOME"
:: *IWorld = { options :: !EngineOptions // Engine configuration
, clock :: !Timespec // Server side clock
, current :: !TaskEvalState // Shared state during task evaluation
:: *IWorld =
{ options :: !EngineOptions // Engine configuration
, clock :: !Timespec // Server side clock
, current :: !TaskEvalState // Shared state during task evaluation
, random :: [Int] // Infinite random stream
, random :: [Int] // Infinite random stream
, sdsNotifyRequests :: !Map SDSIdentity (Map SDSNotifyRequest Timespec) // Notification requests from previously read sds's
, sdsNotifyReqsByTask :: !Map TaskId (Set SDSIdentity) // Allows to efficiently find notification by taskID for clearing notifications
, memoryShares :: !Map String Dynamic // Run-time memory shares
, readCache :: !Map (String,String) Dynamic // Cached share reads
, writeCache :: !Map (String,String) (Dynamic,DeferredWrite) // Cached deferred writes
, jsCompilerState :: !Maybe JSCompilerState // Sapl to Javascript compiler state
, sdsNotifyRequests :: !Map SDSIdentity (Map SDSNotifyRequest Timespec) // Notification requests from previously read sds's
, sdsNotifyReqsByTask :: !Map TaskId (Set SDSIdentity) // Allows to efficiently find notification by taskID for clearing notifications
, memoryShares :: !Map String Dynamic // Run-time memory shares
, readCache :: !Map (String,String) Dynamic // Cached share reads
, writeCache :: !Map (String,String) (Dynamic,DeferredWrite) // Cached deferred writes
, jsCompilerState :: !Maybe JSCompilerState // Sapl to Javascript compiler state
, ioTasks :: !*IOTasks // The low-level input/output tasks
, ioStates :: !IOStates // Results of low-level io tasks, indexed by the high-level taskid that it is linked to
, sdsEvalStates :: !SDSEvalStates
, ioTasks :: !*IOTasks // The low-level input/output tasks
, ioStates :: !IOStates // Results of low-level io tasks, indexed by the high-level taskid that it is linked to
, sdsEvalStates :: !SDSEvalStates
, world :: !*World // The outside world
, signalHandlers :: *[*SigHandler] // Signal handlers
, world :: !*World // The outside world
//Experimental database connection cache
, resources :: *[*Resource]
, onClient :: !Bool // "False" on the server, "True" on the client
, shutdown :: !Maybe Int // Signals the server function to shut down, the int will be set as exit code
}
//Experimental database connection cache
, resources :: *[*Resource]
, onClient :: !Bool // "False" on the server, "True" on the client
, shutdown :: !Maybe Int // Signals the server function to shut down, the int will be set as exit code
}
:: JSCompilerState =
{ loaderState :: !LoaderState // State of the lazy loader
......
......@@ -24,6 +24,7 @@ from StdOrdList import sortBy
from TCPIP import :: TCP_Listener, :: TCP_Listener_, :: TCP_RChannel_, :: TCP_SChannel_, :: TCP_DuplexChannel, :: DuplexChannel, :: IPAddress, :: ByteSeq
import System.Time, StdList, Text.Encodings.Base64, _SystemArray, StdBool, StdTuple, Text.GenJSON, Data.Error, Math.Random
import System.Signal
import iTasks.Internal.TaskStore, iTasks.Internal.Util
import iTasks.Internal.Serialization
import iTasks.Internal.SDS
......@@ -84,6 +85,7 @@ createIWorld options world
,ioStates = 'DM'.newMap
,sdsEvalStates = 'DM'.newMap
,world = world
,signalHandlers = []
,resources = []
,random = genRandInt seed
,onClient = False
......
......@@ -6,6 +6,7 @@ import Data.Tuple
import StdEnv
import System.CommandLine
import System.Time
import System.Signal
import TCPIP
import Text
import iTasks.Engine
......@@ -31,6 +32,7 @@ serve its cts determineTimeout iworld
init :: ![StartupTask] ![(!Int,!ConnectionTask)] !*IWorld -> *IWorld
init its cts iworld
# iworld = installSignalHandlers iworld
// Check if the initial tasks have been added already
# iworld = createInitialInstances its iworld
// All persistent task instances should receive a reset event to continue their work
......@@ -67,13 +69,23 @@ where
# opts = {ListenerInstanceOpts|taskId=TaskId 0 0, port=port, connectionTask=ct, removeOnClose = True}
= (ListenerInstance opts (fromJust mbListener),world)
installSignalHandlers iworld=:{signalHandlers,world}
= case signalInstall SIGTERM world of
(Error (_, e), world) = abort ("Couldn't install SIGTERM: " +++ e)
(Ok h1, world) = case signalInstall SIGINT world of
(Error (_, e), world) = abort ("Couldn't install SIGINT: " +++ e)
(Ok h2, world) = {iworld & signalHandlers=[h1,h2:signalHandlers], world=world}
loop :: !(*IWorld -> (!Maybe Timeout,!*IWorld)) !*IWorld -> *IWorld
loop determineTimeout iworld=:{ioTasks,sdsNotifyRequests}
loop determineTimeout iworld=:{ioTasks,sdsNotifyRequests,signalHandlers}
// Also put all done tasks at the end of the todo list, as the previous event handling may have yielded new tasks.
# (mbTimeout,iworld=:{IWorld|ioTasks={todo},world}) = determineTimeout {iworld & ioTasks = {done=[], todo = ioTasks.todo ++ (reverse ioTasks.done)}}
//Check which mainloop tasks have data available
# (todo,chList,world) = select mbTimeout todo world
# (merr, iworld) = updateClock {iworld & ioTasks = {done=[],todo=todo}, world = world}
# iworld = {iworld & ioTasks = {done=[],todo=todo}, world = world}
# (hadsig, iworld) = hadSignal iworld
| hadsig = halt 1 iworld
# (merr, iworld) = updateClock iworld
| merr=:(Error _) = abort "Error updating clock\n"
// Write ticker
# (merr, iworld=:{options}) = write () tick EmptyContext iworld
......@@ -89,6 +101,18 @@ loop determineTimeout iworld=:{ioTasks,sdsNotifyRequests}
= case shutdown of
(Just exitCode) = halt exitCode iworld
_ = loop determineTimeout iworld
where
pollSignalHandlers [] world = (False, [], world)
pollSignalHandlers [h:hs] world = case signalPoll h world of
(Error e, h, world) = abort "Error polling signal handler" //Shouldn't occur
(Ok s, h, world)
# (stop, hs, world) = pollSignalHandlers hs world
= (stop || s, [h:hs], world)
hadSignal iworld=:{signalHandlers,world}
# (hadsig, signalHandlers, world) = pollSignalHandlers signalHandlers world
# iworld = {iworld & signalHandlers=signalHandlers, world=world}
= (hadsig, iworld)
select :: (Maybe Timeout) *[IOTaskInstance] *World -> (!*[IOTaskInstance],![(Int,SelectResult)],!*World)
select mbTimeout mlInstances world
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment