ghci and ghc -threaded broken with pipes & forking

Simon Marlow simonmarhaskell at gmail.com
Thu Mar 1 11:21:45 EST 2007


John Goerzen wrote:
> On Thu, Mar 01, 2007 at 03:06:22PM +0000, Simon Marlow wrote:
>> Ok, what happens here is that in the forked process there is only a single 
>> thread, the runtime kills all the other threads (as advertised).  
>> Unfortunately this includes the I/O manager thread, so as soon as you do 
>> some I/O in the forked process, you block.
> 
> Could it just revert to the nonthreaded IO model, or is that not within
> the scope of what's easily achievable with the threaded RTS?

The non-threaded I/O system just isn't compiled into the threaded RTS at all. 
We used to use it in the threaded RTS before we switched to the I/O manager 
thread, but as I recall it was a rich source of bugs; the I/O manager thread is 
much simpler, being in Haskell.

>> On a more general note, forkProcess is known to be hairy - simply the fact 
>> that it kills all the other threads in the system in the forked process 
>> means that there's a good supply of means to shoot yourself in the foot, 
>> even accidentally. John - perhaps there's another way to achieve what you 
>>  want?
> 
> Right.  Part of this problem may be one of documentation, and part of it
> rests with ghci.
> 
> I have no need for threads in this program.  And, in fact, as you said,
> threads are known to be hazardous when used in conjuntion with fork().
> I have no interest in combining the to.  The mechanics of signal
> propogation, file descriptor closing, etc. all get complicated.
> 
> But it seems like there is not much choice with ghci.  It appears to be
> built with the threaded RTS by default, and uses threads even though I
> never try to use threads with it.  And there seems to be no way to turn
> it off.

The problem is that the choice between -threaded and non-threaded is made at 
link-time, so we have to make that choice when we link the GHCi binary.

In fact you should think of the non-threaded RTS as deprecated.  It isn't 
Haskell'-compliant, for one thing (assuming that Haskell' will probably require 
non-blocking foreign calls).

I'm hesitant to actually deprecate it, for a few reasons: the threaded RTS is so 
much more complicated, it might have some adverse performance impliciations, and 
there are still people who want to run everything in a single OS thread, for 
whatever reason.  But having multiple variants of the RTS is a maintenance and 
testing headache.

> Between that and the lack of support for forkProcess in Hugs, this
> renders anything that needs to fork and then do I/O as being usable only
> in GHC-compiled code.  Which is sub-optimal, but livable anyway.

I guess I'm really wondering why you need to fork and do I/O at all.  Can you 
describe the problem at a higher level?

> Also, why does hGetContents not work, but hPutStr does?  If the IO
> manager is dead, how does some IO still work?

Ah well, only I/O that needs to block uses the I/O manager thread.  I/O that 
doesn't block just proceeds directly.

Cheers,
	Simon



More information about the Glasgow-haskell-users mailing list