, 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
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(..) )
--
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, () #)
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
-- 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 #-}
| 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
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)
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.
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
sizeofFdSet :: Int
#endif
+
\end{code}
--- /dev/null
+/* ----------------------------------------------------------------------------\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
/* -------------------- 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
*
STARTUPINFO sInfo;
PROCESS_INFORMATION pInfo;
DWORD flags;
- char buffer[256];
ZeroMemory(&sInfo, sizeof(sInfo));
sInfo.cb = sizeof(sInfo);
#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"