module Simulation.Aivika.Task
(
Task,
TaskResult(..),
taskId,
tryGetTaskResult,
taskResult,
taskResultReceived,
taskProcess,
cancelTask,
taskCancelled,
runTask,
runTaskUsingId,
spawnTask,
spawnTaskUsingId,
enqueueTask,
enqueueTaskUsingId) where
import Data.IORef
import Data.Monoid
import Control.Monad
import Control.Monad.Trans
import Control.Exception
import Simulation.Aivika.Internal.Simulation
import Simulation.Aivika.Internal.Dynamics
import Simulation.Aivika.Internal.Event
import Simulation.Aivika.Internal.Cont
import Simulation.Aivika.Internal.Process
import Simulation.Aivika.Internal.Signal
data Task a =
Task { taskId :: ProcessId,
taskResultRef :: IORef (Maybe (TaskResult a)),
taskResultReceived :: Signal (TaskResult a)
}
data TaskResult a = TaskCompleted a
| TaskError IOException
| TaskCancelled
tryGetTaskResult :: Task a -> Event (Maybe (TaskResult a))
tryGetTaskResult t =
Event $ \p -> readIORef (taskResultRef t)
taskResult :: Task a -> Process (TaskResult a)
taskResult t =
do x <- liftIO $ readIORef (taskResultRef t)
case x of
Just x -> return x
Nothing ->
do x <- processAwait (taskResultReceived t)
return x
cancelTask :: Task a -> Event ()
cancelTask t =
cancelProcessUsingId (taskId t)
taskCancelled :: Task a -> Event Bool
taskCancelled t =
processCancelled (taskId t)
newTaskUsingId :: ProcessId -> Process a -> Event (Task a, Process ())
newTaskUsingId pid p =
do r <- liftIO $ newIORef Nothing
s <- liftSimulation newSignalSource
let t = Task { taskId = pid,
taskResultRef = r,
taskResultReceived = publishSignal s }
let m =
do v <- liftIO $ newIORef TaskCancelled
finallyProcess
(catchProcess
(do a <- p
liftIO $ writeIORef v (TaskCompleted a))
(\e ->
liftIO $ writeIORef v (TaskError e)))
(liftEvent $
do x <- liftIO $ readIORef v
liftIO $ writeIORef r (Just x)
triggerSignal s x)
return (t, m)
runTaskUsingId :: ProcessId -> Process a -> Event (Task a)
runTaskUsingId pid p =
do (t, m) <- newTaskUsingId pid p
runProcessUsingId pid m
return t
runTask :: Process a -> Event (Task a)
runTask p =
do pid <- liftSimulation newProcessId
runTaskUsingId pid p
enqueueTaskUsingId :: Double -> ProcessId -> Process a -> Event (Task a)
enqueueTaskUsingId time pid p =
do (t, m) <- newTaskUsingId pid p
enqueueProcessUsingId time pid m
return t
enqueueTask :: Double -> Process a -> Event (Task a)
enqueueTask time p =
do pid <- liftSimulation newProcessId
enqueueTaskUsingId time pid p
spawnTaskUsingId :: ContCancellation -> ProcessId -> Process a -> Process (Task a)
spawnTaskUsingId cancellation pid p =
do (t, m) <- liftEvent $ newTaskUsingId pid p
spawnProcessUsingId cancellation pid m
return t
spawnTask :: ContCancellation -> Process a -> Process (Task a)
spawnTask cancellation p =
do pid <- liftSimulation newProcessId
spawnTaskUsingId cancellation pid p
taskProcess :: Task a -> Process a
taskProcess t =
do x <- taskResult t
case x of
TaskCompleted a -> return a
TaskError e -> throwProcess e
TaskCancelled -> cancelProcess