rawSystem unpredictable with signals
Hi, I'm using System.Cmd.rawSystem in a program and have noticed a mysterious flaw: When I hit Ctrl-C while the child process is running, sometimes: 1) rawSystem returns ExitSuccess or 2) rawSystem raises an IOError saying the child terminated with a signal I am totally at a loss as to explain this difference in behavior. I would prefer it to choose option #2 always. However, even that is not quite ideal. It seems like it would be much better if ExitCode would be replaced with System.Posix.Process.ProcessStatus, which can indicate an Exited (with exit code), Terminated by signal, or Stopped by signal status. Getting an exception when the child was terminated by a signal, but not when it exits with a failure, seems inconsistent. I will probably write my own rawSystem replacement, that returns a ProcessStatus, and put it in MissingH.Cmd. -- John
John Goerzen wrote:
I'm using System.Cmd.rawSystem in a program and have noticed a mysterious flaw:
When I hit Ctrl-C while the child process is running, sometimes:
1) rawSystem returns ExitSuccess
or
2) rawSystem raises an IOError saying the child terminated with a signal
I am totally at a loss as to explain this difference in behavior. I would prefer it to choose option #2 always.
Would you like to submit a bug report on this, I'll try to get to it before GHC 6.6.
However, even that is not quite ideal. It seems like it would be much better if ExitCode would be replaced with System.Posix.Process.ProcessStatus, which can indicate an Exited (with exit code), Terminated by signal, or Stopped by signal status. Getting an exception when the child was terminated by a signal, but not when it exits with a failure, seems inconsistent.
The problem with this is that not all platforms are POSIX, and System.Process is trying to be platform-independent. Having a more elaborate version of System.Process under System.Posix.Process would be an option, though. You can reuse some of the bits from System.Process.Internals. Cheers, Simon
On Thu, Jul 06, 2006 at 11:42:13AM +0100, Simon Marlow wrote:
Would you like to submit a bug report on this, I'll try to get to it before GHC 6.6.
I can also send you the code that works for me on my own reimplementation.
The problem with this is that not all platforms are POSIX, and System.Process is trying to be platform-independent. Having a more elaborate version of System.Process under System.Posix.Process would be an option, though. You can reuse some of the bits from System.Process.Internals.
I believe that isn't actually necessary (at least, not directly). My code in MissingH is: {- | Invokes the specified command in a subprocess, waiting for the result. Return the result status. Never raises an exception. Only available on POSIX platforms. Like system(3), this command ignores SIGINT and SIGQUIT and blocks SIGCHLD during its execution. Logs as MissingH.Cmd.posixRawSystem -} posixRawSystem :: FilePath -> [String] -> IO ProcessStatus posixRawSystem program args = do debugM (logbase ++ ".posixRawSystem") ("Running: " ++ program ++ " " ++ (show args)) oldint <- installHandler sigINT Ignore Nothing oldquit <- installHandler sigQUIT Ignore Nothing let sigset = addSignal sigCHLD emptySignalSet oldset <- getSignalMask blockSignals sigset childpid <- forkProcess (childaction oldint oldquit oldset) mps <- getProcessStatus True False childpid restoresignals oldint oldquit oldset let retval = case mps of Just x -> x Nothing -> error "Nothing returned from getProcessStatus" debugM (logbase ++ ".posixRawSystem") (program ++ ": exited with " ++ show retval) return retval where childaction oldint oldquit oldset = do restoresignals oldint oldquit oldset executeFile program True args Nothing restoresignals oldint oldquit oldset = do installHandler sigINT oldint Nothing installHandler sigQUIT oldquit Nothing setSignalMask oldset
* John Goerzen:
where childaction oldint oldquit oldset = do restoresignals oldint oldquit oldset executeFile program True args Nothing restoresignals oldint oldquit oldset = do installHandler sigINT oldint Nothing installHandler sigQUIT oldquit Nothing setSignalMask oldset
Does this work reliably with threading? Signal handlers are a process-global resource. Or is installHandler performing some magic to make signal handlers thread-specific?
On Sun, Jul 09, 2006 at 11:53:18AM +0200, Florian Weimer wrote:
* John Goerzen:
do installHandler sigINT oldint Nothing installHandler sigQUIT oldquit Nothing setSignalMask oldset
Does this work reliably with threading? Signal handlers are a process-global resource. Or is installHandler performing some magic to make signal handlers thread-specific?
I haven't tested it with threading yet. From looking at the source for the existing rawSystme, I suspect it will work exactly as well (or poorly) as that one.
John Goerzen wrote:
When I hit Ctrl-C while the child process is running, sometimes:
1) rawSystem returns ExitSuccess
or
2) rawSystem raises an IOError saying the child terminated with a signal
I am totally at a loss as to explain this difference in behavior. I would prefer it to choose option #2 always.
Could process #1 have caught SIGINT while process #2 didn't? If so, GHC is not at fault, because wait() doesn't tell about caught signals. Udo. -- Lebensmittelskandal: Gene im Mais entdeckt! (angeblich eine Schlagzeile aus der BILD)
On Thu, Jul 06, 2006 at 04:09:43PM +0200, Udo Stenzel wrote:
1) rawSystem returns ExitSuccess
or
2) rawSystem raises an IOError saying the child terminated with a signal
I am totally at a loss as to explain this difference in behavior. I would prefer it to choose option #2 always.
Could process #1 have caught SIGINT while process #2 didn't? If so, GHC is not at fault, because wait() doesn't tell about caught signals.
Unlikely, I think. Same process doing same things. -- John
Ctrl-C sends signals to the entire process-group, in which case various race conditions may result. Have your experimented by killing just the child process with 'kill -INT <pid>'? On Thursday, July 06, 2006, at 11:15AM, John Goerzen <jgoerzen@complete.org> wrote:
On Thu, Jul 06, 2006 at 04:09:43PM +0200, Udo Stenzel wrote:
1) rawSystem returns ExitSuccess
or
2) rawSystem raises an IOError saying the child terminated with a signal
I am totally at a loss as to explain this difference in behavior. I would prefer it to choose option #2 always.
Could process #1 have caught SIGINT while process #2 didn't? If so, GHC is not at fault, because wait() doesn't tell about caught signals.
Unlikely, I think. Same process doing same things.
-- John _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
participants (5)
-
Florian Weimer -
John Goerzen -
Mathew Mills -
Simon Marlow -
Udo Stenzel