\begin{code}
-{-# OPTIONS_GHC -XNoImplicitPrelude #-}
+{-# LANGUAGE CPP
+ , NoImplicitPrelude
+ , BangPatterns
+ , MagicHash
+ , UnboxedTuples
+ , UnliftedFFITypes
+ , ForeignFunctionInterface
+ , DeriveDataTypeable
+ #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# OPTIONS_HADDOCK not-home #-}
+
-----------------------------------------------------------------------------
-- |
-- Module : GHC.Conc.Sync
, forkOnIO -- :: Int -> IO a -> IO ThreadId
, forkOnIOUnmasked
, numCapabilities -- :: Int
+ , getNumCapabilities -- :: IO Int
, numSparks -- :: IO Int
, childHandler -- :: Exception -> IO ()
, myThreadId -- :: IO ThreadId
, atomically -- :: STM a -> IO a
, retry -- :: STM a
, orElse -- :: STM a -> STM a -> STM a
- , catchSTM -- :: STM a -> (Exception -> STM a) -> STM a
+ , throwSTM -- :: Exception e => e -> STM a
+ , catchSTM -- :: Exception e => STM a -> (e -> STM a) -> STM a
, alwaysSucceeds -- :: STM a -> STM ()
, always -- :: STM Bool -> STM ()
, TVar(..)
, sharedCAF
) where
-import Foreign
+import Foreign hiding (unsafePerformIO)
import Foreign.C
#ifdef mingw32_HOST_OS
import GHC.Exception
import GHC.IORef
import GHC.MVar
-import GHC.Num ( Num(..) )
import GHC.Real ( fromIntegral )
import GHC.Pack ( packCString# )
import GHC.Show ( Show(..), showString )
know in advance how best to distribute the threads.
The `Int` argument specifies the CPU number; it is interpreted modulo
-'numCapabilities' (note that it actually specifies a capability number
-rather than a CPU number, but to a first approximation the two are
-equivalent).
+the value returned by 'getNumCapabilities'.
-}
forkOnIO :: Int -> IO () -> IO ThreadId
forkOnIO (I# cpu) action = IO $ \ s ->
-- Haskell threads that can run truly simultaneously at any given
-- time, and is typically set to the number of physical CPU cores on
-- the machine.
+--
+-- Strictly speaking it is better to use 'getNumCapabilities', because
+-- the number of capabilities might vary at runtime.
+--
numCapabilities :: Int
-numCapabilities = unsafePerformIO $ do
- n <- peek n_capabilities
- return (fromIntegral n)
+numCapabilities = unsafePerformIO $ getNumCapabilities
+
+{- |
+Returns the number of Haskell threads that can run truly
+simultaneously (on separate physical processors) at any given time.
+The CPU number passed to `forkOnIO` is interpreted modulo this
+value.
+
+An implementation in which Haskell threads are mapped directly to
+OS threads might return the number of physical processor cores in
+the machine, and 'forkOnIO' would be implemented using the OS's
+affinity facilities. An implementation that schedules Haskell
+threads onto a smaller number of OS threads (like GHC) would return
+the number of such OS threads that can be running simultaneously.
+
+GHC notes: this returns the number passed as the argument to the
+@+RTS -N@ flag. In current implementations, the value is fixed
+when the program starts and never changes, but it is possible that
+in the future the number of capabilities might vary at runtime.
+-}
+getNumCapabilities :: IO Int
+getNumCapabilities = do
+ n <- peek n_capabilities
+ return (fromIntegral n)
-- | Returns the number of sparks currently in the local spark pool
numSparks :: IO Int
If the target thread is currently making a foreign call, then the
exception will not be raised (and hence 'throwTo' will not return)
until the call has completed. This is the case regardless of whether
-the call is inside a 'mask' or not.
+the call is inside a 'mask' or not. However, in GHC a foreign call
+can be annotated as @interruptible@, in which case a 'throwTo' will
+cause the RTS to attempt to cause the call to return; see the GHC
+documentation for more details.
Important note: the behaviour of 'throwTo' differs from that described in
the paper \"Asynchronous exceptions in Haskell\"
threadStatus :: ThreadId -> IO ThreadStatus
threadStatus (ThreadId t) = IO $ \s ->
case threadStatus# t s of
- (# s', stat #) -> (# s', mk_stat (I# stat) #)
+ (# s', stat, _cap #) -> (# s', mk_stat (I# stat) #)
where
-- NB. keep these in sync with includes/Constants.h
mk_stat 0 = ThreadRunning
mk_stat 1 = ThreadBlocked BlockedOnMVar
mk_stat 2 = ThreadBlocked BlockedOnBlackHole
- mk_stat 3 = ThreadBlocked BlockedOnException
- mk_stat 7 = ThreadBlocked BlockedOnSTM
+ mk_stat 6 = ThreadBlocked BlockedOnSTM
+ mk_stat 10 = ThreadBlocked BlockedOnForeignCall
mk_stat 11 = ThreadBlocked BlockedOnForeignCall
- mk_stat 12 = ThreadBlocked BlockedOnForeignCall
+ mk_stat 12 = ThreadBlocked BlockedOnException
mk_stat 16 = ThreadFinished
mk_stat 17 = ThreadDied
mk_stat _ = ThreadBlocked BlockedOnOther
orElse :: STM a -> STM a -> STM a
orElse (STM m) e = STM $ \s -> catchRetry# m (unSTM e) s
+-- | A variant of 'throw' that can only be used within the 'STM' monad.
+--
+-- Throwing an exception in @STM@ aborts the transaction and propagates the
+-- exception.
+--
+-- Although 'throwSTM' has a type that is an instance of the type of 'throw', the
+-- two functions are subtly different:
+--
+-- > throw e `seq` x ===> throw e
+-- > throwSTM e `seq` x ===> x
+--
+-- The first example will cause the exception @e@ to be raised,
+-- whereas the second one won\'t. In fact, 'throwSTM' will only cause
+-- an exception to be raised when it is used within the 'STM' monad.
+-- The 'throwSTM' variant should be used in preference to 'throw' to
+-- raise an exception within the 'STM' monad because it guarantees
+-- ordering with respect to other 'STM' operations, whereas 'throw'
+-- does not.
+throwSTM :: Exception e => e -> STM a
+throwSTM e = STM $ raiseIO# (toException e)
+
-- |Exception handling within STM actions.
-catchSTM :: STM a -> (SomeException -> STM a) -> STM a
-catchSTM (STM m) k = STM $ \s -> catchSTM# m (\ex -> unSTM (k ex)) s
+catchSTM :: Exception e => STM a -> (e -> STM a) -> STM a
+catchSTM (STM m) handler = STM $ catchSTM# m handler'
+ where
+ handler' e = case fromException e of
+ Just e' -> unSTM (handler e')
+ Nothing -> raiseIO# e
-- | Low-level primitive on which always and alwaysSucceeds are built.
-- checkInv differs form these in that (i) the invariant is not