Elucidating the types

This commit is contained in:
Tony Garnock-Jones 2012-01-20 10:54:10 -05:00
parent fd64c460a4
commit a4113f7608
1 changed files with 149 additions and 0 deletions

149
os.hs Normal file
View File

@ -0,0 +1,149 @@
{-# LANGUAGE ExistentialQuantification #-}
module OS where
-- TODO try avoiding double-matching for metamessages by closing over the callback
-- TODO try using PIDs instead of HIDs to avoid the search in runMetaHandler
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Control.Arrow ((>>>))
import Data.Maybe
import Control.Concurrent.Chan
data VM m mm = VM { hidCounter :: Int,
suspensions :: [Suspension m mm],
messages :: [m],
metaMessages :: [mm],
runnables :: [Callback m mm ()] }
type Callback m mm state = (state -> KernelModeTransition m mm)
data Subscription m mm = forall state. Subscription
state
(Maybe (Callback m mm state))
[Handler m mm state]
[MetaHandler m mm state]
data Suspension m mm = forall state. Suspension
state
(Maybe (Callback m mm state))
[Handler m mm state]
(IntMap (MetaHandler m mm state))
data KernelModeTransition m mm = KernelModeTransition (Subscription m mm)
[m]
[mm]
[Callback m mm ()]
type HID = Int
type Handler m mm state = (m -> Maybe (Callback m mm state))
type MetaHandler m mm state = (mm -> Maybe (Callback m mm state))
newVM boot = VM { hidCounter = 0,
suspensions = [],
messages = [],
metaMessages = [],
runnables = [boot] }
runVM :: VM m mm -> KernelModeTransition mm mm1
runVM = rebuildSuspensions enqueuePoller >>> runRunnables >>> dispatchMessages >>> \ vm ->
let mms = reverse $ metaMessages vm
mmhs = concatMap extractDown $ suspensions vm
pollerK = if shouldPoll vm then Just runVM else Nothing
in
KernelModeTransition (Subscription (vm { metaMessages = [] }) pollerK mmhs []) mms [] []
rebuildSuspensions :: (VM m mm -> Suspension m mm -> VM m mm) -> (VM m mm) -> (VM m mm)
rebuildSuspensions f vm = foldl f (vm { suspensions = [] }) (suspensions vm)
enqueuePoller :: VM m mm -> Suspension m mm -> VM m mm
enqueuePoller vm susp@(Suspension state k _ _) =
if isPolling susp
then vm { runnables = (\ () -> (fromJust k) state) : runnables vm }
else vm { suspensions = susp : suspensions vm }
runRunnables :: VM m mm -> VM m mm
runRunnables vm = foldl runRunnable (vm { runnables = [] }) (reverse (runnables vm))
runRunnable vm r = performTransition (r ()) vm
dispatchMessages :: VM m mm -> VM m mm
dispatchMessages vm = foldr dispatchMessage (vm { messages = [] }) (messages vm)
dispatchMessage m = rebuildSuspensions matchSuspension
where matchSuspension vm susp@(Suspension state _ mhs _) =
let searchHandlers [] = vm { suspensions = susp : suspensions vm }
searchHandlers (mh:mhs) =
case mh m of
Just h -> performTransition (h state) vm
Nothing -> searchHandlers mhs
in searchHandlers mhs
extractDown (Suspension _ _ _ mmhs) =
IntMap.foldWithKey (\ hid mmh xs -> dispatchMetaMessage hid mmh : xs) [] mmhs
dispatchMetaMessage :: HID -> MetaHandler m mm state -> Handler mm mm1 (VM m mm)
dispatchMetaMessage hid mmh mm =
case mmh mm of
Nothing -> Nothing
Just _ -> Just (runMetaHandler hid mm)
isPolling (Suspension _ pollerK _ _) = isNothing pollerK
isBlocked = not . isPolling
shouldPoll vm@(VM { messages = [], runnables = []}) = not $ all isBlocked (suspensions vm)
shouldPoll _ = True
runMetaHandler :: HID -> mm -> (VM m mm) -> (KernelModeTransition mm mm1)
runMetaHandler hid mm = runVM . rebuildSuspensions runHid
where runHid vm susp@(Suspension state _ _ mmhs) =
case IntMap.lookup hid mmhs of
Just h -> performTransition ((fromJust $ h mm) state) vm
Nothing -> vm { suspensions = susp : suspensions vm }
addHids vm mmhs =
foldr (\ mmh (vm, acc) -> let h = hidCounter vm in
(vm { hidCounter = h + 1 }, IntMap.insert h mmh acc))
(vm, IntMap.empty)
mmhs
performTransition :: KernelModeTransition m mm -> VM m mm -> VM m mm
performTransition (KernelModeTransition (Subscription state pollerK mhs mmhs) ms mms cbs) vm =
let (vm, hidMap) = addHids vm mmhs in
vm { suspensions = (Suspension state pollerK mhs hidMap) : suspensions vm,
messages = reverse ms ++ (messages vm),
metaMessages = reverse mms ++ (metaMessages vm),
runnables = reverse cbs ++ (runnables vm) }
---------------------------------------------------------------------------
type LabelledMessage a b = (a, b)
groundVM :: Callback m (IO ()) () -> IO ()
groundVM boot = do inboundChannel <- newChan
mainloop inboundChannel (runVM (makeVM boot))
where mainloop ch (KernelModeTransition (Subscription newState pollingK mhs []) ms [] []) = do
runActions ch ms
case (newState, pollingK, mhs) of
(VM { messages = [], metaMessages = [], runnables = [] }, Nothing, []) ->
-- inert.
return ()
_ ->
(when (not (nested-vm-inert? (kernel-mode-transition-subscription transition)))
(match transition
[(kernel-mode-transition (subscription new-state
polling-k
message-handlers
'())
_
'()
'())
(define inbound-messages
(map (match-lambda [(message-handler e k) (wrap-evt e (lambda (v) (cons v k)))])
message-handlers))
(match-define (cons inbound-value inbound-continuation)
(apply sync
(wrap-evt (if polling-k always-evt never-evt)
(lambda (v) (cons (void)
(lambda (dummy) polling-k))))
inbound-messages))
(loop ((inbound-continuation inbound-value) new-state))]
[_
(error 'ground-vm
"Outermost VM may not spawn new siblings or send or receive metamessages")]))))