document the behaviour of throwTo to the current thread (#4888)
[ghc-base.git] / GHC / Conc / Sync.lhs
index 370bfd9..f16ee3f 100644 (file)
@@ -7,6 +7,8 @@
            , UnliftedFFITypes
            , ForeignFunctionInterface
            , DeriveDataTypeable
            , UnliftedFFITypes
            , ForeignFunctionInterface
            , DeriveDataTypeable
+           , StandaloneDeriving
+           , RankNTypes
   #-}
 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 {-# OPTIONS_HADDOCK not-home #-}
   #-}
 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 {-# OPTIONS_HADDOCK not-home #-}
@@ -39,8 +41,11 @@ module GHC.Conc.Sync
         -- * Forking and suchlike
         , forkIO        -- :: IO a -> IO ThreadId
         , forkIOUnmasked
         -- * Forking and suchlike
         , forkIO        -- :: IO a -> IO ThreadId
         , forkIOUnmasked
-        , forkOnIO      -- :: Int -> IO a -> IO ThreadId
+        , forkIOWithUnmask
+        , forkOn      -- :: Int -> IO a -> IO ThreadId
+        , forkOnIO    -- DEPRECATED
         , forkOnIOUnmasked
         , forkOnIOUnmasked
+        , forkOnWithUnmask
         , numCapabilities -- :: Int
         , getNumCapabilities -- :: IO Int
         , numSparks      -- :: IO Int
         , numCapabilities -- :: Int
         , getNumCapabilities -- :: IO Int
         , numSparks      -- :: IO Int
@@ -195,36 +200,74 @@ forkIO action = IO $ \ s ->
  where
   action_plus = catchException action childHandler
 
  where
   action_plus = catchException action childHandler
 
--- | Like 'forkIO', but the child thread is created with asynchronous exceptions
--- unmasked (see 'Control.Exception.mask').
+{-# DEPRECATED forkIOUnmasked "use forkIOWithUnmask instead" #-}
+-- | This function is deprecated; use 'forkIOWIthUnmask' instead
 forkIOUnmasked :: IO () -> IO ThreadId
 forkIOUnmasked io = forkIO (unsafeUnmask io)
 
 forkIOUnmasked :: IO () -> IO ThreadId
 forkIOUnmasked io = forkIO (unsafeUnmask io)
 
+-- | Like 'forkIO', but the child thread is passed a function that can
+-- be used to unmask asynchronous exceptions.  This function is
+-- typically used in the following way
+--
+-- >  ... mask_ $ forkIOWithUnmask $ \unmask ->
+-- >                 catch (unmask ...) handler
+--
+-- so that the exception handler in the child thread is established
+-- with asynchronous exceptions masked, meanwhile the main body of
+-- the child thread is executed in the unmasked state.
+--
+-- Note that the unmask function passed to the child thread should
+-- only be used in that thread; the behaviour is undefined if it is
+-- invoked in a different thread.
+--
+forkIOWithUnmask :: ((forall a . IO a -> IO a) -> IO ()) -> IO ThreadId
+forkIOWithUnmask io = forkIO (io unsafeUnmask)
+
 {- |
 {- |
-Like 'forkIO', but lets you specify on which CPU the thread is
-created.  Unlike a `forkIO` thread, a thread created by `forkOnIO`
-will stay on the same CPU for its entire lifetime (`forkIO` threads
-can migrate between CPUs according to the scheduling policy).
-`forkOnIO` is useful for overriding the scheduling policy when you
-know in advance how best to distribute the threads.
-
-The `Int` argument specifies the CPU number; it is interpreted modulo
-the value returned by 'getNumCapabilities'.
+Like 'forkIO', but lets you specify on which processor the thread
+should run.  Unlike a `forkIO` thread, a thread created by `forkOn`
+will stay on the same processor for its entire lifetime (`forkIO`
+threads can migrate between processors according to the scheduling
+policy).  `forkOn` is useful for overriding the scheduling policy when
+you know in advance how best to distribute the threads.
+
+The `Int` argument specifies a /capability number/ (see
+'getNumCapabilities').  Typically capabilities correspond to physical
+processors, but the exact behaviour is implementation-dependent.  The
+value passed to 'forkOn' is interpreted modulo the total number of
+capabilities as returned by 'getNumCapabilities'.
+
+GHC note: the number of capabilities is specified by the @+RTS -N@
+option when the program is started.  Capabilities can be fixed to
+actual processor cores with @+RTS -qa@ if the underlying operating
+system supports that, although in practice this is usually unnecessary
+(and may actually degrade perforamnce in some cases - experimentation
+is recommended).
 -}
 -}
-forkOnIO :: Int -> IO () -> IO ThreadId
-forkOnIO (I# cpu) action = IO $ \ s ->
+forkOn :: Int -> IO () -> IO ThreadId
+forkOn (I# cpu) action = IO $ \ s ->
    case (forkOn# cpu action_plus s) of (# s1, tid #) -> (# s1, ThreadId tid #)
  where
   action_plus = catchException action childHandler
 
    case (forkOn# cpu action_plus s) of (# s1, tid #) -> (# s1, ThreadId tid #)
  where
   action_plus = catchException action childHandler
 
--- | Like 'forkOnIO', but the child thread is created with
--- asynchronous exceptions unmasked (see 'Control.Exception.mask').
+{-# DEPRECATED forkOnIO "renamed to forkOn" #-}
+-- | This function is deprecated; use 'forkOn' instead
+forkOnIO :: Int -> IO () -> IO ThreadId
+forkOnIO = forkOn
+
+{-# DEPRECATED forkOnIOUnmasked "use forkOnWithUnmask instead" #-}
+-- | This function is deprecated; use 'forkOnWIthUnmask' instead
 forkOnIOUnmasked :: Int -> IO () -> IO ThreadId
 forkOnIOUnmasked :: Int -> IO () -> IO ThreadId
-forkOnIOUnmasked cpu io = forkOnIO cpu (unsafeUnmask io)
+forkOnIOUnmasked cpu io = forkOn cpu (unsafeUnmask io)
+
+-- | Like 'forkIOWithUnmask', but the child thread is pinned to the
+-- given CPU, as with 'forkOn'.
+forkOnWithUnmask :: Int -> ((forall a . IO a -> IO a) -> IO ()) -> IO ThreadId
+forkOnWithUnmask cpu io = forkOn cpu (io unsafeUnmask)
 
 -- | the value passed to the @+RTS -N@ flag.  This is the number of
 -- Haskell threads that can run truly simultaneously at any given
 
 -- | the value passed to the @+RTS -N@ flag.  This is the number of
 -- Haskell threads that can run truly simultaneously at any given
--- time, and is typically set to the number of physical CPU cores on
+-- time, and is typically set to the number of physical processor cores on
 -- the machine.
 -- 
 -- Strictly speaking it is better to use 'getNumCapabilities', because
 -- the machine.
 -- 
 -- Strictly speaking it is better to use 'getNumCapabilities', because
@@ -236,12 +279,12 @@ numCapabilities = unsafePerformIO $ getNumCapabilities
 {- |
 Returns the number of Haskell threads that can run truly
 simultaneously (on separate physical processors) at any given time.
 {- |
 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
+The number passed to `forkOn` 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
 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
+the machine, and 'forkOn' 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.
 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.
@@ -330,9 +373,17 @@ thread reaches a /safe point/, where a safe point is where memory
 allocation occurs.  Some loops do not perform any memory allocation
 inside the loop and therefore cannot be interrupted by a 'throwTo'.
 
 allocation occurs.  Some loops do not perform any memory allocation
 inside the loop and therefore cannot be interrupted by a 'throwTo'.
 
-Blocked 'throwTo' is fair: if multiple threads are trying to throw an
-exception to the same target thread, they will succeed in FIFO order.
-
+If the target of 'throwTo' is the calling thread, then the behaviour
+is the same as 'Control.Exception.throwIO', except that the exception
+is thrown as an asynchronous exception.  This means that if there is
+an enclosing pure computation, which would be the case if the current
+IO operation is inside 'unsafePerformIO' or 'unsafeInterleaveIO', that
+computation is not permanently replaced by the exception, but is
+suspended as if it had received an asynchronous exception.
+
+Note that if 'throwTo' is called with the current thread as the
+target, the exception will be thrown even if the thread is currently
+inside 'mask' or 'uninterruptibleMask'.
   -}
 throwTo :: Exception e => ThreadId -> e -> IO ()
 throwTo (ThreadId tid) ex = IO $ \ s ->
   -}
 throwTo :: Exception e => ThreadId -> e -> IO ()
 throwTo (ThreadId tid) ex = IO $ \ s ->
@@ -444,7 +495,7 @@ threadStatus (ThreadId t) = IO $ \s ->
 -- | returns the number of the capability on which the thread is currently
 -- running, and a boolean indicating whether the thread is locked to
 -- that capability or not.  A thread is locked to a capability if it
 -- | returns the number of the capability on which the thread is currently
 -- running, and a boolean indicating whether the thread is locked to
 -- that capability or not.  A thread is locked to a capability if it
--- was created with @forkOnIO@.
+-- was created with @forkOn@.
 threadCapability :: ThreadId -> IO (Int, Bool)
 threadCapability (ThreadId t) = IO $ \s ->
    case threadStatus# t s of
 threadCapability :: ThreadId -> IO (Int, Bool)
 threadCapability (ThreadId t) = IO $ \s ->
    case threadStatus# t s of