# include <errno.h>
#endif
+#ifdef HAVE_EVENTFD_H
+# include <sys/eventfd.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+
#include <stdlib.h>
#include <string.h>
}
// 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 System.Event.Control depends on it.
+ io_manager_wakeup_fd = fd;
}
void
-ioManagerWakeup (void)
+setIOManagerControlFd (int fd)
{
- int r;
- // Wake up the IO Manager thread by sending a byte down its pipe
- if (io_manager_pipe >= 0) {
- StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
- r = write(io_manager_pipe, &byte, 1);
- if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); }
- }
+ // only called when THREADED_RTS, but unconditionally
+ // compiled here because System.Event.Control depends on it.
+ io_manager_control_fd = fd;
}
void
-ioManagerSync (void)
+ioManagerWakeup (void)
{
int r;
// Wake up the IO Manager thread by sending a byte down its pipe
- if (io_manager_pipe >= 0) {
- StgWord8 byte = (StgWord8)IO_MANAGER_SYNC;
- r = write(io_manager_pipe, &byte, 1);
- if (r == -1) { sysErrorBelch("ioManagerSync: write"); }
+ 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_wakeup_fd, &byte, 1);
+#endif
+ if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); }
}
}
{
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_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
+ return rts_evalIO(
+ cap,&base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
}
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 = ioManagerStartCap(cap);
rts_unlock(cap);
{
#if defined(THREADED_RTS)
- if (io_manager_pipe != -1)
+ if (io_manager_control_fd != -1)
{
StgWord8 buf[sizeof(siginfo_t) + 1];
int r;
memcpy(buf+1, info, sizeof(siginfo_t));
}
- r = write(io_manager_pipe, buf, sizeof(siginfo_t)+1);
+ 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);
{
sigemptyset(&userSignals);
#ifndef THREADED_RTS
- getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure);
+ getStablePtr((StgPtr)&base_GHCziConcziSignal_runHandlers_closure);
// needed to keep runHandler alive
#endif
}
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))));
}
}
/* -----------------------------------------------------------------------------
+ * 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
#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
if (sigaction(SIGPIPE, &action, NULL) != 0) {
sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
}
+
+ set_sigtstp_action(rtsFalse);
}
void