{-# OPTIONS_GHC -XImplicitParams #-} module Process where import MBox import Control.Exception import System.IO data Process a = Process (a -> IO (Maybe ())) -- write message (IO Bool) -- is open? (IO (Maybe Bool)) -- is empty? -- a process is a build-run-in-my-private-world style process, similar to what Erlang uses, it is -- intentional that no forkIO/forkOS is done in runProcess - it is the responsibility ofthe caller -- proc is bracket(ed) to guarantee that on any exit, including exceptions the mail box is closed -- Unfortunately there is a possibility of resource leaks through mboxes. If a Process structure -- is kept somewhere outside runProcess, it won't be garbage collected. It remains to be seen how -- best to reduce, or eliminate, the risk of that. The problem is that the Process structure -- *must* be passed outside, otherwise it will be a very lonely thread.... runProcess :: Process (Process a) -> (Process a -> IO ()) -> IO () runProcess (Process sendBack isOpen isEmpty) proc = do mbox <- newMBox let ?receive = readMBox mbox let ?tryReceive = tryReadMBox mbox let ?unGet = unGetMBox mbox let p = (Process (writeMBox mbox) (isOpenMBox mbox) (isEmptyMBox mbox)) --should check, for safety, alternatively could take a don't care attitude ok <- sendBack p case ok of Just _ -> bracket (return p) (\_ -> (closeMBox mbox)) proc Nothing -> (closeMBox mbox)