Re: Why it's dangerous to fork off a new process in Glasgow Haskell

Interesting. How exactly does it work, by the way?
Trade secret ;) Simply drop the TSO pointers to all other threads from the queues so the RTS won't find them again (GC is a different issue). Ah I see. The code is in ghc/rts/Schedule.c, in the function forkProcess.
Posix.runProcess really should use it I think.
No, it's better to be able to choose the way to handle this. Maybe add a flag to Posix.runProcess. But the whole GHC.Conc.forkProcess isn't finished, yet, anyway. I don't really see the point of allowing the user to choose the old way. Posix.runProcess is supposed to fork off a new process outside of this runtime system. I don't see any way this can be helped by allowing other
Volker Stolz wrote (about GHC.Conc.forkProcess): [snip] threads to continue in the child until the actual time of exec, unless for some reason the evaluation of the arguments to exec somehow relies on other threads. But this would surely at least require argument evaluation to unsafely conceal IO, and in any case could be better fixed by forcing the arguments to be fully evaluated before the fork.
The signature of Posix.runProcess is not quite adequate though; one wants some control over the child thread. At a minimum, it would be nice to be able to kill it. ^^^^^^^^ process?
You still get the child's pid, so feel free to mess with it.
You don't get it from Posix.runProcess. Posix.runProcess is supposed to be OS-independent (even though it's only available in Posix) and I'm not sure if a pid makes much sense on Windows anyway. What I think I would like on all systems is a new abstract data type ChildProcess with functions runProcess :: FilePath -> [String] -> Maybe [(String,String)] -> Maybe FilePath -> Maybe Handle -> Maybe Handle -> Maybe Handle -> IO ChildProcess (so the same as Posix.runProcess now except for returning ChildProcess) and killChildProcess :: ChildProcess -> IO () and ideally something like Posix.getProcessStatus as well. This is not completely trivial to implement; for example one would like runProcess to raise some exception if the exec fails, which means passing the information back to the parent in some way. But if you put together Sigbjorn's stuff for Windows and the existing Posix code it shouldn't be too hard.

George Russell wrote:
Posix.runProcess really should use it I think.
No, it's better to be able to choose the way to handle this. Maybe add a flag to Posix.runProcess. But the whole GHC.Conc.forkProcess isn't finished, yet, anyway. I don't really see the point of allowing the user to choose the old way. Posix.runProcess is supposed to fork off a new process outside of this runtime system. I don't see any way this can be helped by allowing other threads to continue in the child until the actual time of exec, unless for some reason the evaluation of the arguments to exec somehow relies on other threads. But this would surely at least require argument evaluation to unsafely conceal IO, and in any case could be better fixed by forcing the arguments to be fully evaluated before the fork.
Let's not forget that the new (child) process may never do exec(). I have an interpreter that forks to replicate itself, relying on the runtime system to carry over. My application uses multiple (GHC) threads as well as multiple (Unix) processes. I use an MVar to mutually exclude operations that are externally visible, so that in a new child process I can kill preexisting auxiliary threads. In my case, the cost in coding is modest; I'm not yet at the point where I can gauge the execution cost. The version of `forkProcess` that doesn't retain preexisting auxiliary threads is attractive, except that those threads are apparently not (currently) garbage collected properly in the child process. In my experience, I've not found a use for retaining auxiliary threads in the child process after a fork. On the other hand, I'm not yet convinced that couldn't be useful in some application. Dean

Dean Herington wrote:
George Russell wrote:
Posix.runProcess really should use it I think.
No, it's better to be able to choose the way to handle this. Maybe add a flag to Posix.runProcess. But the whole GHC.Conc.forkProcess isn't finished, yet, anyway. I don't really see the point of allowing the user to choose the old way. Posix.runProcess is supposed to fork off a new process outside of this runtime system. I don't see any way this can be helped by allowing other threads to continue in the child until the actual time of exec, unless for some reason the evaluation of the arguments to exec somehow relies on other threads. But this would surely at least require argument evaluation to unsafely conceal IO, and in any case could be better fixed by forcing the arguments to be fully evaluated before the fork.
Let's not forget that the new (child) process may never do exec(). I have an interpreter that forks to replicate itself, relying on the runtime system to carry over.
Er, are you confusing Posix.forkProcess (which I was talking about) with Posix.runProcess (which is what I am talking about now)?

George Russell wrote:
Dean Herington wrote:
George Russell wrote:
Posix.runProcess really should use it I think.
No, it's better to be able to choose the way to handle this. Maybe add a flag to Posix.runProcess. But the whole GHC.Conc.forkProcess isn't finished, yet, anyway. I don't really see the point of allowing the user to choose the old way. Posix.runProcess is supposed to fork off a new process outside of this runtime system. I don't see any way this can be helped by allowing other
Volker Stolz wrote: threads to continue in the child until the actual time of exec, unless for some reason the evaluation of the arguments to exec somehow relies on other threads. But this would surely at least require argument evaluation to unsafely conceal IO, and in any case could be better fixed by forcing the arguments to be fully evaluated before the fork.
Let's not forget that the new (child) process may never do exec(). I have an interpreter that forks to replicate itself, relying on the runtime system to carry over.
Er, are you confusing Posix.forkProcess (which I was talking about) with Posix.runProcess (which is what I am talking about now)?
Sorry for confusing them. I agree with you that, for Posix.runProcess, auxiliary threads should not be allowed to continue in the child process. In fact, I had to abandon use of Posix.runProcess in my application because it (currently) allows those threads to continue. A second reason Posix.runProcess didn't do the job for me is that it doesn't return a handle to the child process, as you also pointed out. Concerning forking a process (without necessarily doing exec), I agree with Volker that an option to control retention or deletion of auxiliary threads is desirable. Dean
participants (2)
-
Dean Herington
-
George Russell