{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE ConstraintKinds #-}
module Transient.Internals where
import Control.Applicative
import Control.Monad.State
import Data.Dynamic
import qualified Data.Map as M
import System.IO.Unsafe
import Unsafe.Coerce
import Control.Exception hiding (try,onException)
import qualified Control.Exception (try)
import Control.Concurrent
import System.Mem.StableName
import Data.Maybe
import Data.List
import Data.IORef
import System.Environment
import System.IO
import qualified Data.ByteString.Char8 as BS
import Data.Typeable
#ifndef ETA_VERSION
import Data.Atomics
#endif
#ifdef DEBUG
import Debug.Trace
import System.Exit
tshow :: Show a => a -> x -> x
tshow= Debug.Trace.traceShow
{-# INLINE (!>) #-}
(!>) :: Show a => b -> a -> b
(!>) x y = trace (show y) x
infixr 0 !>
#else
tshow :: Show a => a -> x -> x
tshow _ y= y
{-# INLINE (!>) #-}
(!>) :: a -> b -> a
(!>) = const
#endif
#ifdef ETA_VERSION
atomicModifyIORefCAS = atomicModifyIORef
#endif
type StateIO = StateT EventF IO
newtype TransIO a = Transient { runTrans :: StateIO (Maybe a) }
type SData = ()
type EventId = Int
type TransientIO = TransIO
data LifeCycle = Alive | Parent | Listener | Dead
deriving (Eq, Show)
data EventF = forall a b. EventF
{ event :: Maybe SData
, xcomp :: TransIO a
, fcomp :: [b -> TransIO b]
, mfData :: M.Map TypeRep SData
, mfSequence :: Int
, threadId :: ThreadId
, freeTh :: Bool
, parent :: Maybe EventF
, children :: MVar [EventF]
, maxThread :: Maybe (IORef Int)
, labelth :: IORef (LifeCycle, BS.ByteString)
} deriving Typeable
instance MonadState EventF TransIO where
get = Transient $ get >>= return . Just
put x = Transient $ put x >> return (Just ())
state f = Transient $ do
s <- get
let ~(a, s') = f s
put s'
return $ Just a
noTrans :: StateIO x -> TransIO x
noTrans x = Transient $ x >>= return . Just
emptyEventF :: ThreadId -> IORef (LifeCycle, BS.ByteString) -> MVar [EventF] -> EventF
emptyEventF th label childs =
EventF { event = mempty
, xcomp = empty
, fcomp = []
, mfData = mempty
, mfSequence = 0
, threadId = th
, freeTh = False
, parent = Nothing
, children = childs
, maxThread = Nothing
, labelth = label }
runTransient :: TransIO a -> IO (Maybe a, EventF)
runTransient t = do
th <- myThreadId
label <- newIORef $ (Alive, BS.pack "top")
childs <- newMVar []
runStateT (runTrans t) $ emptyEventF th label childs
runTransState :: EventF -> TransIO x -> IO (Maybe x, EventF)
runTransState st x = runStateT (runTrans x) st
getCont :: TransIO EventF
getCont = Transient $ Just <$> get
runCont :: EventF -> StateIO (Maybe a)
runCont EventF { xcomp = x, fcomp = fs } = runTrans $ do
r <- unsafeCoerce x
compose fs r
runCont' :: EventF -> IO (Maybe a, EventF)
runCont' cont = runStateT (runCont cont) cont
getContinuations :: StateIO [a -> TransIO b]
getContinuations = do
EventF { fcomp = fs } <- get
return $ unsafeCoerce fs
{-# INLINE compose #-}
compose :: [a -> TransIO a] -> (a -> TransIO b)
compose [] = const empty
compose (f:fs) = \x -> f x >>= compose fs
runClosure :: EventF -> StateIO (Maybe a)
runClosure EventF { xcomp = x } = unsafeCoerce (runTrans x)
runContinuation :: EventF -> a -> StateIO (Maybe b)
runContinuation EventF { fcomp = fs } =
runTrans . (unsafeCoerce $ compose $ fs)
setContinuation :: TransIO a -> (a -> TransIO b) -> [c -> TransIO c] -> StateIO ()
setContinuation b c fs = do
modify $ \EventF{..} -> EventF { xcomp = b
, fcomp = unsafeCoerce c : fs
, .. }
withContinuation :: b -> TransIO a -> TransIO a
withContinuation c mx = do
EventF { fcomp = fs, .. } <- get
put $ EventF { xcomp = mx
, fcomp = unsafeCoerce c : fs
, .. }
r <- mx
restoreStack fs
return r
restoreStack :: MonadState EventF m => [a -> TransIO a] -> m ()
restoreStack fs = modify $ \EventF {..} -> EventF { event = Nothing, fcomp = fs, .. }
runContinuations :: [a -> TransIO b] -> c -> TransIO d
runContinuations fs x = compose (unsafeCoerce fs) x
instance Functor TransIO where
fmap f mx = do
x <- mx
return $ f x
instance Applicative TransIO where
pure a = Transient . return $ Just a
f <*> g = Transient $ do
rf <- liftIO $ newIORef (Nothing,[])
rg <- liftIO $ newIORef (Nothing,[])
fs <- getContinuations
let hasWait (_:Wait:_) = True
hasWait _ = False
appf k = Transient $ do
Log rec _ full _ <- getData `onNothing` return (Log False [] [] 0)
(liftIO $ writeIORef rf (Just k,full))
(x, full2)<- liftIO $ readIORef rg
when (hasWait full ) $
let full'= head full: full2
in (setData $ Log rec full' full')
return $ Just k <*> x
appg x = Transient $ do
Log rec _ full _ <- getData `onNothing` return (Log False [] [] 0)
liftIO $ writeIORef rg (Just x, full)
(k,full1) <- liftIO $ readIORef rf
when (hasWait full) $
let full'= head full: full1
in (setData $ Log rec full' full')
return $ k <*> Just x
setContinuation f appf fs
k <- runTrans f
was <- getData `onNothing` return NoRemote
when (was == WasParallel) $ setData NoRemote
Log recovery _ full _ <- getData `onNothing` return (Log False [] [] 0)
if was== WasRemote || (not recovery && was == NoRemote && isNothing k )
then do
restoreStack fs
return Nothing
else do
when (isJust k) $ liftIO $ writeIORef rf (k,full)
setContinuation g appg fs
x <- runTrans g
Log recovery _ full' _ <- getData `onNothing` return (Log False [] [] 0)
liftIO $ writeIORef rg (x,full')
restoreStack fs
k'' <- if was== WasParallel
then do
(k',_) <- liftIO $ readIORef rf
return k'
else return k
return $ k'' <*> x
instance Monad TransIO where
return = pure
x >>= f = Transient $ do
setEventCont x f
mk <- runTrans x
resetEventCont mk
case mk of
Just k -> runTrans (f k)
Nothing -> return Nothing
instance MonadIO TransIO where
liftIO x = Transient $ liftIO x >>= return . Just
instance Monoid a => Monoid (TransIO a) where
mappend x y = mappend <$> x <*> y
mempty = return mempty
instance Alternative TransIO where
empty = Transient $ return Nothing
(<|>) = mplus
instance MonadPlus TransIO where
mzero = empty
mplus x y = Transient $ do
mx <- runTrans x
was <- getData `onNothing` return NoRemote
if was == WasRemote
then return Nothing
else case mx of
Nothing -> runTrans y
justx -> return justx
readWithErr :: (Typeable a, Read a) => Int -> String -> IO [(a, String)]
readWithErr n line =
(v `seq` return [(v, left)])
`catch` (\(_ :: SomeException) ->
error $ "read error trying to read type: \"" ++ show (typeOf v)
++ "\" in: " ++ " <" ++ show line ++ "> ")
where (v, left):_ = readsPrec n line
read' s= case readsPrec' 0 s of
[(x,"")] -> x
_ -> error $ "reading " ++ s
readsPrec' n = unsafePerformIO . readWithErr n
type Loggable a = (Show a, Read a, Typeable a)
data IDynamic =
IDyns String
| forall a. Loggable a => IDynamic a
instance Show IDynamic where
show (IDynamic x) = show (show x)
show (IDyns s) = show s
instance Read IDynamic where
readsPrec n str = map (\(x,s) -> (IDyns x,s)) $ readsPrec' n str
type Recover = Bool
type CurrentPointer = [LogElem]
type LogEntries = [LogElem]
type Hash = Int
data LogElem = Wait | Exec | Var IDynamic
deriving (Read, Show)
data Log = Log Recover CurrentPointer LogEntries Hash
deriving (Typeable, Show)
data RemoteStatus = WasRemote | WasParallel | NoRemote
deriving (Typeable, Eq, Show)
stop :: Alternative m => m stopped
stop = empty
instance (Num a,Eq a,Fractional a) =>Fractional (TransIO a)where
mf / mg = (/) <$> mf <*> mg
fromRational r = return $ fromRational r
instance (Num a, Eq a) => Num (TransIO a) where
fromInteger = return . fromInteger
mf + mg = (+) <$> mf <*> mg
mf * mg = (*) <$> mf <*> mg
negate f = f >>= return . negate
abs f = f >>= return . abs
signum f = f >>= return . signum
class AdditionalOperators m where
(**>) :: m a -> m b -> m b
(<**) :: m a -> m b -> m a
atEnd' :: m a -> m b -> m a
atEnd' = (<**)
(<***) :: m a -> m b -> m a
atEnd :: m a -> m b -> m a
atEnd = (<***)
instance AdditionalOperators TransIO where
(**>) :: TransIO a -> TransIO b -> TransIO b
(**>) x y =
Transient $ do
runTrans x
runTrans y
(<***) :: TransIO a -> TransIO b -> TransIO a
(<***) ma mb =
Transient $ do
fs <- getContinuations
setContinuation ma (\x -> mb >> return x) fs
a <- runTrans ma
runTrans mb
restoreStack fs
return a
(<**) :: TransIO a -> TransIO b -> TransIO a
(<**) ma mb =
Transient $ do
a <- runTrans ma
runTrans mb
return a
infixr 1 <***, <**, **>
(<|) :: TransIO a -> TransIO b -> TransIO a
(<|) ma mb = Transient $ do
fs <- getContinuations
ref <- liftIO $ newIORef False
setContinuation ma (cont ref) fs
r <- runTrans ma
restoreStack fs
return r
where cont ref x = Transient $ do
n <- liftIO $ readIORef ref
if n == True
then return $ Just x
else do liftIO $ writeIORef ref True
runTrans mb
return $ Just x
{-# INLINABLE setEventCont #-}
setEventCont :: TransIO a -> (a -> TransIO b) -> StateIO ()
setEventCont x f = modify $ \EventF { fcomp = fs, .. }
-> EventF { xcomp = x
, fcomp = unsafeCoerce f : fs
, .. }
{-# INLINABLE resetEventCont #-}
resetEventCont mx =
modify $ \EventF { fcomp = fs, .. }
-> EventF { xcomp = case mx of
Nothing -> empty
Just x -> unsafeCoerce (head fs) x
, fcomp = tailsafe fs
, .. }
{-# INLINE tailsafe #-}
tailsafe :: [a] -> [a]
tailsafe [] = []
tailsafe (_:xs) = xs
waitQSemB sem = atomicModifyIORefCAS sem $ \n ->
if n > 0 then(n - 1, True) else (n, False)
signalQSemB sem = atomicModifyIORefCAS sem $ \n -> (n + 1, ())
threads :: Int -> TransIO a -> TransIO a
threads n process = do
msem <- gets maxThread
sem <- liftIO $ newIORef n
modify $ \s -> s { maxThread = Just sem }
r <- process <** (modify $ \s -> s { maxThread = msem })
return r
oneThread :: TransIO a -> TransIO a
oneThread comp = do
st <- get
chs <- liftIO $ newMVar []
label <- liftIO $ newIORef (Alive, BS.pack "oneThread")
let st' = st { parent = Just st
, children = chs
, labelth = label }
liftIO $ hangThread st st'
put st'
x <- comp
th <- liftIO myThreadId
chs <- liftIO $ readMVar chs
liftIO $ mapM_ (killChildren1 th) chs
return x
where killChildren1 :: ThreadId -> EventF -> IO ()
killChildren1 th state = do
ths' <- modifyMVar (children state) $ \ths -> do
let (inn, ths')= partition (\st -> threadId st == th) ths
return (inn, ths')
mapM_ (killChildren1 th) ths'
mapM_ (killThread . threadId) ths'
labelState :: (MonadIO m,MonadState EventF m) => String -> m ()
labelState l = do
st <- get
liftIO $ atomicModifyIORefCAS (labelth st) $ \(status,_) -> ((status, BS.pack l), ())
printBlock :: MVar ()
printBlock = unsafePerformIO $ newMVar ()
showThreads :: MonadIO m => EventF -> m ()
showThreads st = liftIO $ withMVar printBlock $ const $ do
mythread <- myThreadId
putStrLn "---------Threads-----------"
let showTree n ch = do
liftIO $ do
putStr $ take n $ repeat ' '
(state, label) <- readIORef $ labelth ch
if BS.null label
then putStr . show $ threadId ch
else do BS.putStr label; putStr . drop 8 . show $ threadId ch
when (state == Dead) $ putStr " dead"
putStrLn $ if mythread == threadId ch then " <--" else ""
chs <- readMVar $ children ch
mapM_ (showTree $ n + 2) $ reverse chs
showTree 0 st
topState :: TransIO EventF
topState = do
st <- get
return $ toplevel st
where toplevel st = case parent st of
Nothing -> st
Just p -> toplevel p
showState :: (Typeable a, MonadIO m, Alternative m) => String -> EventF -> m (Maybe a)
showState th top = resp
where
resp = do
let thstring = drop 9 . show $ threadId top
if thstring == th
then getstate top
else do
sts <- liftIO $ readMVar $ children top
foldl (<|>) empty $ map (showState th) sts
getstate st =
case M.lookup (typeOf $ typeResp resp) $ mfData st of
Just x -> return . Just $ unsafeCoerce x
Nothing -> return Nothing
typeResp :: m (Maybe x) -> x
typeResp = undefined
processStates :: Typeable a => (a-> TransIO ()) -> EventF -> TransIO()
processStates display st = do
getstate st >>= display
liftIO $ print $ threadId st
sts <- liftIO $ readMVar $ children st
mapM_ (processStates display) sts
where
getstate st =
case M.lookup (typeOf $ typeResp display) $ mfData st of
Just x -> return $ unsafeCoerce x
Nothing -> empty
typeResp :: (a -> TransIO()) -> a
typeResp = undefined
addThreads' :: Int -> TransIO ()
addThreads' n= noTrans $ do
msem <- gets maxThread
case msem of
Just sem -> liftIO $ modifyIORef sem $ \n' -> n + n'
Nothing -> do
sem <- liftIO (newIORef n)
modify $ \ s -> s { maxThread = Just sem }
addThreads :: Int -> TransIO ()
addThreads n = noTrans $ do
msem <- gets maxThread
case msem of
Nothing -> return ()
Just sem -> liftIO $ modifyIORef sem $ \n' -> if n' > n then n' else n
freeThreads :: TransIO a -> TransIO a
freeThreads process = Transient $ do
st <- get
put st { freeTh = True }
r <- runTrans process
modify $ \s -> s { freeTh = freeTh st }
return r
hookedThreads :: TransIO a -> TransIO a
hookedThreads process = Transient $ do
st <- get
put st {freeTh = False}
r <- runTrans process
modify $ \st -> st { freeTh = freeTh st }
return r
killChilds :: TransIO ()
killChilds = noTrans $ do
cont <- get
liftIO $ do
killChildren $ children cont
writeIORef (labelth cont) (Alive, mempty)
return ()
killBranch :: TransIO ()
killBranch = noTrans $ do
st <- get
liftIO $ killBranch' st
killBranch' :: EventF -> IO ()
killBranch' cont = do
killChildren $ children cont
let thisth = threadId cont
mparent = parent cont
when (isJust mparent) $
modifyMVar_ (children $ fromJust mparent) $ \sts ->
return $ filter (\st -> threadId st /= thisth) sts
killThread $ thisth
getData :: (MonadState EventF m, Typeable a) => m (Maybe a)
getData = resp
where resp = do
list <- gets mfData
case M.lookup (typeOf $ typeResp resp) list of
Just x -> return . Just $ unsafeCoerce x
Nothing -> return Nothing
typeResp :: m (Maybe x) -> x
typeResp = undefined
getSData :: Typeable a => TransIO a
getSData = Transient getData
getState :: Typeable a => TransIO a
getState = getSData
setData :: (MonadState EventF m, Typeable a) => a -> m ()
setData x = modify $ \st -> st { mfData = M.insert t (unsafeCoerce x) (mfData st) }
where t = typeOf x
modifyData :: (MonadState EventF m, Typeable a) => (Maybe a -> Maybe a) -> m ()
modifyData f = modify $ \st -> st { mfData = M.alter alterf t (mfData st) }
where typeResp :: (Maybe a -> b) -> a
typeResp = undefined
t = typeOf (typeResp f)
alterf mx = unsafeCoerce $ f x'
where x' = case mx of
Just x -> Just $ unsafeCoerce x
Nothing -> Nothing
modifyData' :: (MonadState EventF m, Typeable a) => (a -> a) -> a ->m a
modifyData' f v= do
st <- get
let (ma,nmap)= M.insertLookupWithKey alterf t (unsafeCoerce v) (mfData st)
put st { mfData =nmap}
return $ if isNothing ma then v else unsafeCoerce $ fromJust ma
where t = typeOf v
alterf _ _ x = unsafeCoerce $ f $ unsafeCoerce x
modifyState :: (MonadState EventF m, Typeable a) => (Maybe a -> Maybe a) -> m ()
modifyState = modifyData
setState :: (MonadState EventF m, Typeable a) => a -> m ()
setState = setData
delData :: (MonadState EventF m, Typeable a) => a -> m ()
delData x = modify $ \st -> st { mfData = M.delete (typeOf x) (mfData st) }
delState :: (MonadState EventF m, Typeable a) => a -> m ()
delState = delData
newtype Ref a = Ref (IORef a)
setRState:: Typeable a => a -> TransIO ()
setRState x= do
Ref ref <- getSData
liftIO $ atomicModifyIORefCAS ref $ const (x,())
<|> do
ref <- liftIO (newIORef x)
setData $ Ref ref
getRState :: Typeable a => TransIO a
getRState= do
Ref ref <- getSData
liftIO $ readIORef ref
delRState x= delState (undefined `asTypeOf` ref x)
where ref :: a -> IORef a
ref= undefined
try :: TransIO a -> TransIO a
try mx = do
sd <- gets mfData
mx <|> (modify (\s -> s { mfData = sd }) >> empty)
sandbox :: TransIO a -> TransIO a
sandbox mx = do
sd <- gets mfData
mx <*** modify (\s ->s { mfData = sd})
genGlobalId :: MonadIO m => m Int
genGlobalId= liftIO $ atomicModifyIORefCAS rglobalId $ \n -> (n +1,n)
rglobalId= unsafePerformIO $ newIORef (0 :: Int)
genId :: MonadState EventF m => m Int
genId = do
st <- get
let n = mfSequence st
put st { mfSequence = n + 1 }
return n
getPrevId :: MonadState EventF m => m Int
getPrevId = gets mfSequence
instance Read SomeException where
readsPrec n str = [(SomeException $ ErrorCall s, r)]
where [(s , r)] = readsPrec n str
data StreamData a =
SMore a
| SLast a
| SDone
| SError SomeException
deriving (Typeable, Show,Read)
waitEvents :: IO a -> TransIO a
waitEvents io = do
mr <- parallel (SMore <$> io)
case mr of
SMore x -> return x
SError e -> back e
async :: IO a -> TransIO a
async io = do
mr <- parallel (SLast <$> io)
case mr of
SLast x -> return x
SError e -> back e
sync :: TransIO a -> TransIO a
sync x = do
setData WasRemote
r <- x
delData WasRemote
return r
spawn :: IO a -> TransIO a
spawn = freeThreads . waitEvents
sample :: Eq a => IO a -> Int -> TransIO a
sample action interval = do
v <- liftIO action
prev <- liftIO $ newIORef v
waitEvents (loop action prev) <|> async (return v)
where loop action prev = loop'
where loop' = do
threadDelay interval
v <- action
v' <- readIORef prev
if v /= v' then writeIORef prev v >> return v else loop'
parallel :: IO (StreamData b) -> TransIO (StreamData b)
parallel ioaction = Transient $ do
cont <- get
case event cont of
j@(Just _) -> do
put cont { event = Nothing }
return $ unsafeCoerce j
Nothing -> do
liftIO $ atomicModifyIORefCAS (labelth cont) $ \(_, lab) -> ((Parent, lab), ())
liftIO $ loop cont ioaction
was <- getData `onNothing` return NoRemote
when (was /= WasRemote) $ setData WasParallel
return Nothing
loop :: EventF -> IO (StreamData t) -> IO ()
loop parentc rec = forkMaybe parentc $ \cont -> do
liftIO $ atomicModifyIORefCAS (labelth cont) $ const ((Listener,BS.pack "wait"),())
let loop'= do
mdat <- rec `catch` \(e :: SomeException) -> return $ SError e
case mdat of
se@(SError _) -> setworker cont >> iocont se cont
SDone -> setworker cont >> iocont SDone cont
last@(SLast _) -> setworker cont >> iocont last cont
more@(SMore _) -> do
forkMaybe cont $ iocont more
loop'
where
setworker cont= liftIO $ atomicModifyIORefCAS (labelth cont) $ const ((Alive,BS.pack "work"),())
iocont dat cont = do
let cont'= cont{event= Just $ unsafeCoerce dat}
runStateT (runCont cont') cont'
return ()
loop'
return ()
where
{-# INLINABLE forkMaybe #-}
forkMaybe parent proc = do
case maxThread parent of
Nothing -> forkIt parent proc
Just sem -> do
dofork <- waitQSemB sem
if dofork then forkIt parent proc else proc parent
forkIt parent proc= do
chs <- liftIO $ newMVar []
label <- newIORef (Alive, BS.pack "work")
let cont = parent{parent=Just parent,children= chs, labelth= label}
forkFinally1 (do
th <- myThreadId
let cont'= cont{threadId=th}
when(not $ freeTh parent )$ hangThread parent cont'
proc cont')
$ \me -> do
case me of
Left e -> exceptBack cont e >> return ()
_ -> do
case maxThread cont of
Just sem -> signalQSemB sem
Nothing -> return ()
when(not $ freeTh parent ) $ do
th <- myThreadId
(can,label) <- atomicModifyIORefCAS (labelth cont) $ \(l@(status,label)) ->
((if status== Alive then Dead else status, label),l)
when (can/= Parent ) $ free th parent
return ()
forkFinally1 :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
forkFinally1 action and_then =
mask $ \restore -> forkIO $ Control.Exception.try (restore action) >>= and_then
free th env= do
let sibling= children env
(sbs',found) <- modifyMVar sibling $ \sbs -> do
let (sbs', found) = drop [] th sbs
return (sbs',(sbs',found))
if found
then do
(typ,_) <- readIORef $ labelth env
if (null sbs' && typ /= Listener && isJust (parent env))
then free (threadId env) ( fromJust $ parent env)
else return ()
else return ()
where
drop processed th []= (processed,False)
drop processed th (ev:evts)| th == threadId ev= (processed ++ evts, True)
| otherwise= drop (ev:processed) th evts
hangThread parentProc child = do
let headpths= children parentProc
modifyMVar_ headpths $ \ths -> return (child:ths)
killChildren childs = do
ths <- modifyMVar childs $ \ths -> return ([],ths)
mapM_ (killChildren . children) ths
mapM_ (killThread . threadId) ths !> ("KILL", map threadId ths )
react
:: Typeable eventdata
=> ((eventdata -> IO response) -> IO ())
-> IO response
-> TransIO eventdata
react setHandler iob= Transient $ do
cont <- get
case event cont of
Nothing -> do
liftIO $ setHandler $ \dat ->do
runStateT (runCont cont) cont{event= Just $ unsafeCoerce dat} `catch` exceptBack cont
iob
was <- getData `onNothing` return NoRemote
when (was /= WasRemote) $ setData WasParallel
return Nothing
j@(Just _) -> do
put cont{event=Nothing}
return $ unsafeCoerce j
abduce = async $ return ()
option :: (Typeable b, Show b, Read b, Eq b) =>
b -> String -> TransIO b
option = optionf False
option1 :: (Typeable b, Show b, Read b, Eq b) =>
b -> String -> TransIO b
option1= optionf True
optionf :: (Typeable b, Show b, Read b, Eq b) =>
Bool -> b -> String -> TransIO b
optionf flag ret message = do
let sret= if typeOf ret == typeOf "" then unsafeCoerce ret else show ret
liftIO $ putStrLn $ "Enter "++sret++"\tto: " ++ message
inputf flag sret message Nothing ( == sret)
liftIO $ putStr "\noption: " >> putStrLn sret
return ret
inputf flag ident message mv cond= do
r <- react (addListener ident) (return ())
when (null r) $ liftIO $ writeIORef rconsumed True
let rr= read1 r
when flag $ liftIO $ delListener ident
case rr of
Just x -> if cond x
then do
liftIO $ do
writeIORef rconsumed True
print x;
return x
else do liftIO $ when (isJust mv) $ putStrLn ""; returnm mv
_ -> do liftIO $ when (isJust mv) $ putStrLn ""; returnm mv
where
returnm (Just x)= return x
returnm _ = empty
read1 s= x where
x= if typeOf(typeOfr x) == typeOf ""
then Just $ unsafeCoerce s
else unsafePerformIO $ do
(let r= read s in r `seq` return (Just r)) `catch` \(e :: SomeException) -> (return Nothing)
typeOfr :: Maybe a -> a
typeOfr = undefined
input :: (Typeable a, Read a,Show a) => (a -> Bool) -> String -> TransIO a
input= input' Nothing
input' :: (Typeable a, Read a,Show a) => Maybe a -> (a -> Bool) -> String -> TransIO a
input' mv cond prompt= do
liftIO $ putStr prompt >> hFlush stdout
inputf True "input" prompt mv cond
rcb= unsafePerformIO $ newIORef M.empty :: IORef (M.Map String (String -> IO()))
addListener :: String -> (String -> IO ()) -> IO ()
addListener name cb= atomicModifyIORef rcb $ \cbs -> (M.insert name cb cbs,())
delListener :: String -> IO ()
delListener name= atomicModifyIORef rcb $ \cbs -> (M.delete name cbs,())
reads1 s=x where
x= if typeOf(typeOfr x) == typeOf "" then unsafeCoerce[(s,"")] else readsPrec' 0 s
typeOfr :: [(a,String)] -> a
typeOfr = undefined
inputLoop= do
x <- getLine
processLine x
putStr "> "; hFlush stdout
inputLoop
rconsumed = unsafePerformIO $ newIORef False
processLine r = do
let rs = breakSlash [] r
return () !> rs
mapM' invoke rs
where
invoke x= do
mbs <- readIORef rcb
mapM (\cb -> cb x) $ M.elems mbs
mapM' f []= return ()
mapM' f (xss@(x:xs)) =do
f x
r <- readIORef rconsumed
if r
then do
writeIORef riterloop 0
writeIORef rconsumed False
mapM' f xs
else do
threadDelay 1000
n <- atomicModifyIORef riterloop $ \n -> (n+1,n)
if n==100
then do
when (not $ null x) $ putStr x >> putStrLn ": can't read, skip"
writeIORef riterloop 0
writeIORef rconsumed False
mapM' f xs
else mapM' f xss
riterloop= unsafePerformIO $ newIORef 0
breakSlash :: [String] -> String -> [String]
breakSlash [] ""= [""]
breakSlash s ""= s
breakSlash res ('\"':s)=
let (r,rest) = span(/= '\"') s
in breakSlash (res++[r]) $ tail1 rest
breakSlash res s=
let (r,rest) = span(\x -> x /= '/' && x /= ' ') s
in breakSlash (res++[r]) $ tail1 rest
tail1 []= []
tail1 x= tail x
stay rexit= takeMVar rexit
`catch` \(e :: BlockedIndefinitelyOnMVar) -> return Nothing
newtype Exit a= Exit a deriving Typeable
keep :: Typeable a => TransIO a -> IO (Maybe a)
keep mx = do
liftIO $ hSetBuffering stdout LineBuffering
rexit <- newEmptyMVar
forkIO $ do
runTransient $ do
onException $ \(e :: SomeException ) -> liftIO $ putStr "keep block: " >> print e
st <- get
setData $ Exit rexit
(abduce >> labelState "input" >> liftIO inputLoop >> empty)
<|> do
option "options" "show all options"
mbs <- liftIO $ readIORef rcb
liftIO $ mapM_ (\c ->do putStr c; putStr "|") $ M.keys mbs
liftIO $ putStrLn ""
empty
<|> do
option "ps" "show threads"
liftIO $ showThreads st
empty
<|> do
option "log" "inspect the log of a thread"
th <- input (const True) "thread number>"
ml <- liftIO $ showState th st
liftIO $ print $ fmap (\(Log _ _ log _) -> reverse log) ml
empty
<|> do
option "end" "exit"
liftIO $ putStrLn "exiting..."
abduce
killChilds
liftIO $ putMVar rexit Nothing
empty
<|> mx
return ()
threadDelay 10000
execCommandLine
stay rexit
where
type1 :: TransIO a -> Either String (Maybe a)
type1= undefined
keep' :: Typeable a => TransIO a -> IO (Maybe a)
keep' mx = do
liftIO $ hSetBuffering stdout LineBuffering
rexit <- newEmptyMVar
forkIO $ do
runTransient $ do
setData $ Exit rexit
mx
return ()
threadDelay 10000
forkIO $ execCommandLine
stay rexit
execCommandLine= do
args <- getArgs
let mindex = findIndex (\o -> o == "-p" || o == "--path" ) args
when (isJust mindex) $ do
let i= fromJust mindex +1
when (length args >= i) $ do
let path= args !! i
putStr "Executing: " >> print path
processLine path
exit :: Typeable a => a -> TransIO a
exit x= do
Exit rexit <- getSData <|> error "exit: not the type expected" `asTypeOf` type1 x
liftIO $ putMVar rexit $ Just x
stop
where
type1 :: a -> TransIO (Exit (MVar (Maybe a)))
type1= undefined
onNothing :: Monad m => m (Maybe b) -> m b -> m b
onNothing iox iox'= do
mx <- iox
case mx of
Just x -> return x
Nothing -> iox'
data Backtrack b= Show b =>Backtrack{backtracking :: Maybe b
,backStack :: [EventF] }
deriving Typeable
backCut :: (Typeable b, Show b) => b -> TransientIO ()
backCut reason= Transient $ do
delData $ Backtrack (Just reason) []
return $ Just ()
undoCut :: TransientIO ()
undoCut = backCut ()
{-# NOINLINE onBack #-}
onBack :: (Typeable b, Show b) => TransientIO a -> ( b -> TransientIO a) -> TransientIO a
onBack ac bac = registerBack (typeof bac) $ Transient $ do
Backtrack mreason stack <- getData `onNothing` (return $ backStateOf (typeof bac))
runTrans $ case mreason of
Nothing -> ac
Just reason -> do
bac reason
where
typeof :: (b -> TransIO a) -> b
typeof = undefined
onUndo :: TransientIO a -> TransientIO a -> TransientIO a
onUndo x y= onBack x (\() -> y)
{-# NOINLINE registerUndo #-}
registerBack :: (Typeable b, Show b) => b -> TransientIO a -> TransientIO a
registerBack witness f = Transient $ do
cont@(EventF _ x _ _ _ _ _ _ _ _ _) <- get
md <- getData `asTypeOf` (Just <$> return (backStateOf witness))
case md of
Just (Backtrack b []) -> setData $ Backtrack b [cont]
Just (bss@(Backtrack b (bs@((EventF _ x' _ _ _ _ _ _ _ _ _):_)))) ->
when (isNothing b) $ do
addrx <- addr x
addrx' <- addr x'
setData $ if addrx == addrx' then bss else Backtrack b (cont:bs)
Nothing -> setData $ Backtrack mwit [cont]
runTrans f
where
mwit= Nothing `asTypeOf` (Just witness)
addr x = liftIO $ return . hashStableName =<< (makeStableName $! x)
registerUndo :: TransientIO a -> TransientIO a
registerUndo f= registerBack () f
forward :: (Typeable b, Show b) => b -> TransIO ()
forward reason= Transient $ do
Backtrack _ stack <- getData `onNothing` ( return $ backStateOf reason)
setData $ Backtrack(Nothing `asTypeOf` Just reason) stack
return $ Just ()
retry= forward ()
noFinish= continue
back :: (Typeable b, Show b) => b -> TransientIO a
back reason = do
bs <- getData `onNothing` return (backStateOf reason)
goBackt bs
where
runClosure :: EventF -> TransIO a
runClosure EventF { xcomp = x } = unsafeCoerce x
runContinuation :: EventF -> a -> TransIO b
runContinuation EventF { fcomp = fs } = (unsafeCoerce $ compose $ fs)
goBackt (Backtrack _ [] )= empty
goBackt (Backtrack b (stack@(first : bs)) )= do
setData $ Backtrack (Just reason) stack
x <- runClosure first
return () !> "runclosure"
Backtrack back _ <- getData `onNothing` return (backStateOf reason)
case back of
Nothing -> runContinuation first x
justreason ->do
setData $ Backtrack justreason bs
goBackt $ Backtrack justreason bs
empty
backStateOf :: (Show a, Typeable a) => a -> Backtrack a
backStateOf reason= Backtrack (Nothing `asTypeOf` (Just reason)) []
undo :: TransIO a
undo= back ()
newtype Finish= Finish String deriving Show
instance Exception Finish
onFinish :: (Finish ->TransIO ()) -> TransIO ()
onFinish f= onException' (return ()) f
onFinish' ::TransIO a ->(Finish ->TransIO a) -> TransIO a
onFinish' proc f= proc `onException'` f
initFinish = cutExceptions
finish :: String -> TransIO ()
finish reason= (throwt $ Finish reason) <|> return()
checkFinalize v=
case v of
SDone -> stop
SLast x -> return x
SError e -> throwt e
SMore x -> return x
onException :: Exception e => (e -> TransIO ()) -> TransIO ()
onException exc= return () `onException'` exc
onException' :: Exception e => TransIO a -> (e -> TransIO a) -> TransIO a
onException' mx f= onAnyException mx $ \e ->
case fromException e of
Nothing -> empty
Just e' -> f e'
where
onAnyException :: TransIO a -> (SomeException ->TransIO a) -> TransIO a
onAnyException mx f= ioexp f `onBack` f
ioexp f = Transient $ do
st <- get
(mx,st') <- liftIO $ (runStateT
(do
case event st of
Nothing -> do
r <- runTrans mx
modify $ \s -> s{event= Just $ unsafeCoerce r}
return () !> "MX"
runCont st
was <- getData `onNothing` return NoRemote
when (was /= WasRemote) $ setData WasParallel
return Nothing
Just r -> do
modify $ \s -> s{event=Nothing}
return () !> "JUSTTTTTTTTTTT"
return $ unsafeCoerce r) st)
`catch` exceptBack st
put st'
return mx
exceptBack st = \(e ::SomeException) -> do
runStateT ( runTrans $ back e ) st !> "EXCEPTBACK"
`catch` exceptBack st
cutExceptions :: TransIO ()
cutExceptions= backCut (undefined :: SomeException)
continue :: TransIO ()
continue = forward (undefined :: SomeException)
catcht :: Exception e => TransIO b -> (e -> TransIO b) -> TransIO b
catcht mx exc= do
rpassed <- liftIO $ newIORef False
sandbox $ do
cutExceptions
r <- onException' mx (\e -> do
passed <- liftIO $ readIORef rpassed
if not passed then continue >> exc e else empty)
liftIO $ writeIORef rpassed True
return r
where
sandbox mx= do
exState <- getState <|> return (backStateOf (undefined :: SomeException))
mx
<*** do setState exState
throwt :: Exception e => e -> TransIO a
throwt= back . toException