
Judah Jacobson wrote:
Hi all,
I'm writing a program that reads input from the user but should also handle a ctrl-c. My attempt is below; the program forks a thread to read one character of input, and kills that thread upon receiving a sigINT. It works fine compiled without -threaded, but with -threaded it blocks forever after a ctrl-c.
I know that in general, foreign calls are not interruptible; but the documentation for Control.Concurrent and System.Timeout suggests that I/O operations are a special case. In particular, the documentation for System.Timeout.timeout says:
"Standard I/O functions like hGetBuf, hPutBuf, Network.Socket.accept, or hWaitForInput appear to be blocking, but they really don't because the runtime system uses scheduling mechanisms like select(2) to perform asynchronous I/O, so it is possible to interrupt standard socket I/O or file I/O using this combinator."
So is the behavior that I'm seeing correct? If so, it seems odd to get better concurrency without the threaded runtime. If not, I can file a bug for this. I used ghc-6.8.2 and HEAD on OS X 10.5 (x86).
Ah, this is a consequence of the change we made to stdin/stdout/stderr so that they no longer use O_NONBLOCK, but with -threaded they use blocking foreign calls instead. In your example, getChar is stuck in a blocking foreign call and can't be interrupted. I don't see a good workaround. One way is to add another thread: run the getChar in a subthread and the parent will be able to receive the signal. Or perhaps you could cause the read() that getChar has called to return EINTR, but that might not be enough because the I/O library executes mostly inside Control.Exception.block. Unix semantics just isn't the right thing when it comes to non-blocking I/O. If only there were non-blocking read()/write() system calls, we'd be fine. Cheers, Simon