Opened 9 years ago

Last modified 7 years ago

#3081 new bug

Double output after Ctrl+C on Windows

Reported by: NeilMitchell Owned by:
Priority: normal Milestone:
Component: Runtime System Version: 6.10.1
Keywords: Cc: ganesh
Operating System: Windows Architecture: x86
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

C:\Temp>type Test.hs
import Control.Exception
import System.Cmd
main = system "sleep 1m" `finally` putStrLn "goodbye"

C:\Temp>ghc --version
The Glorious Glasgow Haskell Compilation System, version 6.10.1

C:\Temp>ghc --make Test.hs
[1 of 1] Compiling Main             ( Test.hs, Test.o )
Linking Test.exe ...

C:\Temp>test.exe
^Cgoodbye
goodbye
C:\Temp>

The ^C is the consoles way of saying that Ctrl+C was pressed - i.e. I ran the program and hit Ctrl+C while the sleep was still ongoing. I can replicate this issue from the DOS prompt and from the Cygwin prompt. It does not occur from GHCi.

Change History (5)

comment:1 Changed 9 years ago by NeilMitchell

Philip K.F. Hölzenspies reports that the above test works fine on Linux, giving the correct behaviour.

comment:2 Changed 9 years ago by simonmar

difficulty: Unknown
Milestone: 6.10.2
Owner: set to simonmar

This is slightly worrying, I'll try to look into it before 6.10.2.

comment:3 Changed 9 years ago by simonmar

Milestone: 6.10.2_|_
Summary: Finally run twice on Ctrl+CDouble output after Ctrl+C on Windows

Ok, this was an interesting one. In fact it has nothing to do with finally; the following program has the same behaviour:

import System.Cmd
main = system "sleep 1m" >> putStrLn "goodbye"

In fact it even crashed with the HEAD, but the crash was particularly fragile and most attempts to investigate it made it go away. This patch fixes the crash:

Wed Mar 11 08:45:59 PDT 2009  Simon Marlow <marlowsd@gmail.com>
  * avoid a crash: don't return unless the run queue has some threads in it

which Ian has already merged.

However, the double-output problem still happens. It doesn't happen if you use -threaded. Here's what's going on:

  • When the user hits ^C, the system call immediately returns.
  • The RTS spins up a thread to throw the ^C exception to the main thread
  • The main thread calls putStrLn "goodbye"
  • The async IO system in the non-threaded RTS creates an OS thread to do write(1,"goodbye\n"), and the main thread is blocked waiting for it to complete
  • the write completes
  • The main thread receives the Interrupted exception. We try to abort the IO, but it has already happened.
  • The top-level exception handler in the main thread flushes stdout. The stdout buffer still contains "goodbye", because the first IO was interrupted, so it writes that to stdout.

I don't think there's a way to fix this without serious surgery - we'd need a way to synchronously abandon an async IO request, and I don't even know if that's possible. I'll leave the bug at _|_ since it still exists, but I doubt I'll fix it. If anyone else wants to try you're more than welcome!

comment:4 Changed 9 years ago by simonmar

Owner: simonmar deleted

comment:5 Changed 7 years ago by ganesh

Cc: ganesh added
Type of failure: None/Unknown
Note: See TracTickets for help on using tickets.