Add support for the IO manager thread on Windows
authorSimon Marlow <simonmar@microsoft.com>
Fri, 1 Dec 2006 15:20:42 +0000 (15:20 +0000)
committerSimon Marlow <simonmar@microsoft.com>
Fri, 1 Dec 2006 15:20:42 +0000 (15:20 +0000)
Fixes #637.  The test program in that report now works for me with
-threaded, but it doesn't work without -threaded (I don't know if
that's new behaviour or not, though).

GHC/Conc.lhs
cbits/Win32Utils.c [new file with mode: 0644]
cbits/runProcess.c
include/HsBase.h

index c506ba4..461a3bf 100644 (file)
@@ -79,13 +79,13 @@ module GHC.Conc
        , asyncWriteBA  -- :: Int -> Int -> Int -> Int -> MutableByteArray# RealWorld -> IO (Int, Int)
 #endif
 
-#ifndef mingw32_HOST_OS
        , ensureIOManagerIsRunning
-#endif
         ) where
 
 import System.Posix.Types
+#ifndef mingw32_HOST_OS
 import System.Posix.Internals
+#endif
 import Foreign
 import Foreign.C
 
@@ -99,7 +99,9 @@ import GHC.Base
 import GHC.IOBase
 import GHC.Num         ( Num(..) )
 import GHC.Real                ( fromIntegral, quot )
+#ifndef mingw32_HOST_OS
 import GHC.Base                ( Int(..) )
+#endif
 import GHC.Exception    ( catchException, Exception(..), AsyncException(..) )
 import GHC.Pack                ( packCString# )
 import GHC.Ptr          ( Ptr(..), plusPtr, FunPtr(..) )
@@ -614,11 +616,7 @@ threadWaitWrite fd
 --
 threadDelay :: Int -> IO ()
 threadDelay time
-#ifndef mingw32_HOST_OS
   | threaded  = waitForDelayEvent time
-#else
-  | threaded  = c_Sleep (fromIntegral (time `quot` 1000))
-#endif
   | otherwise = IO $ \s -> 
        case fromIntegral time of { I# time# ->
        case delay# time# s of { s -> (# s, () #)
@@ -626,20 +624,42 @@ threadDelay time
 
 registerDelay :: Int -> IO (TVar Bool)
 registerDelay usecs 
-#ifndef mingw32_HOST_OS
   | threaded = waitForDelayEventSTM usecs
   | otherwise = error "registerDelay: requires -threaded"
-#else
-  = error "registerDelay: not currently supported on Windows"
-#endif
-
--- On Windows, we just make a safe call to 'Sleep' to implement threadDelay.
-#ifdef mingw32_HOST_OS
-foreign import stdcall safe "Sleep" c_Sleep :: CInt -> IO ()
-#endif
 
 foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
 
+waitForDelayEvent :: Int -> IO ()
+waitForDelayEvent usecs = do
+  m <- newEmptyMVar
+  now <- getTicksOfDay
+  let target = now + usecs `quot` tick_usecs
+  atomicModifyIORef pendingDelays (\xs -> (Delay target m : xs, ()))
+  prodServiceThread
+  takeMVar m
+
+-- Delays for use in STM
+waitForDelayEventSTM :: Int -> IO (TVar Bool)
+waitForDelayEventSTM usecs = do
+   t <- atomically $ newTVar False
+   now <- getTicksOfDay
+   let target = now + usecs `quot` tick_usecs
+   atomicModifyIORef pendingDelays (\xs -> (DelaySTM target t : xs, ()))
+   prodServiceThread
+   return t  
+    
+calculateTarget :: Int -> IO Int
+calculateTarget usecs = do
+    now <- getTicksOfDay
+    let -- Convert usecs to ticks, rounding up as we must wait /at least/
+        -- as long as we are told
+        usecs' = (usecs + tick_usecs - 1) `quot` tick_usecs
+        target = now + 1 -- getTicksOfDay will have rounded down, but
+                         -- again we need to wait for /at least/ as long
+                         -- as we are told, so add 1 to it
+               + usecs'
+    return target
+
 -- ----------------------------------------------------------------------------
 -- Threaded RTS implementation of threadWaitRead, threadWaitWrite, threadDelay
 
@@ -673,16 +693,18 @@ foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
 --       hope we don't need to do any blocking IO between fork & exec.
 
 #ifndef mingw32_HOST_OS
-
 data IOReq
   = Read   {-# UNPACK #-} !Fd {-# UNPACK #-} !(MVar ())
   | Write  {-# UNPACK #-} !Fd {-# UNPACK #-} !(MVar ())
+#endif
 
 data DelayReq
   = Delay    {-# UNPACK #-} !Int {-# UNPACK #-} !(MVar ())
   | DelaySTM {-# UNPACK #-} !Int {-# UNPACK #-} !(TVar Bool)
 
+#ifndef mingw32_HOST_OS
 pendingEvents :: IORef [IOReq]
+#endif
 pendingDelays :: IORef [DelayReq]
        -- could use a strict list or array here
 {-# NOINLINE pendingEvents #-}
@@ -700,6 +722,146 @@ ensureIOManagerIsRunning
   | threaded  = seq pendingEvents $ return ()
   | otherwise = return ()
 
+insertDelay :: DelayReq -> [DelayReq] -> [DelayReq]
+insertDelay d [] = [d]
+insertDelay d1 ds@(d2 : rest)
+  | delayTime d1 <= delayTime d2 = d1 : ds
+  | otherwise                    = d2 : insertDelay d1 rest
+
+delayTime (Delay t _) = t
+delayTime (DelaySTM t _) = t
+
+type Ticks = Int
+tick_freq  = 50 :: Ticks  -- accuracy of threadDelay (ticks per sec)
+tick_usecs = 1000000 `quot` tick_freq :: Int
+tick_msecs = 1000 `quot` tick_freq :: Int
+
+-- 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 "getTicksOfDay" 
+  getTicksOfDay :: IO Ticks
+
+#ifdef mingw32_HOST_OS
+-- ----------------------------------------------------------------------------
+-- Windows IO manager thread
+
+startIOManagerThread :: IO ()
+startIOManagerThread = do
+  wakeup <- c_getIOManagerEvent
+  forkIO $ service_loop wakeup []
+  return ()
+
+service_loop :: HANDLE          -- read end of pipe
+             -> [DelayReq]      -- current delay requests
+             -> IO ()
+
+service_loop wakeup old_delays = do
+  -- pick up new delay requests
+  new_delays <- atomicModifyIORef pendingDelays (\a -> ([],a))
+  let  delays = foldr insertDelay old_delays new_delays
+
+  now <- getTicksOfDay
+  (delays', timeout) <- getDelay now delays
+
+  r <- c_WaitForSingleObject wakeup timeout
+  case r of
+    0xffffffff -> do c_maperrno; throwErrno "service_loop"
+    0 -> do
+        r <- c_readIOManagerEvent
+        exit <- 
+             case r of
+               _ | r == io_MANAGER_WAKEUP -> return False
+               _ | r == io_MANAGER_DIE    -> return True
+                0 -> return False -- spurious wakeup
+               r -> do start_console_handler (r `shiftR` 1); return False
+        if exit
+          then return ()
+          else service_cont wakeup delays'
+
+    _other -> service_cont wakeup delays' -- probably timeout        
+
+service_cont wakeup delays = do
+  takeMVar prodding
+  putMVar prodding False
+  service_loop wakeup delays
+
+-- must agree with rts/win32/ThrIOManager.c
+io_MANAGER_WAKEUP = 0xffffffff :: Word32
+io_MANAGER_DIE    = 0xfffffffe :: Word32
+
+start_console_handler :: Word32 -> IO ()
+start_console_handler r = do                   
+  stableptr <- peek console_handler
+  forkIO $ do io <- deRefStablePtr stableptr; io (fromIntegral r)
+  return ()
+
+foreign import ccall "&console_handler" 
+   console_handler :: Ptr (StablePtr (CInt -> IO ()))
+
+stick :: IORef HANDLE
+{-# NOINLINE stick #-}
+stick = unsafePerformIO (newIORef nullPtr)
+
+prodding :: MVar Bool
+{-# NOINLINE prodding #-}
+prodding = unsafePerformIO (newMVar False)
+
+prodServiceThread :: IO ()
+prodServiceThread = do
+  b <- takeMVar prodding
+  if (not b) 
+    then do hdl <- readIORef stick
+            c_sendIOManagerEvent io_MANAGER_WAKEUP
+    else return ()
+  putMVar prodding True
+
+-- 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 :: Ticks -> [DelayReq] -> IO ([DelayReq], DWORD)
+getDelay now [] = return ([], iNFINITE)
+getDelay now all@(d : rest) 
+  = case d of
+     Delay time m | now >= time -> do
+       putMVar m ()
+       getDelay now rest
+     DelaySTM time t | now >= time -> do
+       atomically $ writeTVar t True
+       getDelay now rest
+     _otherwise ->
+        return (all, (fromIntegral (delayTime d - now) * 
+                        fromIntegral tick_msecs))
+                        -- delay is in millisecs for WaitForSingleObject
+
+-- ToDo: this just duplicates part of System.Win32.Types, which isn't
+-- available yet.  We should move some Win32 functionality down here,
+-- maybe as part of the grand reorganisation of the base package...
+type HANDLE       = Ptr ()
+type DWORD        = Word32
+
+iNFINITE = 0xFFFFFFFF :: DWORD -- urgh
+
+foreign import ccall unsafe "getIOManagerEvent" -- in the RTS (ThrIOManager.c)
+  c_getIOManagerEvent :: IO HANDLE
+
+foreign import ccall unsafe "readIOManagerEvent" -- in the RTS (ThrIOManager.c)
+  c_readIOManagerEvent :: IO Word32
+
+foreign import ccall unsafe "sendIOManagerEvent" -- in the RTS (ThrIOManager.c)
+  c_sendIOManagerEvent :: Word32 -> IO ()
+
+foreign import ccall unsafe "maperrno"             -- in runProcess.c
+   c_maperrno :: IO ()
+
+foreign import stdcall "WaitForSingleObject"
+   c_WaitForSingleObject :: HANDLE -> DWORD -> IO DWORD
+
+#else
+-- ----------------------------------------------------------------------------
+-- Unix IO manager thread, using select()
+
 startIOManagerThread :: IO ()
 startIOManagerThread = do
         allocaArray 2 $ \fds -> do
@@ -793,13 +955,13 @@ 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
+
 stick :: IORef Fd
 {-# NOINLINE stick #-}
 stick = unsafePerformIO (newIORef 0)
 
-io_MANAGER_WAKEUP = 0xff :: CChar
-io_MANAGER_DIE    = 0xfe :: CChar
-
 prodding :: MVar Bool
 {-# NOINLINE prodding #-}
 prodding = unsafePerformIO (newMVar False)
@@ -864,42 +1026,9 @@ waitForWriteEvent fd = do
   prodServiceThread
   takeMVar m
 
--- 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
-
 -- -----------------------------------------------------------------------------
 -- Delays
 
-waitForDelayEvent :: Int -> IO ()
-waitForDelayEvent usecs = do
-  m <- newEmptyMVar
-  target <- calculateTarget usecs
-  atomicModifyIORef pendingDelays (\xs -> (Delay target m : xs, ()))
-  prodServiceThread
-  takeMVar m
-
--- Delays for use in STM
-waitForDelayEventSTM :: Int -> IO (TVar Bool)
-waitForDelayEventSTM usecs = do
-   t <- atomically $ newTVar False
-   target <- calculateTarget usecs
-   atomicModifyIORef pendingDelays (\xs -> (DelaySTM target t : xs, ()))
-   prodServiceThread
-   return t  
-    
-calculateTarget :: Int -> IO Int
-calculateTarget usecs = do
-    now <- getTicksOfDay
-    let -- Convert usecs to ticks, rounding up as we must wait /at least/
-        -- as long as we are told
-        usecs' = (usecs + tick_usecs - 1) `quot` tick_usecs
-        target = now + 1 -- getTicksOfDay will have rounded down, but
-                         -- again we need to wait for /at least/ as long
-                         -- as we are told, so add 1 to it
-               + usecs'
-    return target
-
 -- 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.
@@ -917,30 +1046,20 @@ getDelay now ptimeval all@(d : rest)
        setTimevalTicks ptimeval (delayTime d - now)
        return (all,ptimeval)
 
-insertDelay :: DelayReq -> [DelayReq] -> [DelayReq]
-insertDelay d [] = [d]
-insertDelay d1 ds@(d2 : rest)
-  | delayTime d1 <= delayTime d2 = d1 : ds
-  | otherwise                    = d2 : insertDelay d1 rest
-
-delayTime (Delay t _) = t
-delayTime (DelaySTM t _) = t
-
-type Ticks = Int
-tick_freq  = 50 :: Ticks  -- accuracy of threadDelay (ticks per sec)
-tick_usecs = 1000000 `quot` tick_freq :: Int
-
 newtype CTimeVal = CTimeVal ()
 
 foreign import ccall unsafe "sizeofTimeVal"
   sizeofTimeVal :: Int
 
-foreign import ccall unsafe "getTicksOfDay" 
-  getTicksOfDay :: IO Ticks
-
 foreign import ccall unsafe "setTimevalTicks" 
   setTimevalTicks :: Ptr CTimeVal -> Ticks -> IO ()
 
+{- 
+  On Win32 we're going to have a single Pipe, and a
+  waitForSingleObject with the delay time.  For signals, we send a
+  byte down the pipe just like on Unix.
+-}
+
 -- ----------------------------------------------------------------------------
 -- select() interface
 
@@ -971,4 +1090,5 @@ foreign import ccall unsafe "sizeof_fd_set"
   sizeofFdSet :: Int
 
 #endif
+
 \end{code}
diff --git a/cbits/Win32Utils.c b/cbits/Win32Utils.c
new file mode 100644 (file)
index 0000000..dca270a
--- /dev/null
@@ -0,0 +1,121 @@
+/* ----------------------------------------------------------------------------\r
+   (c) The University of Glasgow 2006\r
+   \r
+   Useful Win32 bits\r
+   ------------------------------------------------------------------------- */\r
+\r
+#include "HsBase.h"\r
+\r
+/* This is the error table that defines the mapping between OS error\r
+   codes and errno values */\r
+\r
+struct errentry {\r
+        unsigned long oscode;           /* OS return value */\r
+        int errnocode;  /* System V error code */\r
+};\r
+\r
+static struct errentry errtable[] = {\r
+        {  ERROR_INVALID_FUNCTION,       EINVAL    },  /* 1 */\r
+        {  ERROR_FILE_NOT_FOUND,         ENOENT    },  /* 2 */\r
+        {  ERROR_PATH_NOT_FOUND,         ENOENT    },  /* 3 */\r
+        {  ERROR_TOO_MANY_OPEN_FILES,    EMFILE    },  /* 4 */\r
+        {  ERROR_ACCESS_DENIED,          EACCES    },  /* 5 */\r
+        {  ERROR_INVALID_HANDLE,         EBADF     },  /* 6 */\r
+        {  ERROR_ARENA_TRASHED,          ENOMEM    },  /* 7 */\r
+        {  ERROR_NOT_ENOUGH_MEMORY,      ENOMEM    },  /* 8 */\r
+        {  ERROR_INVALID_BLOCK,          ENOMEM    },  /* 9 */\r
+        {  ERROR_BAD_ENVIRONMENT,        E2BIG     },  /* 10 */\r
+        {  ERROR_BAD_FORMAT,             ENOEXEC   },  /* 11 */\r
+        {  ERROR_INVALID_ACCESS,         EINVAL    },  /* 12 */\r
+        {  ERROR_INVALID_DATA,           EINVAL    },  /* 13 */\r
+        {  ERROR_INVALID_DRIVE,          ENOENT    },  /* 15 */\r
+        {  ERROR_CURRENT_DIRECTORY,      EACCES    },  /* 16 */\r
+        {  ERROR_NOT_SAME_DEVICE,        EXDEV     },  /* 17 */\r
+        {  ERROR_NO_MORE_FILES,          ENOENT    },  /* 18 */\r
+        {  ERROR_LOCK_VIOLATION,         EACCES    },  /* 33 */\r
+        {  ERROR_BAD_NETPATH,            ENOENT    },  /* 53 */\r
+        {  ERROR_NETWORK_ACCESS_DENIED,  EACCES    },  /* 65 */\r
+        {  ERROR_BAD_NET_NAME,           ENOENT    },  /* 67 */\r
+        {  ERROR_FILE_EXISTS,            EEXIST    },  /* 80 */\r
+        {  ERROR_CANNOT_MAKE,            EACCES    },  /* 82 */\r
+        {  ERROR_FAIL_I24,               EACCES    },  /* 83 */\r
+        {  ERROR_INVALID_PARAMETER,      EINVAL    },  /* 87 */\r
+        {  ERROR_NO_PROC_SLOTS,          EAGAIN    },  /* 89 */\r
+        {  ERROR_DRIVE_LOCKED,           EACCES    },  /* 108 */\r
+        {  ERROR_BROKEN_PIPE,            EPIPE     },  /* 109 */\r
+        {  ERROR_DISK_FULL,              ENOSPC    },  /* 112 */\r
+        {  ERROR_INVALID_TARGET_HANDLE,  EBADF     },  /* 114 */\r
+        {  ERROR_INVALID_HANDLE,         EINVAL    },  /* 124 */\r
+        {  ERROR_WAIT_NO_CHILDREN,       ECHILD    },  /* 128 */\r
+        {  ERROR_CHILD_NOT_COMPLETE,     ECHILD    },  /* 129 */\r
+        {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF     },  /* 130 */\r
+        {  ERROR_NEGATIVE_SEEK,          EINVAL    },  /* 131 */\r
+        {  ERROR_SEEK_ON_DEVICE,         EACCES    },  /* 132 */\r
+        {  ERROR_DIR_NOT_EMPTY,          ENOTEMPTY },  /* 145 */\r
+        {  ERROR_NOT_LOCKED,             EACCES    },  /* 158 */\r
+        {  ERROR_BAD_PATHNAME,           ENOENT    },  /* 161 */\r
+        {  ERROR_MAX_THRDS_REACHED,      EAGAIN    },  /* 164 */\r
+        {  ERROR_LOCK_FAILED,            EACCES    },  /* 167 */\r
+        {  ERROR_ALREADY_EXISTS,         EEXIST    },  /* 183 */\r
+        {  ERROR_FILENAME_EXCED_RANGE,   ENOENT    },  /* 206 */\r
+        {  ERROR_NESTING_NOT_ALLOWED,    EAGAIN    },  /* 215 */\r
+        {  ERROR_NOT_ENOUGH_QUOTA,       ENOMEM    }    /* 1816 */\r
+};\r
+\r
+/* size of the table */\r
+#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))\r
+\r
+/* The following two constants must be the minimum and maximum\r
+   values in the (contiguous) range of Exec Failure errors. */\r
+#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG\r
+#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN\r
+\r
+/* These are the low and high value in the range of errors that are\r
+   access violations */\r
+#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT\r
+#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED\r
+\r
+void maperrno (void)\r
+{\r
+       int i;\r
+       DWORD dwErrorCode;\r
+\r
+       dwErrorCode = GetLastError();\r
+\r
+       /* check the table for the OS error code */\r
+       for (i = 0; i < ERRTABLESIZE; ++i)\r
+       {\r
+               if (dwErrorCode == errtable[i].oscode)\r
+               {\r
+                       errno = errtable[i].errnocode;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       /* The error code wasn't in the table.  We check for a range of */\r
+       /* EACCES errors or exec failure errors (ENOEXEC).  Otherwise   */\r
+       /* EINVAL is returned.                                          */\r
+\r
+       if (dwErrorCode >= MIN_EACCES_RANGE && dwErrorCode <= MAX_EACCES_RANGE)\r
+               errno = EACCES;\r
+       else\r
+               if (dwErrorCode >= MIN_EXEC_ERROR && dwErrorCode <= MAX_EXEC_ERROR)\r
+                       errno = ENOEXEC;\r
+               else\r
+                       errno = EINVAL;\r
+}\r
+\r
+#define TICKS_PER_SECOND 50\r
+// must match GHC.Conc.tick_freq\r
+\r
+HsInt getTicksOfDay(void)\r
+{\r
+    HsInt64 t;\r
+    FILETIME ft;\r
+    GetSystemTimeAsFileTime(&ft);\r
+    t = ((HsInt64)ft.dwHighDateTime << 32) | ft.dwLowDateTime;\r
+    t = (t * TICKS_PER_SECOND) / 10000000LL;\r
+      /* FILETIMES are in units of 100ns */\r
+    return (HsInt)t;\r
+}\r
+\r
index 39597b7..93aa8c4 100644 (file)
@@ -233,105 +233,6 @@ int waitForProcess (ProcHandle handle)
 
 /* -------------------- WINDOWS VERSION --------------------- */
 
-/* This is the error table that defines the mapping between OS error
-   codes and errno values */
-
-struct errentry {
-        unsigned long oscode;           /* OS return value */
-        int errnocode;  /* System V error code */
-};
-
-static struct errentry errtable[] = {
-        {  ERROR_INVALID_FUNCTION,       EINVAL    },  /* 1 */
-        {  ERROR_FILE_NOT_FOUND,         ENOENT    },  /* 2 */
-        {  ERROR_PATH_NOT_FOUND,         ENOENT    },  /* 3 */
-        {  ERROR_TOO_MANY_OPEN_FILES,    EMFILE    },  /* 4 */
-        {  ERROR_ACCESS_DENIED,          EACCES    },  /* 5 */
-        {  ERROR_INVALID_HANDLE,         EBADF     },  /* 6 */
-        {  ERROR_ARENA_TRASHED,          ENOMEM    },  /* 7 */
-        {  ERROR_NOT_ENOUGH_MEMORY,      ENOMEM    },  /* 8 */
-        {  ERROR_INVALID_BLOCK,          ENOMEM    },  /* 9 */
-        {  ERROR_BAD_ENVIRONMENT,        E2BIG     },  /* 10 */
-        {  ERROR_BAD_FORMAT,             ENOEXEC   },  /* 11 */
-        {  ERROR_INVALID_ACCESS,         EINVAL    },  /* 12 */
-        {  ERROR_INVALID_DATA,           EINVAL    },  /* 13 */
-        {  ERROR_INVALID_DRIVE,          ENOENT    },  /* 15 */
-        {  ERROR_CURRENT_DIRECTORY,      EACCES    },  /* 16 */
-        {  ERROR_NOT_SAME_DEVICE,        EXDEV     },  /* 17 */
-        {  ERROR_NO_MORE_FILES,          ENOENT    },  /* 18 */
-        {  ERROR_LOCK_VIOLATION,         EACCES    },  /* 33 */
-        {  ERROR_BAD_NETPATH,            ENOENT    },  /* 53 */
-        {  ERROR_NETWORK_ACCESS_DENIED,  EACCES    },  /* 65 */
-        {  ERROR_BAD_NET_NAME,           ENOENT    },  /* 67 */
-        {  ERROR_FILE_EXISTS,            EEXIST    },  /* 80 */
-        {  ERROR_CANNOT_MAKE,            EACCES    },  /* 82 */
-        {  ERROR_FAIL_I24,               EACCES    },  /* 83 */
-        {  ERROR_INVALID_PARAMETER,      EINVAL    },  /* 87 */
-        {  ERROR_NO_PROC_SLOTS,          EAGAIN    },  /* 89 */
-        {  ERROR_DRIVE_LOCKED,           EACCES    },  /* 108 */
-        {  ERROR_BROKEN_PIPE,            EPIPE     },  /* 109 */
-        {  ERROR_DISK_FULL,              ENOSPC    },  /* 112 */
-        {  ERROR_INVALID_TARGET_HANDLE,  EBADF     },  /* 114 */
-        {  ERROR_INVALID_HANDLE,         EINVAL    },  /* 124 */
-        {  ERROR_WAIT_NO_CHILDREN,       ECHILD    },  /* 128 */
-        {  ERROR_CHILD_NOT_COMPLETE,     ECHILD    },  /* 129 */
-        {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF     },  /* 130 */
-        {  ERROR_NEGATIVE_SEEK,          EINVAL    },  /* 131 */
-        {  ERROR_SEEK_ON_DEVICE,         EACCES    },  /* 132 */
-        {  ERROR_DIR_NOT_EMPTY,          ENOTEMPTY },  /* 145 */
-        {  ERROR_NOT_LOCKED,             EACCES    },  /* 158 */
-        {  ERROR_BAD_PATHNAME,           ENOENT    },  /* 161 */
-        {  ERROR_MAX_THRDS_REACHED,      EAGAIN    },  /* 164 */
-        {  ERROR_LOCK_FAILED,            EACCES    },  /* 167 */
-        {  ERROR_ALREADY_EXISTS,         EEXIST    },  /* 183 */
-        {  ERROR_FILENAME_EXCED_RANGE,   ENOENT    },  /* 206 */
-        {  ERROR_NESTING_NOT_ALLOWED,    EAGAIN    },  /* 215 */
-        {  ERROR_NOT_ENOUGH_QUOTA,       ENOMEM    }    /* 1816 */
-};
-
-/* size of the table */
-#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
-
-/* The following two constants must be the minimum and maximum
-   values in the (contiguous) range of Exec Failure errors. */
-#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
-#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
-
-/* These are the low and high value in the range of errors that are
-   access violations */
-#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
-#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
-
-static void maperrno (void)
-{
-       int i;
-       DWORD dwErrorCode;
-
-       dwErrorCode = GetLastError();
-
-       /* check the table for the OS error code */
-       for (i = 0; i < ERRTABLESIZE; ++i)
-       {
-               if (dwErrorCode == errtable[i].oscode)
-               {
-                       errno = errtable[i].errnocode;
-                       return;
-               }
-       }
-
-       /* The error code wasn't in the table.  We check for a range of */
-       /* EACCES errors or exec failure errors (ENOEXEC).  Otherwise   */
-       /* EINVAL is returned.                                          */
-
-       if (dwErrorCode >= MIN_EACCES_RANGE && dwErrorCode <= MAX_EACCES_RANGE)
-               errno = EACCES;
-       else
-               if (dwErrorCode >= MIN_EXEC_ERROR && dwErrorCode <= MAX_EXEC_ERROR)
-                       errno = ENOEXEC;
-               else
-                       errno = EINVAL;
-}
-
 /*
  * Function: mkAnonPipe
  *
@@ -413,7 +314,6 @@ runProcess (char *cmd, char *workingDirectory, void *environment,
        STARTUPINFO sInfo;
        PROCESS_INFORMATION pInfo;
        DWORD flags;
-       char buffer[256];
 
        ZeroMemory(&sInfo, sizeof(sInfo));
        sInfo.cb = sizeof(sInfo);       
index aa1a7fb..fe8c0cd 100644 (file)
 #include "runProcess.h"
 
 #if defined(__MINGW32__)
+/* in Win32Utils.c */
+extern void maperrno (void);
+extern HsInt getTicksOfDay(void);
+#endif
+
+#if defined(__MINGW32__)
 #include <io.h>
 #include <fcntl.h>
 #include "timeUtils.h"