halive 0.1.0.3 → 0.1.0.4
raw patch · 3 files changed
+52/−2 lines, 3 filesdep +containers
Dependencies added: containers
Files
- exec/main.hs +1/−0
- halive.cabal +4/−2
- src/Halive/Concurrent.hs +47/−0
exec/main.hs view
@@ -1,6 +1,7 @@ import Halive import Banner import System.Environment+import Control.Applicative separateArgs :: [String] -> ([String], [String]) separateArgs args = (haliveArgs, drop 1 targetArgs)
halive.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: halive-version: 0.1.0.3+version: 0.1.0.4 synopsis: A live recompiler description: Live recompiler for Haskell@@ -33,11 +33,13 @@ hs-source-dirs: src exposed-modules: Halive.Utils+ Halive.Concurrent default-language: Haskell2010 ghc-options: -Wall build-depends: base,- foreign-store+ foreign-store,+ containers executable halive
+ src/Halive/Concurrent.hs view
@@ -0,0 +1,47 @@+module Halive.Concurrent (+ killThreads,+ registerThread,+ forkIO',+ forkOS'+ ) where++import Control.Concurrent+import System.IO.Unsafe+import Data.Set (Set)+import qualified Data.Set as Set++-- | A small collection of helper functions for creating threads that can be killed each time Halive re-runs your main function.+-- This is helpful for programs where you control the threads, but doesn't solve the problem of libraries that use threads +-- (unless you unpack them and replace all forkIO/forkOS with forkIO'/forkOS')+-- It would be good to ask GHC devs about this; +-- perhaps a GHC flag that registers threads similar to this module, for development use only?++-- An internal global variable to hold threads that should be killed+{-# NOINLINE registeredThreads #-}+registeredThreads :: MVar (Set ThreadId)+registeredThreads = unsafePerformIO (newMVar Set.empty)++-- | Kill all threads registered to be killed.+-- Meant to be called at the beginning of your program to clean up threads from the last execution before continuing+killThreads :: IO ()+killThreads = modifyMVar_ registeredThreads $ \threadIDs -> do+ mapM_ killThread threadIDs+ return Set.empty++-- | Register a thread to be killed when killThreads is called+registerThread :: ThreadId -> IO ()+registerThread threadID = modifyMVar_ registeredThreads (return . Set.insert threadID)++-- | Fork a thread and register it to be killed when killThreads is called+forkIO' :: IO () -> IO ThreadId+forkIO' action = do+ threadID <- forkIO action+ registerThread threadID+ return threadID++-- | Fork an OS thread and register it to be killed when killThreads is called+forkOS' :: IO () -> IO ThreadId+forkOS' action = do+ threadID <- forkOS action+ registerThread threadID+ return threadID