summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/RtsAPI.h10
-rw-r--r--rts/RtsMain.c2
-rw-r--r--rts/RtsStartup.c64
3 files changed, 60 insertions, 16 deletions
diff --git a/includes/RtsAPI.h b/includes/RtsAPI.h
index 29c28d8fcc..daae30b821 100644
--- a/includes/RtsAPI.h
+++ b/includes/RtsAPI.h
@@ -94,14 +94,12 @@ extern void hs_init_with_rtsopts (int *argc, char **argv[]);
extern void hs_init_ghc (int *argc, char **argv[], // program arguments
RtsConfig rts_config); // RTS configuration
-extern void shutdownHaskellAndExit ( int exitCode )
-#if __GNUC__ >= 3
- __attribute__((__noreturn__))
-#endif
- ;
+extern void shutdownHaskellAndExit (int exitCode, int fastExit)
+ GNUC3_ATTRIBUTE(__noreturn__);
#ifndef mingw32_HOST_OS
-extern void shutdownHaskellAndSignal (int sig);
+extern void shutdownHaskellAndSignal (int sig, int fastExit)
+ GNUC3_ATTRIBUTE(__noreturn__);
#endif
extern void getProgArgv ( int *argc, char **argv[] );
diff --git a/rts/RtsMain.c b/rts/RtsMain.c
index 435df420c5..df637169f8 100644
--- a/rts/RtsMain.c
+++ b/rts/RtsMain.c
@@ -84,7 +84,7 @@ static void real_main(void)
default:
barf("main thread completed with invalid status");
}
- shutdownHaskellAndExit(exit_status);
+ shutdownHaskellAndExit(exit_status, 0 /* !fastExit */);
}
/* The rts entry point from a compiled program using a Haskell main
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
index a1c74ae6a6..aa7306f88a 100644
--- a/rts/RtsStartup.c
+++ b/rts/RtsStartup.c
@@ -455,24 +455,70 @@ shutdownHaskell(void)
}
void
-shutdownHaskellAndExit(int n)
+shutdownHaskellAndExit(int n, int fastExit)
{
- // even if hs_init_count > 1, we still want to shut down the RTS
- // and exit immediately (see #5402)
- hs_init_count = 1;
+ if (!fastExit) {
+ // even if hs_init_count > 1, we still want to shut down the RTS
+ // and exit immediately (see #5402)
+ hs_init_count = 1;
- // we're about to exit(), no need to wait for foreign calls to return.
- hs_exit_(rtsFalse);
+ // we're about to exit(), no need to wait for foreign calls to return.
+ hs_exit_(rtsFalse);
+ }
stg_exit(n);
}
#ifndef mingw32_HOST_OS
+static void exitBySignal(int sig) GNUC3_ATTRIBUTE(__noreturn__);
+
void
-shutdownHaskellAndSignal(int sig)
+shutdownHaskellAndSignal(int sig, int fastExit)
{
- hs_exit_(rtsFalse);
- kill(getpid(),sig);
+ if (!fastExit) {
+ hs_exit_(rtsFalse);
+ }
+
+ exitBySignal(sig);
+}
+
+void
+exitBySignal(int sig)
+{
+ // We're trying to kill ourselves with a given signal.
+ // That's easier said that done because:
+ // - signals can be ignored have handlers set for them
+ // - signals can be masked
+ // - signals default action can do things other than terminate:
+ // + can do nothing
+ // + can do weirder things: stop/continue the process
+
+ struct sigaction dfl;
+ sigset_t sigset;
+
+ // So first of all, we reset the signal to use the default action.
+ (void)sigemptyset(&dfl.sa_mask);
+ dfl.sa_flags = 0;
+ dfl.sa_handler = SIG_DFL;
+ (void)sigaction(sig, &dfl, NULL);
+
+ // Then we unblock the signal so we can deliver it to ourselves
+ sigemptyset(&sigset);
+ sigaddset(&sigset, sig);
+ sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+
+ switch (sig) {
+ case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: case SIGCONT:
+ // These signals stop (or continue) the process, so are no good for
+ // exiting.
+ exit(0xff);
+
+ default:
+ kill(getpid(),sig);
+ // But it's possible the signal is one where the default action is to
+ // ignore, in which case we'll still be alive... so just exit.
+ exit(0xff);
+ }
}
#endif