Commit addff19a authored by Simon Marlow's avatar Simon Marlow
Browse files

FIX part of #2301, and #1619

2301: Control-C now causes the new exception (AsyncException
UserInterrupt) to be raised in the main thread.  The signal handler
is set up by GHC.TopHandler.runMainIO, and can be overriden in the
usual way by installing a new signal handler.  The advantage is that
now all programs will get a chance to clean up on ^C.

When UserInterrupt is caught by the topmost handler, we now exit the
program via kill(getpid(),SIGINT), which tells the parent process that
we exited as a result of ^C, so the parent can take appropriate action
(it might want to exit too, for example).

One subtlety is that we have to use a weak reference to the ThreadId
for the main thread, so that the signal handler doesn't prevent the
main thread from being subject to deadlock detection.

1619: we now ignore SIGPIPE by default.  Although POSIX says that a
SIGPIPE should terminate the process by default, I wonder if this
decision was made because many C applications failed to check the exit
code from write().  In Haskell a failed write due to a closed pipe
will generate an exception anyway, so the main difference is that we
now get a useful error message instead of silent program termination.
See #1619 for more discussion.
parent 5f923aab
......@@ -45,6 +45,10 @@ extern void setProgArgv ( int argc, char *argv[] );
extern void getFullProgArgv ( int *argc, char **argv[] );
extern void setFullProgArgv ( int argc, char *argv[] );
#ifndef mingw32_HOST_OS
extern void shutdownHaskellAndSignal (int sig);
#endif
/* exit() override */
extern void (*exitFn)(int);
......
......@@ -174,6 +174,7 @@ typedef struct _RtsSymbolVal {
#if !defined (mingw32_HOST_OS)
#define RTS_POSIX_ONLY_SYMBOLS \
SymX(shutdownHaskellAndSignal) \
Sym(lockFile) \
Sym(unlockFile) \
SymX(signal_handlers) \
......
......@@ -40,6 +40,7 @@ extern void initUserSignals(void);
* Ctrl+C handler that shuts down the RTS in an orderly manner.
*/
extern void initDefaultHandlers(void);
extern void resetDefaultHandlers(void);
extern void freeSignalHandlers(void);
......
......@@ -71,6 +71,9 @@
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if USE_PAPI
#include "Papi.h"
......@@ -383,6 +386,8 @@ hs_exit_(rtsBool wait_foreign)
/* start timing the shutdown */
stat_startExit();
OnExitHook();
#if defined(RTS_USER_SIGNALS)
if (RtsFlags.MiscFlags.install_signal_handlers) {
freeSignalHandlers();
......@@ -440,6 +445,9 @@ hs_exit_(rtsBool wait_foreign)
PAR_TICKY_PAR_END();
#endif
// uninstall signal handlers
resetDefaultHandlers();
/* stop timing the shutdown, we're about to print stats */
stat_endExit();
......@@ -528,10 +536,10 @@ shutdownHaskell(void)
void
shutdownHaskellAndExit(int n)
{
if (hs_init_count == 1) {
OnExitHook();
hs_exit_(rtsFalse);
// we're about to exit(), no need to wait for foreign calls to return.
// we're about to exit(), no need to wait for foreign calls to return.
hs_exit_(rtsFalse);
if (hs_init_count == 0) {
#if defined(PAR)
/* really exit (stg_exit() would call shutdownParallelSystem() again) */
exit(n);
......@@ -541,6 +549,15 @@ shutdownHaskellAndExit(int n)
}
}
#ifndef mingw32_HOST_OS
void
shutdownHaskellAndSignal(int sig)
{
hs_exit_(rtsFalse);
kill(getpid(),sig);
}
#endif
/*
* called from STG-land to exit the program
*/
......
......@@ -496,6 +496,33 @@ initDefaultHandlers(void)
#ifdef alpha_HOST_ARCH
ieee_set_fp_control(0);
#endif
// ignore SIGPIPE; see #1619
action.sa_handler = SIG_IGN;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGPIPE, &action, &oact) != 0) {
sysErrorBelch("warning: failed to install SIGPIPE handler");
}
}
void
resetDefaultHandlers(void)
{
struct sigaction action;
action.sa_handler = SIG_DFL;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
// restore SIGINT
if (sigaction(SIGINT, &action, NULL) != 0) {
sysErrorBelch("warning: failed to uninstall SIGINT handler");
}
// restore SIGPIPE
if (sigaction(SIGPIPE, &action, NULL) != 0) {
sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
}
}
void
......
......@@ -119,6 +119,12 @@ void initDefaultHandlers(void)
}
}
void resetDefaultHandlers(void)
{
if ( !SetConsoleCtrlHandler(shutdown_handler, FALSE) ) {
errorBelch("warning: failed to uninstall default console handler");
}
}
/*
* Function: blockUserSignals()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment