Created
August 16, 2023 11:56
-
-
Save Lucus16/4a78d4a19a8979d2545b90eb590742e6 to your computer and use it in GitHub Desktop.
Proof of concept for interruptible-checked IO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module System.SafeIO where | |
import "base" Control.Concurrent ( ThreadId ) | |
import "base" Control.Concurrent qualified as Unsafe | |
import "base" Control.Exception ( AsyncException(..), Exception(..) ) | |
import "base" Control.Exception qualified as Unsafe | |
import "base" Prelude ( Applicative(..), Functor(..), Monad(..), const, ($), (.) ) | |
import "base" System.IO qualified as Unsafe | |
data Uninterruptible | |
data Interruptible | |
newtype SafeIO i a = SafeIO { unSafeIO :: Unsafe.IO a } | |
instance Functor (SafeIO i) where | |
fmap f = SafeIO . fmap f . unSafeIO | |
instance Applicative (SafeIO i) where | |
pure = SafeIO . pure | |
SafeIO f <*> SafeIO x = SafeIO $ f <*> x | |
instance Monad (SafeIO i) where | |
SafeIO x >>= f = SafeIO $ x >>= unSafeIO . f | |
liftInterruptibleIO :: Unsafe.IO a -> SafeIO Interruptible a | |
liftInterruptibleIO = SafeIO | |
liftUninterruptibleIO :: Unsafe.IO a -> SafeIO i a | |
liftUninterruptibleIO = SafeIO | |
mask :: ((forall a. SafeIO o a -> SafeIO Uninterruptible a) -> SafeIO Uninterruptible b) -> SafeIO o b | |
mask unmaskToSafeIO = SafeIO $ Unsafe.mask \unsafeUnmask -> unSafeIO $ unmaskToSafeIO $ SafeIO . unsafeUnmask . unSafeIO | |
mask_ :: SafeIO Uninterruptible b -> SafeIO o b | |
mask_ io = mask (const io) | |
forkIO :: SafeIO i () -> SafeIO i ThreadId | |
forkIO (SafeIO io) = SafeIO (Unsafe.forkIO io) | |
forkIOWithUnmask :: ((forall a. SafeIO i a -> SafeIO Uninterruptible a) -> SafeIO Uninterruptible ()) -> SafeIO o ThreadId | |
forkIOWithUnmask unmaskToSafeIO = SafeIO $ Unsafe.forkIOWithUnmask \unsafeUnmask -> unSafeIO $ unmaskToSafeIO $ SafeIO . unsafeUnmask . unSafeIO | |
myThreadId :: SafeIO i ThreadId | |
myThreadId = SafeIO Unsafe.myThreadId | |
killThread :: ThreadId -> SafeIO Interruptible () | |
killThread tId = throwTo tId ThreadKilled | |
throwTo :: Exception e => ThreadId -> e -> SafeIO Interruptible () | |
throwTo tId e = SafeIO $ Unsafe.throwTo tId e | |
test :: SafeIO Interruptible () | |
test = do | |
someThreadId <- forkIO $ pure () | |
otherThreadId <- mask \unmask -> forkIO do | |
killThread someThreadId | |
tid2 <- mask_ $ mask \restore -> forkIOWithUnmask \unmask -> do | |
unmask $ killThread someThreadId | |
pure () |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment