X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2Fposix%2FSignals.c;h=9f5bf9f370edc4aba35028054b4716d7fd295b2b;hb=6cec61d14a324285dbb8ce73d4c7215f1f8d6766;hp=e723b8ff0a469d199148bdc9b743dca6c53ae16a;hpb=08d888b90c82b3aa3092e439b197cef939ed3d44;p=ghc-hetmet.git diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c index e723b8f..9f5bf9f 100644 --- a/rts/posix/Signals.c +++ b/rts/posix/Signals.c @@ -40,6 +40,10 @@ # include #endif +#ifdef HAVE_TERMIOS_H +#include +#endif + #include #include @@ -97,7 +101,7 @@ void setIOManagerWakeupFd (int fd) { // only called when THREADED_RTS, but unconditionally - // compiled here because System.Event.Control depends on it. + // compiled here because GHC.Event.Control depends on it. io_manager_wakeup_fd = fd; } @@ -105,7 +109,7 @@ void setIOManagerControlFd (int fd) { // only called when THREADED_RTS, but unconditionally - // compiled here because System.Event.Control depends on it. + // compiled here because GHC.Event.Control depends on it. io_manager_control_fd = fd; } @@ -480,6 +484,75 @@ empty_handler (int sig STG_UNUSED) } /* ----------------------------------------------------------------------------- + SIGTSTP handling + + When a process is suspeended with ^Z and resumed again, the shell + makes no attempt to save and restore the terminal settings. So on + resume, any terminal setting modificaions we made (e.g. turning off + ICANON due to hSetBuffering NoBuffering) may well be lost. Hence, + we arrange to save and restore the terminal settings ourselves. + + The trick we use is: + - catch SIGTSTP + - in the handler, kill(getpid(),SIGTSTP) + - when this returns, restore the TTY settings + This means we don't have to catch SIGCONT too. + + -------------------------------------------------------------------------- */ + +static void sigtstp_handler(int sig); +static void set_sigtstp_action (rtsBool handle); + +static void +sigtstp_handler (int sig) +{ + int fd; + struct termios ts[3]; + + // save the current TTY state for TTYs we modified + for (fd = 0; fd <= 2; fd++) { + if (__hscore_get_saved_termios(fd) != NULL) { + tcgetattr(fd,&ts[fd]); + } + } + + // de-install the SIGTSTP handler + set_sigtstp_action(rtsFalse); + + // really stop the process now + { + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, sig); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + kill(getpid(), sig); + } + + // on return, restore the TTY state + for (fd = 0; fd <= 2; fd++) { + if (__hscore_get_saved_termios(fd) != NULL) { + tcsetattr(0,TCSANOW,&ts[fd]); + } + } + + set_sigtstp_action(rtsTrue); +} + +static void +set_sigtstp_action (rtsBool handle) +{ + struct sigaction sa; + if (handle) { + sa.sa_handler = sigtstp_handler; + } else { + sa.sa_handler = SIG_DFL; + } + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(SIGTSTP, &sa, NULL); +} + +/* ----------------------------------------------------------------------------- * Install default signal handlers. * * The RTS installs a default signal handler for catching @@ -543,6 +616,8 @@ initDefaultHandlers(void) if (sigaction(SIGPIPE, &action, &oact) != 0) { sysErrorBelch("warning: failed to install SIGPIPE handler"); } + + set_sigtstp_action(rtsTrue); } void @@ -562,6 +637,8 @@ resetDefaultHandlers(void) if (sigaction(SIGPIPE, &action, NULL) != 0) { sysErrorBelch("warning: failed to uninstall SIGPIPE handler"); } + + set_sigtstp_action(rtsFalse); } void