Skip to content

Instantly share code, notes, and snippets.

@barrucadu
Last active June 23, 2020 17:34
Show Gist options
  • Save barrucadu/c3e4384074f3c7dcc15cf9dbe4d1b53d to your computer and use it in GitHub Desktop.
Save barrucadu/c3e4384074f3c7dcc15cf9dbe4d1b53d to your computer and use it in GitHub Desktop.
data ThreadId = ThreadId
{ realThreadId :: Int
, exceptionVariable :: TVar (Maybe SomeException)
, canBeThrownTo :: TVar Bool
}
-- when a thread is created: canBeThrownTo depends on the masking state (True for Unmasked, False otherwise)
-- when a thread is killed: canBeThrownTo is True
---
-- throwTo becomes this:
throwTo :: Exception e => ThreadId e -> IO ()
throwTo t@(ThreadId _ ve vb) e = synchronised . atomicallyU $ readTVar vb >>= \case
True -> writeTVar ve (Just (toException e))
False -> retry
-- all actions are transformed into this:
transform :: ThreadId -> MaskingState -> Bool -> IO a -> IO a
tranasform (ThreadId _ ve vb) ms thisIsARepeatOfABlockingAction a = case ms of
Unmasked -> allowException
MaskedInterruptible -> if thisIsARepeatOfABlockingAction then allowException else a
MaskedUninterruptible -> a
where
allowException = do
atomicallyU (writeTVar vb True)
atomicallyU (writeTVar vb False >> readTVar ve) >>= \case
Just e -> throwAsync e -- throw an async exception in the current thread
Nothing -> a
-- 'atomicallyU' is just 'atomically', but doesn't enforce a memory barrier
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment