[Haskell-cafe] control-c only caught once -- bug?

Brian Johnson brianjohnsonhaskellcafe at gmail.com
Sat Oct 29 21:18:07 CEST 2011

On Sat, Oct 29, 2011 at 9:36 AM, Donn Cave <donn at avvanta.com> wrote:

> The SIGINT handler looks like more of a quirk of the RTS, than
> a feature whose behavior you should depend on in great detail.

I looked into this some more, and found that it is indeed a quirk of the
RTS -- an apparently /intentional/ one.  From

"When the interrupt signal is received, the default behaviour of the
runtime is to attempt to shut down the Haskell program gracefully. It does
this by calling interruptStgRts() in
 (see Commentary/Rts/Scheduler#ShuttingDown<http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Scheduler#ShuttingDown>).
If a second interrupt signal is received, then we terminate the process
immediately; this is just in case the normal shutdown procedure failed or
hung for some reason, the user is always able to stop the process with two
control-C keystrokes"

While I'm sure someone or ones meant well when designing the RTS to work in
this way, I do not agree that this is sensible.  It's fine for calculation
or utility programs that perform one task and exit, but not for interactive
programs such as shells, editors, or anything with a command line
interface.  IMO, handholding behavior such as this is exactly the sort of
thing that risks new Haskell users coming to the conclusion that "Haskell
is not intended for real programming projects" -- I know, because I nearly
came to this exact conclusion while pulling my hair out trying to figure
out what was going on here.  Further complicating the matter is that this
feature only exists in POSIX environments, i.e. not on Windows.

I can use System.Posix.Signals.installHandler to catch <ctrl>C (SIGINT)
> in a repeatable way, on MacOS X, so that's working as it should.  If you
> want it to return control to the user interface, that's going to take
> some work - for all I know, there may be some way to hook a signal handler
> up with Control.Exception.catch.

Indeed, it's easy to hook up your own signal handler so that ALL keyboard
interrupts have the expected behavior of throwing a UserInterrupt exception
-- although I would not have thought to do this before learning that the
RTS is "broken" in this regard:

import Control.Exception as C
import Control.Concurrent
import System.Posix.Signals

main = do
  tid <- myThreadId
  installHandler keyboardSignal (Catch (throwTo tid UserInterrupt)) Nothing
  ... -- rest of program

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20111029/34be69b3/attachment.htm>

More information about the Haskell-Cafe mailing list