Remove unused imports from base
[ghc-base.git] / GHC / Conc.lhs
index 1b61036..4318825 100644 (file)
@@ -1,5 +1,6 @@
 \begin{code}
 {-# OPTIONS_GHC -XNoImplicitPrelude #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 {-# OPTIONS_HADDOCK not-home #-}
 -----------------------------------------------------------------------------
 -- |
@@ -36,6 +37,7 @@ module GHC.Conc
         , throwTo       -- :: ThreadId -> Exception -> IO ()
         , par           -- :: a -> b -> b
         , pseq          -- :: a -> b -> b
+        , runSparks
         , yield         -- :: IO ()
         , labelThread   -- :: ThreadId -> String -> IO ()
 
@@ -48,17 +50,6 @@ module GHC.Conc
         , threadWaitRead        -- :: Int -> IO ()
         , threadWaitWrite       -- :: Int -> IO ()
 
-        -- * MVars
-        , MVar(..)
-        , newMVar       -- :: a -> IO (MVar a)
-        , newEmptyMVar  -- :: IO (MVar a)
-        , takeMVar      -- :: MVar a -> IO a
-        , putMVar       -- :: MVar a -> a -> IO ()
-        , tryTakeMVar   -- :: MVar a -> IO (Maybe a)
-        , tryPutMVar    -- :: MVar a -> a -> IO Bool
-        , isEmptyMVar   -- :: MVar a -> IO Bool
-        , addMVarFinalizer -- :: MVar a -> IO () -> IO ()
-
         -- * TVars
         , STM(..)
         , atomically    -- :: STM a -> IO a
@@ -71,10 +62,12 @@ module GHC.Conc
         , newTVar       -- :: a -> STM (TVar a)
         , newTVarIO     -- :: a -> STM (TVar a)
         , readTVar      -- :: TVar a -> STM a
+        , readTVarIO    -- :: TVar a -> IO a
         , writeTVar     -- :: a -> TVar a -> STM ()
         , unsafeIOToSTM -- :: IO a -> STM a
 
         -- * Miscellaneous
+        , withMVar
 #ifdef mingw32_HOST_OS
         , asyncRead     -- :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
         , asyncWrite    -- :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
@@ -85,16 +78,23 @@ module GHC.Conc
 #endif
 
 #ifndef mingw32_HOST_OS
-        , signalHandlerLock
+        , Signal, HandlerFun, setHandler, runHandlers
 #endif
 
         , ensureIOManagerIsRunning
+#ifndef mingw32_HOST_OS
+        , syncIOManager
+#endif
 
 #ifdef mingw32_HOST_OS
         , ConsoleEvent(..)
         , win32ConsoleHandler
         , toWin32ConsoleEvent
 #endif
+        , setUncaughtExceptionHandler      -- :: (Exception -> IO ()) -> IO ()
+        , getUncaughtExceptionHandler      -- :: IO (Exception -> IO ())
+
+        , reportError, reportStackOverflow
         ) where
 
 import System.Posix.Types
@@ -104,29 +104,39 @@ import System.Posix.Internals
 import Foreign
 import Foreign.C
 
-#ifndef __HADDOCK__
-import {-# SOURCE #-} GHC.TopHandler ( reportError, reportStackOverflow )
+#ifndef mingw32_HOST_OS
+import Data.Dynamic
+import Control.Monad
 #endif
-
 import Data.Maybe
 
 import GHC.Base
-import GHC.IOBase
+import {-# SOURCE #-} GHC.IO.Handle ( hFlush )
+import {-# SOURCE #-} GHC.IO.Handle.FD ( stdout )
+import GHC.IO
+import GHC.IO.Exception
+import GHC.Exception
+import GHC.IORef
+import GHC.MVar
 import GHC.Num          ( Num(..) )
-import GHC.Real         ( fromIntegral, div )
+import GHC.Real         ( fromIntegral )
 #ifndef mingw32_HOST_OS
-import GHC.Base         ( Int(..) )
+import GHC.IOArray
+import GHC.Arr          ( inRange )
+#endif
+#ifdef mingw32_HOST_OS
+import GHC.Real         ( div )
+import GHC.Ptr          ( FunPtr(..) )
 #endif
 #ifdef mingw32_HOST_OS
 import GHC.Read         ( Read )
 import GHC.Enum         ( Enum )
 #endif
-import GHC.Exception    ( SomeException(..), throw )
 import GHC.Pack         ( packCString# )
-import GHC.Ptr          ( Ptr(..), plusPtr, FunPtr(..) )
-import GHC.STRef
+import GHC.Ptr          ( Ptr(..) )
 import GHC.Show         ( Show(..), showString )
 import Data.Typeable
+import GHC.Err
 
 infixr 0 `par`, `pseq`
 \end{code}
@@ -199,10 +209,15 @@ library that uses thread-local storage, use 'Control.Concurrent.forkOS' instead.
 
 GHC note: the new thread inherits the /blocked/ state of the parent 
 (see 'Control.Exception.block').
+
+The newly created thread has an exception handler that discards the
+exceptions 'BlockedOnDeadMVar', 'BlockedIndefinitely', and
+'ThreadKilled', and passes all other exceptions to the uncaught
+exception handler (see 'setUncaughtExceptionHandler').
 -}
 forkIO :: IO () -> IO ThreadId
 forkIO action = IO $ \ s -> 
-   case (fork# action_plus s) of (# s1, id #) -> (# s1, ThreadId id #)
+   case (fork# action_plus s) of (# s1, tid #) -> (# s1, ThreadId tid #)
  where
   action_plus = catchException action childHandler
 
@@ -221,7 +236,7 @@ equivalent).
 -}
 forkOnIO :: Int -> IO () -> IO ThreadId
 forkOnIO (I# cpu) action = IO $ \ s -> 
-   case (forkOn# cpu action_plus s) of (# s1, id #) -> (# s1, ThreadId id #)
+   case (forkOn# cpu action_plus s) of (# s1, tid #) -> (# s1, ThreadId tid #)
  where
   action_plus = catchException action childHandler
 
@@ -234,8 +249,11 @@ numCapabilities = unsafePerformIO $  do
                     n <- peek n_capabilities
                     return (fromIntegral n)
 
+#if defined(mingw32_HOST_OS) && defined(__PIC__)
+foreign import ccall "_imp__n_capabilities" n_capabilities :: Ptr CInt
+#else
 foreign import ccall "&n_capabilities" n_capabilities :: Ptr CInt
-
+#endif
 childHandler :: SomeException -> IO ()
 childHandler err = catchException (real_handler err) childHandler
 
@@ -260,11 +278,12 @@ The memory used by the thread will be garbage collected if it isn\'t
 referenced from anywhere.  The 'killThread' function is defined in
 terms of 'throwTo':
 
-> killThread tid = throwTo tid (AsyncException ThreadKilled)
+> killThread tid = throwTo tid ThreadKilled
 
+Killthread is a no-op if the target thread has already completed.
 -}
 killThread :: ThreadId -> IO ()
-killThread tid = throwTo tid (toException ThreadKilled)
+killThread tid = throwTo tid ThreadKilled
 
 {- | 'throwTo' raises an arbitrary exception in the target thread (GHC only).
 
@@ -286,25 +305,24 @@ the paper \"Asynchronous exceptions in Haskell\"
 (<http://research.microsoft.com/~simonpj/Papers/asynch-exns.htm>).
 In the paper, 'throwTo' is non-blocking; but the library implementation adopts
 a more synchronous design in which 'throwTo' does not return until the exception
-is received by the target thread.  The trade-off is discussed in Section 8 of the paper.
-Like any blocking operation, 'throwTo' is therefore interruptible (see Section 4.3 of
+is received by the target thread.  The trade-off is discussed in Section 9 of the paper.
+Like any blocking operation, 'throwTo' is therefore interruptible (see Section 5.3 of
 the paper).
 
 There is currently no guarantee that the exception delivered by 'throwTo' will be
-delivered at the first possible opportunity.  In particular, if a thread may 
+delivered at the first possible opportunity.  In particular, a thread may 
 unblock and then re-block exceptions (using 'unblock' and 'block') without receiving
 a pending 'throwTo'.  This is arguably undesirable behaviour.
 
  -}
--- XXX This is duplicated in Control.{Old,}Exception
-throwTo :: ThreadId -> SomeException -> IO ()
-throwTo (ThreadId id) ex = IO $ \ s ->
-   case (killThread# id ex s) of s1 -> (# s1, () #)
+throwTo :: Exception e => ThreadId -> e -> IO ()
+throwTo (ThreadId tid) ex = IO $ \ s ->
+   case (killThread# tid (toException ex) s) of s1 -> (# s1, () #)
 
 -- | Returns the 'ThreadId' of the calling thread (GHC only).
 myThreadId :: IO ThreadId
 myThreadId = IO $ \s ->
-   case (myThreadId# s) of (# s1, id #) -> (# s1, ThreadId id #)
+   case (myThreadId# s) of (# s1, tid #) -> (# s1, ThreadId tid #)
 
 
 -- |The 'yield' action allows (forces, in a co-operative multitasking
@@ -327,8 +345,8 @@ Other applications like the graphical Concurrent Haskell Debugger
 
 labelThread :: ThreadId -> String -> IO ()
 labelThread (ThreadId t) str = IO $ \ s ->
-   let ps  = packCString# str
-       adr = byteArrayContents# ps in
+   let !ps  = packCString# str
+       !adr = byteArrayContents# ps in
      case (labelThread# t adr s) of s1 -> (# s1, () #)
 
 --      Nota Bene: 'pseq' used to be 'seq'
@@ -350,6 +368,13 @@ pseq  x y = x `seq` lazy y
 par :: a -> b -> b
 par  x y = case (par# x) of { _ -> lazy y }
 
+-- | Internal function used by the RTS to run sparks.
+runSparks :: IO ()
+runSparks = IO loop
+  where loop s = case getSpark# s of
+                   (# s', n, p #) ->
+                      if n ==# 0# then (# s', () #)
+                                  else p `seq` loop s'
 
 data BlockReason
   = BlockedOnMVar
@@ -437,7 +462,7 @@ bindSTM (STM m) k = STM ( \s ->
 thenSTM :: STM a -> STM b -> STM b
 thenSTM (STM m) k = STM ( \s ->
   case m s of 
-    (# new_s, a #) -> unSTM k new_s
+    (# new_s, _ #) -> unSTM k new_s
   )
 
 returnSTM :: a -> STM a
@@ -546,6 +571,16 @@ newTVarIO val = IO $ \s1# ->
     case newTVar# val s1# of
          (# s2#, tvar# #) -> (# s2#, TVar tvar# #)
 
+-- |Return the current value stored in a TVar.
+-- This is equivalent to
+--
+-- >  readTVarIO = atomically . readTVar
+--
+-- but works much faster, because it doesn't perform a complete
+-- transaction, it just reads the current value of the 'TVar'.
+readTVarIO :: TVar a -> IO a
+readTVarIO (TVar tvar#) = IO $ \s# -> readTVarIO# tvar# s#
+
 -- |Return the current value stored in a TVar
 readTVar :: TVar a -> STM a
 readTVar (TVar tvar#) = STM $ \s# -> readTVar# tvar# s#
@@ -558,109 +593,9 @@ writeTVar (TVar tvar#) val = STM $ \s1# ->
   
 \end{code}
 
-%************************************************************************
-%*                                                                      *
-\subsection[mvars]{M-Structures}
-%*                                                                      *
-%************************************************************************
-
-M-Vars are rendezvous points for concurrent threads.  They begin
-empty, and any attempt to read an empty M-Var blocks.  When an M-Var
-is written, a single blocked thread may be freed.  Reading an M-Var
-toggles its state from full back to empty.  Therefore, any value
-written to an M-Var may only be read once.  Multiple reads and writes
-are allowed, but there must be at least one read between any two
-writes.
+MVar utilities
 
 \begin{code}
---Defined in IOBase to avoid cycle: data MVar a = MVar (SynchVar# RealWorld a)
-
--- |Create an 'MVar' which is initially empty.
-newEmptyMVar  :: IO (MVar a)
-newEmptyMVar = IO $ \ s# ->
-    case newMVar# s# of
-         (# s2#, svar# #) -> (# s2#, MVar svar# #)
-
--- |Create an 'MVar' which contains the supplied value.
-newMVar :: a -> IO (MVar a)
-newMVar value =
-    newEmptyMVar        >>= \ mvar ->
-    putMVar mvar value  >>
-    return mvar
-
--- |Return the contents of the 'MVar'.  If the 'MVar' is currently
--- empty, 'takeMVar' will wait until it is full.  After a 'takeMVar', 
--- the 'MVar' is left empty.
--- 
--- There are two further important properties of 'takeMVar':
---
---   * 'takeMVar' is single-wakeup.  That is, if there are multiple
---     threads blocked in 'takeMVar', and the 'MVar' becomes full,
---     only one thread will be woken up.  The runtime guarantees that
---     the woken thread completes its 'takeMVar' operation.
---
---   * When multiple threads are blocked on an 'MVar', they are
---     woken up in FIFO order.  This is useful for providing
---     fairness properties of abstractions built using 'MVar's.
---
-takeMVar :: MVar a -> IO a
-takeMVar (MVar mvar#) = IO $ \ s# -> takeMVar# mvar# s#
-
--- |Put a value into an 'MVar'.  If the 'MVar' is currently full,
--- 'putMVar' will wait until it becomes empty.
---
--- There are two further important properties of 'putMVar':
---
---   * 'putMVar' is single-wakeup.  That is, if there are multiple
---     threads blocked in 'putMVar', and the 'MVar' becomes empty,
---     only one thread will be woken up.  The runtime guarantees that
---     the woken thread completes its 'putMVar' operation.
---
---   * When multiple threads are blocked on an 'MVar', they are
---     woken up in FIFO order.  This is useful for providing
---     fairness properties of abstractions built using 'MVar's.
---
-putMVar  :: MVar a -> a -> IO ()
-putMVar (MVar mvar#) x = IO $ \ s# ->
-    case putMVar# mvar# x s# of
-        s2# -> (# s2#, () #)
-
--- |A non-blocking version of 'takeMVar'.  The 'tryTakeMVar' function
--- returns immediately, with 'Nothing' if the 'MVar' was empty, or
--- @'Just' a@ if the 'MVar' was full with contents @a@.  After 'tryTakeMVar',
--- the 'MVar' is left empty.
-tryTakeMVar :: MVar a -> IO (Maybe a)
-tryTakeMVar (MVar m) = IO $ \ s ->
-    case tryTakeMVar# m s of
-        (# s, 0#, _ #) -> (# s, Nothing #)      -- MVar is empty
-        (# s, _,  a #) -> (# s, Just a  #)      -- MVar is full
-
--- |A non-blocking version of 'putMVar'.  The 'tryPutMVar' function
--- attempts to put the value @a@ into the 'MVar', returning 'True' if
--- it was successful, or 'False' otherwise.
-tryPutMVar  :: MVar a -> a -> IO Bool
-tryPutMVar (MVar mvar#) x = IO $ \ s# ->
-    case tryPutMVar# mvar# x s# of
-        (# s, 0# #) -> (# s, False #)
-        (# s, _  #) -> (# s, True #)
-
--- |Check whether a given 'MVar' is empty.
---
--- Notice that the boolean value returned  is just a snapshot of
--- the state of the MVar. By the time you get to react on its result,
--- the MVar may have been filled (or emptied) - so be extremely
--- careful when using this operation.   Use 'tryTakeMVar' instead if possible.
-isEmptyMVar :: MVar a -> IO Bool
-isEmptyMVar (MVar mv#) = IO $ \ s# -> 
-    case isEmptyMVar# mv# s# of
-        (# s2#, flg #) -> (# s2#, not (flg ==# 0#) #)
-
--- |Add a finalizer to an 'MVar' (GHC only).  See "Foreign.ForeignPtr" and
--- "System.Mem.Weak" for more about finalizers.
-addMVarFinalizer :: MVar a -> IO () -> IO ()
-addMVarFinalizer (MVar m) finalizer = 
-  IO $ \s -> case mkWeak# m () finalizer s of { (# s1, w #) -> (# s1, () #) }
-
 withMVar :: MVar a -> (a -> IO b) -> IO b
 withMVar m io = 
   block $ do
@@ -671,7 +606,6 @@ withMVar m io =
     return b
 \end{code}
 
-
 %************************************************************************
 %*                                                                      *
 \subsection{Thread waiting}
@@ -688,19 +622,19 @@ withMVar m io =
 asyncRead :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
 asyncRead  (I# fd) (I# isSock) (I# len) (Ptr buf) =
   IO $ \s -> case asyncRead# fd isSock len buf s of 
-               (# s, len#, err# #) -> (# s, (I# len#, I# err#) #)
+               (# s', len#, err# #) -> (# s', (I# len#, I# err#) #)
 
 asyncWrite :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
 asyncWrite  (I# fd) (I# isSock) (I# len) (Ptr buf) =
   IO $ \s -> case asyncWrite# fd isSock len buf s of 
-               (# s, len#, err# #) -> (# s, (I# len#, I# err#) #)
+               (# s', len#, err# #) -> (# s', (I# len#, I# err#) #)
 
 asyncDoProc :: FunPtr (Ptr a -> IO Int) -> Ptr a -> IO Int
 asyncDoProc (FunPtr proc) (Ptr param) = 
     -- the 'length' value is ignored; simplifies implementation of
     -- the async*# primops to have them all return the same result.
   IO $ \s -> case asyncDoProc# proc param s  of 
-               (# s, len#, err# #) -> (# s, I# err# #)
+               (# s', _len#, err# #) -> (# s', I# err# #)
 
 -- to aid the use of these primops by the IO Handle implementation,
 -- provide the following convenience funs:
@@ -728,7 +662,7 @@ threadWaitRead fd
 #endif
   | otherwise = IO $ \s -> 
         case fromIntegral fd of { I# fd# ->
-        case waitRead# fd# s of { s -> (# s, () #)
+        case waitRead# fd# s of { s' -> (# s', () #)
         }}
 
 -- | Block the current thread until data can be written to the
@@ -740,7 +674,7 @@ threadWaitWrite fd
 #endif
   | otherwise = IO $ \s -> 
         case fromIntegral fd of { I# fd# ->
-        case waitWrite# fd# s of { s -> (# s, () #)
+        case waitWrite# fd# s of { s' -> (# s', () #)
         }}
 
 -- | Suspends the current thread for a given number of microseconds
@@ -755,7 +689,7 @@ threadDelay time
   | threaded  = waitForDelayEvent time
   | otherwise = IO $ \s -> 
         case fromIntegral time of { I# time# ->
-        case delay# time# s of { s -> (# s, () #)
+        case delay# time# s of { s' -> (# s', () #)
         }}
 
 
@@ -866,10 +800,6 @@ delayTime (DelaySTM t _) = t
 
 type USecs = Word64
 
--- XXX: move into GHC.IOBase from Data.IORef?
-atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b
-atomicModifyIORef (IORef (STRef r#)) f = IO $ \s -> atomicModifyMutVar# r# f s
-
 foreign import ccall unsafe "getUSecOfDay" 
   getUSecOfDay :: IO USecs
 
@@ -908,26 +838,29 @@ service_loop wakeup old_delays = do
   case r of
     0xffffffff -> do c_maperrno; throwErrno "service_loop"
     0 -> do
-        r <- c_readIOManagerEvent
+        r2 <- c_readIOManagerEvent
         exit <- 
-              case r of
-                _ | r == io_MANAGER_WAKEUP -> return False
-                _ | r == io_MANAGER_DIE    -> return True
+              case r2 of
+                _ | r2 == io_MANAGER_WAKEUP -> return False
+                _ | r2 == io_MANAGER_DIE    -> return True
                 0 -> return False -- spurious wakeup
-                r -> do start_console_handler (r `shiftR` 1); return False
+                _ -> do start_console_handler (r2 `shiftR` 1); return False
         if exit
           then return ()
           else service_cont wakeup delays'
 
     _other -> service_cont wakeup delays' -- probably timeout        
 
+service_cont :: HANDLE -> [DelayReq] -> IO ()
 service_cont wakeup delays = do
-  atomicModifyIORef prodding (\_ -> (False,False))
+  r <- atomicModifyIORef prodding (\_ -> (False,False))
+  r `seq` return () -- avoid space leak
   service_loop wakeup delays
 
 -- must agree with rts/win32/ThrIOManager.c
-io_MANAGER_WAKEUP = 0xffffffff :: Word32
-io_MANAGER_DIE    = 0xfffffffe :: Word32
+io_MANAGER_WAKEUP, io_MANAGER_DIE :: Word32
+io_MANAGER_WAKEUP = 0xffffffff
+io_MANAGER_DIE    = 0xfffffffe
 
 data ConsoleEvent
  = ControlC
@@ -946,6 +879,7 @@ start_console_handler r =
                     return ()
      Nothing -> return ()
 
+toWin32ConsoleEvent :: Num a => a -> Maybe ConsoleEvent
 toWin32ConsoleEvent ev = 
    case ev of
        0 {- CTRL_C_EVENT-}        -> Just ControlC
@@ -958,19 +892,21 @@ toWin32ConsoleEvent ev =
 win32ConsoleHandler :: MVar (ConsoleEvent -> IO ())
 win32ConsoleHandler = unsafePerformIO (newMVar (error "win32ConsoleHandler"))
 
+-- XXX Is this actually needed?
 stick :: IORef HANDLE
 {-# NOINLINE stick #-}
 stick = unsafePerformIO (newIORef nullPtr)
 
+wakeupIOManager :: IO ()
 wakeupIOManager = do 
-  hdl <- readIORef stick
+  _hdl <- readIORef stick
   c_sendIOManagerEvent io_MANAGER_WAKEUP
 
 -- Walk the queue of pending delays, waking up any that have passed
 -- and return the smallest delay to wait for.  The queue of pending
 -- delays is kept ordered.
 getDelay :: USecs -> [DelayReq] -> IO ([DelayReq], DWORD)
-getDelay now [] = return ([], iNFINITE)
+getDelay _   [] = return ([], iNFINITE)
 getDelay now all@(d : rest) 
   = case d of
      Delay time m | now >= time -> do
@@ -991,7 +927,8 @@ getDelay now all@(d : rest)
 type HANDLE       = Ptr ()
 type DWORD        = Word32
 
-iNFINITE = 0xFFFFFFFF :: DWORD -- urgh
+iNFINITE :: DWORD
+iNFINITE = 0xFFFFFFFF -- urgh
 
 foreign import ccall unsafe "getIOManagerEvent" -- in the RTS (ThrIOManager.c)
   c_getIOManagerEvent :: IO HANDLE
@@ -1018,6 +955,10 @@ startIOManagerThread = do
         throwErrnoIfMinus1 "startIOManagerThread" (c_pipe fds)
         rd_end <- peekElemOff fds 0
         wr_end <- peekElemOff fds 1
+        setNonBlockingFD wr_end True -- writes happen in a signal handler, we
+                                     -- don't want them to block.
+        setCloseOnExec rd_end
+        setCloseOnExec wr_end
         writeIORef stick (fromIntegral wr_end)
         c_setIOManagerPipe wr_end
         forkIO $ do
@@ -1043,7 +984,7 @@ service_loop wakeup readfds writefds ptimeval old_reqs old_delays = do
 
   -- pick up new delay requests
   new_delays <- atomicModifyIORef pendingDelays (\a -> ([],a))
-  let  delays = foldr insertDelay old_delays new_delays
+  let  delays0 = foldr insertDelay old_delays new_delays
 
   -- build the FDSets for select()
   fdZero readfds
@@ -1076,7 +1017,7 @@ service_loop wakeup readfds writefds ptimeval old_reqs old_delays = do
              else
                 return (False,delays')
 
-  (wakeup_all,delays') <- do_select delays
+  (wakeup_all,delays') <- do_select delays0
 
   exit <-
     if wakeup_all then return False
@@ -1085,17 +1026,24 @@ service_loop wakeup readfds writefds ptimeval old_reqs old_delays = do
         if b == 0 
           then return False
           else alloca $ \p -> do 
-                 c_read (fromIntegral wakeup) p 1; return ()
+                 c_read (fromIntegral wakeup) p 1
                  s <- peek p            
                  case s of
                   _ | s == io_MANAGER_WAKEUP -> return False
                   _ | s == io_MANAGER_DIE    -> return True
-                  _ -> withMVar signalHandlerLock $ \_ -> do
-                          handler_tbl <- peek handlers
-                          sp <- peekElemOff handler_tbl (fromIntegral s)
-                          io <- deRefStablePtr sp
-                          forkIO io
-                          return False
+                  _ | s == io_MANAGER_SYNC   -> do
+                       mvars <- readIORef sync
+                       mapM_ (flip putMVar ()) mvars
+                       return False
+                  _ -> do
+                       fp <- mallocForeignPtrBytes (fromIntegral sizeof_siginfo_t)
+                       withForeignPtr fp $ \p_siginfo -> do
+                         r <- c_read (fromIntegral wakeup) (castPtr p_siginfo)
+                                 sizeof_siginfo_t
+                         when (r /= fromIntegral sizeof_siginfo_t) $
+                            error "failed to read siginfo_t"
+                       runHandlers' fp (fromIntegral s)
+                       return False
 
   if exit then return () else do
 
@@ -1106,45 +1054,116 @@ service_loop wakeup readfds writefds ptimeval old_reqs old_delays = do
 
   service_loop wakeup readfds writefds ptimeval reqs' delays'
 
-io_MANAGER_WAKEUP = 0xff :: CChar
-io_MANAGER_DIE    = 0xfe :: CChar
+io_MANAGER_WAKEUP, io_MANAGER_DIE, io_MANAGER_SYNC :: Word8
+io_MANAGER_WAKEUP = 0xff
+io_MANAGER_DIE    = 0xfe
+io_MANAGER_SYNC   = 0xfd
 
+-- | the stick is for poking the IO manager with
 stick :: IORef Fd
 {-# NOINLINE stick #-}
 stick = unsafePerformIO (newIORef 0)
 
+{-# NOINLINE sync #-}
+sync :: IORef [MVar ()]
+sync = unsafePerformIO (newIORef [])
+
+-- waits for the IO manager to drain the pipe
+syncIOManager :: IO ()
+syncIOManager = do
+  m <- newEmptyMVar
+  atomicModifyIORef sync (\old -> (m:old,()))
+  fd <- readIORef stick
+  with io_MANAGER_SYNC $ \pbuf -> do 
+    c_write (fromIntegral fd) pbuf 1; return ()
+  takeMVar m
+
 wakeupIOManager :: IO ()
 wakeupIOManager = do
   fd <- readIORef stick
   with io_MANAGER_WAKEUP $ \pbuf -> do 
     c_write (fromIntegral fd) pbuf 1; return ()
 
--- Lock used to protect concurrent access to signal_handlers.  Symptom of
--- this race condition is #1922, although that bug was on Windows a similar
--- bug also exists on Unix.
-signalHandlerLock :: MVar ()
-signalHandlerLock = unsafePerformIO (newMVar ())
-
-foreign import ccall "&signal_handlers" handlers :: Ptr (Ptr (StablePtr (IO ())))
+-- For the non-threaded RTS
+runHandlers :: Ptr Word8 -> Int -> IO ()
+runHandlers p_info sig = do
+  fp <- mallocForeignPtrBytes (fromIntegral sizeof_siginfo_t)
+  withForeignPtr fp $ \p -> do
+    copyBytes p p_info (fromIntegral sizeof_siginfo_t)
+    free p_info
+  runHandlers' fp (fromIntegral sig)
+
+runHandlers' :: ForeignPtr Word8 -> Signal -> IO ()
+runHandlers' p_info sig = do
+  let int = fromIntegral sig
+  withMVar signal_handlers $ \arr ->
+      if not (inRange (boundsIOArray arr) int)
+         then return ()
+         else do handler <- unsafeReadIOArray arr int
+                 case handler of
+                    Nothing -> return ()
+                    Just (f,_)  -> do forkIO (f p_info); return ()
 
 foreign import ccall "setIOManagerPipe"
   c_setIOManagerPipe :: CInt -> IO ()
 
+foreign import ccall "__hscore_sizeof_siginfo_t"
+  sizeof_siginfo_t :: CSize
+
+type Signal = CInt
+
+maxSig = 64 :: Int
+
+type HandlerFun = ForeignPtr Word8 -> IO ()
+
+-- Lock used to protect concurrent access to signal_handlers.  Symptom of
+-- this race condition is #1922, although that bug was on Windows a similar
+-- bug also exists on Unix.
+{-# NOINLINE signal_handlers #-}
+signal_handlers :: MVar (IOArray Int (Maybe (HandlerFun,Dynamic)))
+signal_handlers = unsafePerformIO $ do
+   arr <- newIOArray (0,maxSig) Nothing
+   m <- newMVar arr
+   block $ do
+     stable_ref <- newStablePtr m
+     let ref = castStablePtrToPtr stable_ref
+     ref2 <- getOrSetSignalHandlerStore ref
+     if ref==ref2
+        then return m
+        else do freeStablePtr stable_ref
+                deRefStablePtr (castPtrToStablePtr ref2)
+
+foreign import ccall unsafe "getOrSetSignalHandlerStore"
+    getOrSetSignalHandlerStore :: Ptr a -> IO (Ptr a)
+
+setHandler :: Signal -> Maybe (HandlerFun,Dynamic) -> IO (Maybe (HandlerFun,Dynamic))
+setHandler sig handler = do
+  let int = fromIntegral sig
+  withMVar signal_handlers $ \arr -> 
+     if not (inRange (boundsIOArray arr) int)
+        then error "GHC.Conc.setHandler: signal out of range"
+        else do old <- unsafeReadIOArray arr int
+                unsafeWriteIOArray arr int handler
+                return old
+
 -- -----------------------------------------------------------------------------
 -- IO requests
 
-buildFdSets maxfd readfds writefds [] = return maxfd
-buildFdSets maxfd readfds writefds (Read fd m : reqs)
+buildFdSets :: Fd -> Ptr CFdSet -> Ptr CFdSet -> [IOReq] -> IO Fd
+buildFdSets maxfd _       _        [] = return maxfd
+buildFdSets maxfd readfds writefds (Read fd _ : reqs)
   | fd >= fD_SETSIZE =  error "buildFdSets: file descriptor out of range"
   | otherwise        =  do
         fdSet fd readfds
         buildFdSets (max maxfd fd) readfds writefds reqs
-buildFdSets maxfd readfds writefds (Write fd m : reqs)
+buildFdSets maxfd readfds writefds (Write fd _ : reqs)
   | fd >= fD_SETSIZE =  error "buildFdSets: file descriptor out of range"
   | otherwise        =  do
         fdSet fd writefds
         buildFdSets (max maxfd fd) readfds writefds reqs
 
+completeRequests :: [IOReq] -> Ptr CFdSet -> Ptr CFdSet -> [IOReq]
+                 -> IO [IOReq]
 completeRequests [] _ _ reqs' = return reqs'
 completeRequests (Read fd m : reqs) readfds writefds reqs' = do
   b <- fdIsSet fd readfds
@@ -1157,9 +1176,10 @@ completeRequests (Write fd m : reqs) readfds writefds reqs' = do
     then do putMVar m (); completeRequests reqs readfds writefds reqs'
     else completeRequests reqs readfds writefds (Write fd m : reqs')
 
+wakeupAll :: [IOReq] -> IO ()
 wakeupAll [] = return ()
-wakeupAll (Read  fd m : reqs) = do putMVar m (); wakeupAll reqs
-wakeupAll (Write fd m : reqs) = do putMVar m (); wakeupAll reqs
+wakeupAll (Read  _ m : reqs) = do putMVar m (); wakeupAll reqs
+wakeupAll (Write _ m : reqs) = do putMVar m (); wakeupAll reqs
 
 waitForReadEvent :: Fd -> IO ()
 waitForReadEvent fd = do
@@ -1182,7 +1202,7 @@ waitForWriteEvent fd = do
 -- and return the smallest delay to wait for.  The queue of pending
 -- delays is kept ordered.
 getDelay :: USecs -> Ptr CTimeVal -> [DelayReq] -> IO ([DelayReq], Ptr CTimeVal)
-getDelay now ptimeval [] = return ([],nullPtr)
+getDelay _   _        [] = return ([],nullPtr)
 getDelay now ptimeval all@(d : rest) 
   = case d of
      Delay time m | now >= time -> do
@@ -1195,7 +1215,7 @@ getDelay now ptimeval all@(d : rest)
         setTimevalTicks ptimeval (delayTime d - now)
         return (all,ptimeval)
 
-newtype CTimeVal = CTimeVal ()
+data CTimeVal
 
 foreign import ccall unsafe "sizeofTimeVal"
   sizeofTimeVal :: Int
@@ -1214,7 +1234,7 @@ foreign import ccall unsafe "setTimevalTicks"
 
 -- ToDo: move to System.Posix.Internals?
 
-newtype CFdSet = CFdSet ()
+data CFdSet
 
 foreign import ccall safe "select"
   c_select :: CInt -> Ptr CFdSet -> Ptr CFdSet -> Ptr CFdSet -> Ptr CTimeVal
@@ -1226,12 +1246,6 @@ foreign import ccall unsafe "hsFD_SETSIZE"
 fD_SETSIZE :: Fd
 fD_SETSIZE = fromIntegral c_fD_SETSIZE
 
-foreign import ccall unsafe "hsFD_CLR"
-  c_fdClr :: CInt -> Ptr CFdSet -> IO ()
-
-fdClr :: Fd -> Ptr CFdSet -> IO ()
-fdClr (Fd fd) fdset = c_fdClr fd fdset
-
 foreign import ccall unsafe "hsFD_ISSET"
   c_fdIsSet :: CInt -> Ptr CFdSet -> IO CInt
 
@@ -1252,4 +1266,44 @@ foreign import ccall unsafe "sizeof_fd_set"
 
 #endif
 
+reportStackOverflow :: IO a
+reportStackOverflow = do callStackOverflowHook; return undefined
+
+reportError :: SomeException -> IO a
+reportError ex = do
+   handler <- getUncaughtExceptionHandler
+   handler ex
+   return undefined
+
+-- SUP: Are the hooks allowed to re-enter Haskell land?  If so, remove
+-- the unsafe below.
+foreign import ccall unsafe "stackOverflow"
+        callStackOverflowHook :: IO ()
+
+{-# NOINLINE uncaughtExceptionHandler #-}
+uncaughtExceptionHandler :: IORef (SomeException -> IO ())
+uncaughtExceptionHandler = unsafePerformIO (newIORef defaultHandler)
+   where
+      defaultHandler :: SomeException -> IO ()
+      defaultHandler se@(SomeException ex) = do
+         (hFlush stdout) `catchAny` (\ _ -> return ())
+         let msg = case cast ex of
+               Just Deadlock -> "no threads to run:  infinite loop or deadlock?"
+               _ -> case cast ex of
+                    Just (ErrorCall s) -> s
+                    _                  -> showsPrec 0 se ""
+         withCString "%s" $ \cfmt ->
+          withCString msg $ \cmsg ->
+            errorBelch cfmt cmsg
+
+-- don't use errorBelch() directly, because we cannot call varargs functions
+-- using the FFI.
+foreign import ccall unsafe "HsBase.h errorBelch2"
+   errorBelch :: CString -> CString -> IO ()
+
+setUncaughtExceptionHandler :: (SomeException -> IO ()) -> IO ()
+setUncaughtExceptionHandler = writeIORef uncaughtExceptionHandler
+
+getUncaughtExceptionHandler :: IO (SomeException -> IO ())
+getUncaughtExceptionHandler = readIORef uncaughtExceptionHandler
 \end{code}