For nhc98 only, use hsc2hs to determine System.Posix.Types.
[haskell-directory.git] / System / Process.hs
index f30967a..91a9359 100644 (file)
@@ -167,7 +167,8 @@ runInteractiveProcess1 fun cmd args mb_cwd mb_env = do
      hndStdInput  <- fdToHandle pfdStdInput  WriteMode
      hndStdOutput <- fdToHandle pfdStdOutput ReadMode
      hndStdError  <- fdToHandle pfdStdError  ReadMode
-     return (hndStdInput, hndStdOutput, hndStdError, ProcessHandle proc_handle)
+     ph <- mkProcessHandle proc_handle
+     return (hndStdInput, hndStdOutput, hndStdError, ph)
 
 foreign import ccall unsafe "runInteractiveProcess" 
   c_runInteractiveProcess
@@ -201,8 +202,8 @@ runInteractiveProcess1 fun cmd args workDir env extra_cmdline
        hndStdInput  <- fdToHandle pfdStdInput  WriteMode
        hndStdOutput <- fdToHandle pfdStdOutput ReadMode
        hndStdError  <- fdToHandle pfdStdError  ReadMode
-       return (hndStdInput, hndStdOutput, hndStdError, 
-               ProcessHandle proc_handle)
+       ph <- mkProcessHandle proc_handle
+       return (hndStdInput, hndStdOutput, hndStdError, ph)
 
 foreign import ccall unsafe "runInteractiveProcess" 
   c_runInteractiveProcess
@@ -228,18 +229,31 @@ fdToHandle pfd mode = do
 
 {- | Waits for the specified process to terminate, and returns its exit code.
    
-     GHC Note: in order to call waitForProcess without blocking all the
+     GHC Note: in order to call @waitForProcess@ without blocking all the
      other threads in the system, you must compile the program with
      @-threaded@.
 -}
 waitForProcess
   :: ProcessHandle
   -> IO ExitCode
-waitForProcess (ProcessHandle handle) = do
-  code <- throwErrnoIfMinus1 "waitForProcess" (c_waitForProcess handle)
-  if (code == 0) 
-    then return ExitSuccess
-    else return (ExitFailure (fromIntegral code))
+waitForProcess ph = do
+  p_ <- withProcessHandle ph $ \p_ -> return (p_,p_)
+  case p_ of
+    ClosedHandle e -> return e
+    OpenHandle h  -> do
+       -- don't hold the MVar while we call c_waitForProcess...
+       -- (XXX but there's a small race window here during which another
+       -- thread could close the handle or call waitForProcess)
+       code <- throwErrnoIfMinus1 "waitForProcess" (c_waitForProcess h)
+       withProcessHandle ph $ \p_ ->
+         case p_ of
+           ClosedHandle e -> return (p_,e)
+           OpenHandle ph  -> do
+             closePHANDLE ph
+             let e = if (code == 0)
+                  then ExitSuccess
+                  else (ExitFailure (fromIntegral code))
+             return (ClosedHandle e, e)
 
 -- ----------------------------------------------------------------------------
 -- terminateProcess
@@ -253,25 +267,43 @@ waitForProcess (ProcessHandle handle) = do
 -- On Windows systems, the Win32 @TerminateProcess@ function is called, passing
 -- an exit code of 1.
 terminateProcess :: ProcessHandle -> IO ()
-terminateProcess (ProcessHandle pid) =
-  throwErrnoIfMinus1_ "terminateProcess" (c_terminateProcess pid)
+terminateProcess ph = do
+  withProcessHandle_ ph $ \p_ ->
+    case p_ of 
+      ClosedHandle _ -> return p_
+      OpenHandle h -> do
+       throwErrnoIfMinus1_ "terminateProcess" $ c_terminateProcess h
+       return p_
+       -- does not close the handle, we might want to try terminating it
+       -- again, or get its exit code.
 
 -- ----------------------------------------------------------------------------
 -- getProcessExitCode
 
-{- | Verifies whether the process is completed and if it is then returns the exit code.
-   If the process is still running the function returns Nothing
+{- | 
+This is a non-blocking version of 'waitForProcess'.  If the process is
+still running, 'Nothing' is returned.  If the process has exited, then
+@'Just' e@ is returned where @e@ is the exit code of the process.
+Subsequent calls to @getProcessExitStatus@ always return @'Just'
+'ExitSuccess'@, regardless of what the original exit code was.
 -}
 getProcessExitCode :: ProcessHandle -> IO (Maybe ExitCode)
-getProcessExitCode (ProcessHandle handle) =
-  alloca $ \pExitCode -> do
-    res <- throwErrnoIfMinus1 "getProcessExitCode" (c_getProcessExitCode handle pExitCode)
-    code <- peek pExitCode
-    if res == 0
-      then return Nothing
-      else if code == 0
-             then return (Just ExitSuccess)
-             else return (Just (ExitFailure (fromIntegral code)))
+getProcessExitCode ph = do
+  withProcessHandle ph $ \p_ ->
+    case p_ of
+      ClosedHandle e -> return (p_, Just e)
+      OpenHandle h ->
+       alloca $ \pExitCode -> do
+           res <- throwErrnoIfMinus1 "getProcessExitCode" $
+                       c_getProcessExitCode h pExitCode
+           code <- peek pExitCode
+           if res == 0
+             then return (p_, Nothing)
+             else do
+                  closePHANDLE h
+                  let e  | code == 0 = ExitSuccess
+                         | otherwise = ExitFailure (fromIntegral code)
+                  return (ClosedHandle e, Just e)
 
 -- ----------------------------------------------------------------------------
 -- Interface to C bits