X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=rts%2Fposix%2FSignals.c;h=9f5bf9f370edc4aba35028054b4716d7fd295b2b;hp=c1ffb5d2cfaa6f7a703d8e8acc5cb9cb9e6bf487;hb=cf5905ea24904cf73a041fd7535e8723a668cb9a;hpb=1c45176f3b9be75b5c4744d9ef074430bf034e3f diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c index c1ffb5d..9f5bf9f 100644 --- a/rts/posix/Signals.c +++ b/rts/posix/Signals.c @@ -6,18 +6,15 @@ * * ---------------------------------------------------------------------------*/ -/* This is non-Posix-compliant. - #include "PosixSource.h" -*/ +#include "PosixSource.h" #include "Rts.h" -#include "SchedAPI.h" + #include "Schedule.h" #include "RtsSignals.h" -#include "posix/Signals.h" +#include "Signals.h" #include "RtsUtils.h" -#include "RtsFlags.h" #include "Prelude.h" -#include "ThrIOManager.h" +#include "Stable.h" #ifdef alpha_HOST_ARCH # if defined(linux_HOST_OS) @@ -39,6 +36,14 @@ # include #endif +#ifdef HAVE_EVENTFD_H +# include +#endif + +#ifdef HAVE_TERMIOS_H +#include +#endif + #include #include @@ -85,54 +90,76 @@ more_handlers(int sig) } // Here's the pipe into which we will send our signals -static int io_manager_pipe = -1; +static int io_manager_wakeup_fd = -1; +static int io_manager_control_fd = -1; #define IO_MANAGER_WAKEUP 0xff #define IO_MANAGER_DIE 0xfe +#define IO_MANAGER_SYNC 0xfd void -setIOManagerPipe (int fd) +setIOManagerWakeupFd (int fd) { // only called when THREADED_RTS, but unconditionally - // compiled here because GHC.Conc depends on it. - io_manager_pipe = fd; + // compiled here because GHC.Event.Control depends on it. + io_manager_wakeup_fd = fd; +} + +void +setIOManagerControlFd (int fd) +{ + // only called when THREADED_RTS, but unconditionally + // compiled here because GHC.Event.Control depends on it. + io_manager_control_fd = fd; } -#if defined(THREADED_RTS) void ioManagerWakeup (void) { int r; // Wake up the IO Manager thread by sending a byte down its pipe - if (io_manager_pipe >= 0) { + if (io_manager_wakeup_fd >= 0) { +#if defined(HAVE_EVENTFD) + StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP; + r = write(io_manager_wakeup_fd, (char *) &n, 8); +#else StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP; - r = write(io_manager_pipe, &byte, 1); + r = write(io_manager_wakeup_fd, &byte, 1); +#endif if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); } } } +#if defined(THREADED_RTS) void ioManagerDie (void) { int r; // Ask the IO Manager thread to exit - if (io_manager_pipe >= 0) { + if (io_manager_control_fd >= 0) { StgWord8 byte = (StgWord8)IO_MANAGER_DIE; - r = write(io_manager_pipe, &byte, 1); + r = write(io_manager_control_fd, &byte, 1); if (r == -1) { sysErrorBelch("ioManagerDie: write"); } - close(io_manager_pipe); - io_manager_pipe = -1; + io_manager_control_fd = -1; + io_manager_wakeup_fd = -1; } } +Capability * +ioManagerStartCap (Capability *cap) +{ + return rts_evalIO( + cap,&base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL); +} + void ioManagerStart (void) { // Make sure the IO manager thread is running Capability *cap; - if (io_manager_pipe < 0) { + if (io_manager_control_fd < 0 || io_manager_wakeup_fd < 0) { cap = rts_lock(); - cap = rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL); + cap = ioManagerStartCap(cap); rts_unlock(cap); } } @@ -161,14 +188,21 @@ generic_handler(int sig USED_IF_THREADS, { #if defined(THREADED_RTS) - if (io_manager_pipe != -1) + if (io_manager_control_fd != -1) { StgWord8 buf[sizeof(siginfo_t) + 1]; int r; buf[0] = sig; - memcpy(buf+1, info, sizeof(siginfo_t)); - r = write(io_manager_pipe, buf, sizeof(siginfo_t)+1); + + if (info == NULL) { + // info may be NULL on Solaris (see #3790) + memset(buf+1, 0, sizeof(siginfo_t)); + } else { + memcpy(buf+1, info, sizeof(siginfo_t)); + } + + r = write(io_manager_control_fd, buf, sizeof(siginfo_t)+1); if (r == -1 && errno == EAGAIN) { errorBelch("lost signal due to full pipe: %d\n", sig); @@ -235,7 +269,7 @@ initUserSignals(void) { sigemptyset(&userSignals); #ifndef THREADED_RTS - getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure); + getStablePtr((StgPtr)&base_GHCziConcziSignal_runHandlers_closure); // needed to keep runHandler alive #endif } @@ -389,7 +423,7 @@ startSignalHandlers(Capability *cap) RtsFlags.GcFlags.initialStkSize, rts_apply(cap, rts_apply(cap, - &base_GHCziConc_runHandlers_closure, + &base_GHCziConcziSignal_runHandlers_closure, rts_mkPtr(cap, info)), rts_mkInt(cap, info->si_signo)))); } @@ -441,6 +475,84 @@ shutdown_handler(int sig STG_UNUSED) } /* ----------------------------------------------------------------------------- + * An empty signal handler, currently used for SIGPIPE + * -------------------------------------------------------------------------- */ +static void +empty_handler (int sig STG_UNUSED) +{ + // nothing +} + +/* ----------------------------------------------------------------------------- + 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 @@ -496,12 +608,16 @@ initDefaultHandlers(void) #endif // ignore SIGPIPE; see #1619 - action.sa_handler = SIG_IGN; + // actually, we use an empty signal handler rather than SIG_IGN, + // so that SIGPIPE gets reset to its default behaviour on exec. + action.sa_handler = empty_handler; sigemptyset(&action.sa_mask); action.sa_flags = 0; if (sigaction(SIGPIPE, &action, &oact) != 0) { sysErrorBelch("warning: failed to install SIGPIPE handler"); } + + set_sigtstp_action(rtsTrue); } void @@ -521,6 +637,8 @@ resetDefaultHandlers(void) if (sigaction(SIGPIPE, &action, NULL) != 0) { sysErrorBelch("warning: failed to uninstall SIGPIPE handler"); } + + set_sigtstp_action(rtsFalse); } void