Rewrite of signal-handling (base patch; see also ghc and unix patches)
[ghc-base.git] / GHC / Conc.lhs
index a584d31..796e4c7 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 ()
 
@@ -71,6 +73,7 @@ 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
 
@@ -85,16 +88,20 @@ module GHC.Conc
 #endif
 
 #ifndef mingw32_HOST_OS
-        , signalHandlerLock
+        , Signal, HandlerFun, setHandler, runHandlers
 #endif
 
         , ensureIOManagerIsRunning
+        , syncIOManager
 
 #ifdef mingw32_HOST_OS
         , ConsoleEvent(..)
         , win32ConsoleHandler
         , toWin32ConsoleEvent
 #endif
+        , setUncaughtExceptionHandler      -- :: (Exception -> IO ()) -> IO ()
+        , getUncaughtExceptionHandler      -- :: IO (Exception -> IO ())
+
         , reportError, reportStackOverflow
         ) where
 
@@ -105,14 +112,19 @@ import System.Posix.Internals
 import Foreign
 import Foreign.C
 
+import Data.Dynamic
 import Data.Maybe
+import Control.Monad
 
 import GHC.Base
+import {-# SOURCE #-} GHC.Handle
 import GHC.IOBase
 import GHC.Num          ( Num(..) )
-import GHC.Real         ( fromIntegral, div )
-#ifndef mingw32_HOST_OS
-import GHC.Base         ( Int(..) )
+import GHC.Real         ( fromIntegral )
+import GHC.Arr          ( inRange )
+#ifdef mingw32_HOST_OS
+import GHC.Real         ( div )
+import GHC.Ptr          ( plusPtr, FunPtr(..) )
 #endif
 #ifdef mingw32_HOST_OS
 import GHC.Read         ( Read )
@@ -120,12 +132,11 @@ import GHC.Enum         ( Enum )
 #endif
 import GHC.Exception    ( SomeException(..), throw )
 import GHC.Pack         ( packCString# )
-import GHC.Ptr          ( Ptr(..), plusPtr, FunPtr(..) )
+import GHC.Ptr          ( Ptr(..) )
 import GHC.STRef
 import GHC.Show         ( Show(..), showString )
 import Data.Typeable
 import GHC.Err
-import Control.Exception hiding (throwTo)
 
 infixr 0 `par`, `pseq`
 \end{code}
@@ -198,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
 
@@ -220,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
 
@@ -233,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
 
@@ -259,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).
 
@@ -285,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
@@ -349,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
@@ -436,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
@@ -545,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#
@@ -631,8 +667,8 @@ putMVar (MVar mvar#) x = IO $ \ s# ->
 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
+        (# 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
@@ -658,16 +694,7 @@ isEmptyMVar (MVar mv#) = IO $ \ s# ->
 -- "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
-    a <- takeMVar m
-    b <- catchAny (unblock (io a))
-            (\e -> do putMVar m a; throw e)
-    putMVar m a
-    return b
+  IO $ \s -> case mkWeak# m () finalizer s of { (# s1, _ #) -> (# s1, () #) }
 \end{code}
 
 
@@ -687,19 +714,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:
@@ -727,7 +754,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
@@ -739,7 +766,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
@@ -754,7 +781,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', () #)
         }}
 
 
@@ -907,26 +934,28 @@ 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))
   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
@@ -945,6 +974,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
@@ -957,19 +987,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
@@ -990,7 +1022,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
@@ -1017,6 +1050,8 @@ startIOManagerThread = do
         throwErrnoIfMinus1 "startIOManagerThread" (c_pipe fds)
         rd_end <- peekElemOff fds 0
         wr_end <- peekElemOff fds 1
+        setNonBlockingFD wr_end -- writes happen in a signal handler, we
+                                -- don't want them to block.
         writeIORef stick (fromIntegral wr_end)
         c_setIOManagerPipe wr_end
         forkIO $ do
@@ -1042,7 +1077,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
@@ -1075,7 +1110,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
@@ -1084,17 +1119,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
 
@@ -1105,45 +1147,105 @@ 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 :: CChar
+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
+   newMVar arr
+
+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
@@ -1156,9 +1258,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
@@ -1181,7 +1284,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
@@ -1194,7 +1297,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
@@ -1213,7 +1316,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
@@ -1225,12 +1328,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
 
@@ -1264,4 +1361,41 @@ reportError ex = do
 -- 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
+
+
+withMVar :: MVar a -> (a -> IO b) -> IO b
+withMVar m io = 
+  block $ do
+    a <- takeMVar m
+    b <- catchAny (unblock (io a))
+            (\e -> do putMVar m a; throw e)
+    putMVar m a
+    return b
 \end{code}