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

George Russell ger@tzi.de
Tue, 03 Sep 2002 19:46:28 +0200


I have some code which forks off a new process which does some non-Haskelly stuff.  Thus it does
the standard things, something like


processId <- Posix.forkProcess
case processId of
   Just _ -> -- parent process, continue normally
      ...
   Nothing -> -- child process
      do
         ... -- rearrange plumbing of stdin/stdout/stderr
         Posix.executeFile [blah]

The GHC runProcess function uses a similar mechanism.

Unfortunately this has developed an extremely irritating bug.  The problem is that my program has
a lot of worker threads which do things like communicating with servers, already running programs,
and so on. These worker threads get replicated in the child process (like everything else) which
means that you now have two clients communicating with the server, where there ought to
be one, result chaos.  (Or in this case, the entire program coming to a halt.)  I've had this code for
several years (I inherited it), but the problem seems to have recently got much worse; I don't know whether
this is because of a change in GHC's scheduling with ghc5.04, or because I am now compiling much more
complicated programs.

Whatever, I simply couldn't find a way of fixing this in Haskell.  It would be good if there were a
way of telling GHC's RTS scheduler "Please don't run any other threads apart from this one until
further notice".  If so, you could do

[block other threads]
[do fork]
[if parent process
    then
       unblock other threads
       ...
    else -- child process
       rearrange plumbing and do exec
    ]

But there isn't.

So in the end I resorted to writing a C function which does both the forking and replumbing and execing.
Since GHC doesn't run native threads while foreign C code is executing, this fixes the problem.
It would be nice if there were a better way . . .