diff options
Diffstat (limited to 'rts')
-rw-r--r-- | rts/Prelude.h | 1 | ||||
-rw-r--r-- | rts/RtsStartup.c | 12 | ||||
-rw-r--r-- | rts/package.conf.in | 2 | ||||
-rw-r--r-- | rts/posix/Signals.c | 171 | ||||
-rw-r--r-- | rts/posix/Signals.h | 8 |
5 files changed, 101 insertions, 93 deletions
diff --git a/rts/Prelude.h b/rts/Prelude.h index d89119ad1e..69bd3f516b 100644 --- a/rts/Prelude.h +++ b/rts/Prelude.h @@ -44,6 +44,7 @@ PRELUDE_CLOSURE(base_ControlziExceptionziBase_nestedAtomically_closure); PRELUDE_CLOSURE(base_GHCziConc_runSparks_closure); PRELUDE_CLOSURE(base_GHCziConc_ensureIOManagerIsRunning_closure); +PRELUDE_CLOSURE(base_GHCziConc_runHandlers_closure); PRELUDE_INFO(ghczmprim_GHCziTypes_Czh_static_info); PRELUDE_INFO(ghczmprim_GHCziTypes_Izh_static_info); diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index 6abeb404a0..b9442d2bd5 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -402,12 +402,6 @@ hs_exit_(rtsBool wait_foreign) OnExitHook(); -#if defined(RTS_USER_SIGNALS) - if (RtsFlags.MiscFlags.install_signal_handlers) { - freeSignalHandlers(); - } -#endif - #if defined(THREADED_RTS) ioManagerDie(); #endif @@ -418,6 +412,12 @@ hs_exit_(rtsBool wait_foreign) /* run C finalizers for all active weak pointers */ runAllCFinalizers(weak_ptr_list); +#if defined(RTS_USER_SIGNALS) + if (RtsFlags.MiscFlags.install_signal_handlers) { + freeSignalHandlers(); + } +#endif + #if defined(GRAN) /* end_gr_simulation prints global stats if requested -- HWL */ if (!RtsFlags.GranFlags.GranSimStats.Suppressed) diff --git a/rts/package.conf.in b/rts/package.conf.in index d4882a5868..490222fdb9 100644 --- a/rts/package.conf.in +++ b/rts/package.conf.in @@ -110,6 +110,7 @@ ld-options: , "-u", "_base_GHCziTopHandler_runNonIO_closure" , "-u", "_base_GHCziConc_ensureIOManagerIsRunning_closure" , "-u", "_base_GHCziConc_runSparks_closure" + , "-u", "_base_GHCziConc_runHandlers_closure" #else "-u", "ghczmprim_GHCziTypes_Izh_static_info" , "-u", "ghczmprim_GHCziTypes_Czh_static_info" @@ -147,6 +148,7 @@ ld-options: , "-u", "base_GHCziTopHandler_runNonIO_closure" , "-u", "base_GHCziConc_ensureIOManagerIsRunning_closure" , "-u", "base_GHCziConc_runSparks_closure" + , "-u", "base_GHCziConc_runHandlers_closure" #endif /* Pick up static libraries in preference over dynamic if in earlier search diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c index 493b083401..c016b9bf75 100644 --- a/rts/posix/Signals.c +++ b/rts/posix/Signals.c @@ -35,7 +35,12 @@ # include <signal.h> #endif +#ifdef HAVE_ERRNO_H +# include <errno.h> +#endif + #include <stdlib.h> +#include <string.h> /* This curious flag is provided for the benefit of the Haskell binding * to POSIX.1 to control whether or not to include SA_NOCLDSTOP when @@ -60,7 +65,7 @@ static nat n_haskell_handlers = 0; * -------------------------------------------------------------------------- */ static void -more_handlers(I_ sig) +more_handlers(int sig) { StgInt i; @@ -79,33 +84,6 @@ more_handlers(I_ sig) nHandlers = sig + 1; } -/* ----------------------------------------------------------------------------- - * Pending Handlers - * - * The mechanism for starting handlers differs between the threaded - * (THREADED_RTS) and non-threaded versions of the RTS. - * - * When the RTS is single-threaded, we just write the pending signal - * handlers into a buffer, and start a thread for each one in the - * scheduler loop. - * - * When THREADED_RTS, the problem is that signals might be - * delivered to multiple threads, so we would need to synchronise - * access to pending_handler_buf somehow. Using thread - * synchronisation from a signal handler isn't possible in general - * (some OSs support it, eg. MacOS X, but not all). So instead: - * - * - the signal handler writes the signal number into the pipe - * managed by the IO manager thread (see GHC.Conc). - * - the IO manager picks up the signal number and calls - * startSignalHandler() to start the thread. - * - * This also has the nice property that we don't need to arrange to - * wake up a worker task to start the signal handler: the IO manager - * wakes up when we write into the pipe. - * - * -------------------------------------------------------------------------- */ - // Here's the pipe into which we will send our signals static int io_manager_pipe = -1; @@ -138,6 +116,8 @@ ioManagerDie (void) if (io_manager_pipe >= 0) { StgWord8 byte = (StgWord8)IO_MANAGER_DIE; write(io_manager_pipe, &byte, 1); + close(io_manager_pipe); + io_manager_pipe = -1; } } @@ -158,8 +138,8 @@ ioManagerStart (void) #define N_PENDING_HANDLERS 16 -StgPtr pending_handler_buf[N_PENDING_HANDLERS]; -StgPtr *next_pending_handler = pending_handler_buf; +siginfo_t pending_handler_buf[N_PENDING_HANDLERS]; +siginfo_t *next_pending_handler = pending_handler_buf; #endif /* THREADED_RTS */ @@ -171,7 +151,9 @@ StgPtr *next_pending_handler = pending_handler_buf; * -------------------------------------------------------------------------- */ static void -generic_handler(int sig) +generic_handler(int sig USED_IF_THREADS, + siginfo_t *info, + void *p STG_UNUSED) { sigset_t signals; @@ -179,10 +161,16 @@ generic_handler(int sig) if (io_manager_pipe != -1) { - // Write the signal number into the pipe as a single byte. We - // hope that signals fit into a byte... - StgWord8 csig = (StgWord8)sig; - write(io_manager_pipe, &csig, 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 (r == -1 && errno == EAGAIN) + { + errorBelch("lost signal due to full pipe: %d\n", sig); + } } // If the IO manager hasn't told us what the FD of the write end // of its pipe is, there's not much we can do here, so just ignore @@ -218,7 +206,9 @@ generic_handler(int sig) circumstances, depending on the signal. */ - *next_pending_handler++ = deRefStablePtr((StgStablePtr)signal_handlers[sig]); + memcpy(next_pending_handler, info, sizeof(siginfo_t)); + + next_pending_handler++; // stack full? if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) { @@ -247,6 +237,10 @@ void initUserSignals(void) { sigemptyset(&userSignals); +#ifndef THREADED_RTS + getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure); + // needed to keep runHandler alive +#endif } void @@ -279,10 +273,14 @@ awaitUserSignals(void) /* ----------------------------------------------------------------------------- * Install a Haskell signal handler. + * + * We should really do this in Haskell in GHC.Conc, and share the + * signal_handlers array with the one there. + * * -------------------------------------------------------------------------- */ int -stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask) +stg_sig_install(int sig, int spi, void *mask) { sigset_t signals, osignals; struct sigaction action; @@ -303,26 +301,19 @@ stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask) switch(spi) { case STG_SIG_IGN: - signal_handlers[sig] = STG_SIG_IGN; - sigdelset(&userSignals, sig); action.sa_handler = SIG_IGN; break; - + case STG_SIG_DFL: - signal_handlers[sig] = STG_SIG_DFL; - sigdelset(&userSignals, sig); action.sa_handler = SIG_DFL; break; - case STG_SIG_HAN: case STG_SIG_RST: - signal_handlers[sig] = (StgInt)*handler; - sigaddset(&userSignals, sig); - action.sa_handler = generic_handler; - if (spi == STG_SIG_RST) { - action.sa_flags = SA_RESETHAND; - } - n_haskell_handlers++; + action.sa_flags |= SA_RESETHAND; + /* fall through */ + case STG_SIG_HAN: + action.sa_sigaction = generic_handler; + action.sa_flags |= SA_SIGINFO; break; default: @@ -336,25 +327,38 @@ stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask) action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0; - if (sigaction(sig, &action, NULL) || - sigprocmask(SIG_SETMASK, &osignals, NULL)) + if (sigaction(sig, &action, NULL)) { - // need to return an error code, so avoid a stable pointer leak - // by freeing the previous handler if there was one. - if (previous_spi >= 0) { - freeStablePtr(stgCast(StgStablePtr,signal_handlers[sig])); - n_haskell_handlers--; - } + errorBelch("sigaction"); return STG_SIG_ERR; } - if (previous_spi == STG_SIG_DFL || previous_spi == STG_SIG_IGN - || previous_spi == STG_SIG_ERR) { - return previous_spi; - } else { - *handler = (StgStablePtr)previous_spi; - return STG_SIG_HAN; + signal_handlers[sig] = spi; + + switch(spi) { + case STG_SIG_RST: + case STG_SIG_HAN: + sigaddset(&userSignals, sig); + if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) { + n_haskell_handlers++; + } + break; + + default: + sigdelset(&userSignals, sig); + if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) { + n_haskell_handlers--; + } + break; + } + + if (sigprocmask(SIG_SETMASK, &osignals, NULL)) + { + errorBelch("sigprocmask"); + return STG_SIG_ERR; } + + return previous_spi; } /* ----------------------------------------------------------------------------- @@ -365,16 +369,32 @@ stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask) void startSignalHandlers(Capability *cap) { + siginfo_t *info; + int sig; + blockUserSignals(); while (next_pending_handler != pending_handler_buf) { next_pending_handler--; + sig = next_pending_handler->si_signo; + if (signal_handlers[sig] == STG_SIG_DFL) { + continue; // handler has been changed. + } + + info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers"); + // freed by runHandler + memcpy(info, next_pending_handler, sizeof(siginfo_t)); + scheduleThread (cap, createIOThread(cap, RtsFlags.GcFlags.initialStkSize, - (StgClosure *) *next_pending_handler)); + rts_apply(cap, + rts_apply(cap, + &base_GHCziConc_runHandlers_closure, + rts_mkPtr(cap, info)), + rts_mkInt(cap, info->si_signo)))); } unblockUserSignals(); @@ -383,37 +403,18 @@ startSignalHandlers(Capability *cap) /* ---------------------------------------------------------------------------- * Mark signal handlers during GC. - * - * We do this rather than trying to start all the signal handlers - * prior to GC, because that requires extra heap for the new threads. - * Signals must be blocked (see blockUserSignals() above) during GC to - * avoid race conditions. * -------------------------------------------------------------------------- */ -#if !defined(THREADED_RTS) -void -markSignalHandlers (evac_fn evac, void *user) -{ - StgPtr *p; - - p = next_pending_handler; - while (p != pending_handler_buf) { - p--; - evac(user, (StgClosure **)p); - } -} -#else void markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED) { + // nothing to do } -#endif #else /* !RTS_USER_SIGNALS */ StgInt stg_sig_install(StgInt sig STG_UNUSED, StgInt spi STG_UNUSED, - StgStablePtr* handler STG_UNUSED, void* mask STG_UNUSED) { //barf("User signals not supported"); diff --git a/rts/posix/Signals.h b/rts/posix/Signals.h index aa440b38aa..e1d550fdad 100644 --- a/rts/posix/Signals.h +++ b/rts/posix/Signals.h @@ -9,11 +9,15 @@ #ifndef POSIX_SIGNALS_H #define POSIX_SIGNALS_H +#ifdef HAVE_SIGNAL_H +# include <signal.h> +#endif + extern rtsBool anyUserHandlers(void); #if !defined(THREADED_RTS) -extern StgPtr pending_handler_buf[]; -extern StgPtr *next_pending_handler; +extern siginfo_t pending_handler_buf[]; +extern siginfo_t *next_pending_handler; #define signals_pending() (next_pending_handler != pending_handler_buf) void startSignalHandlers(Capability *cap); #endif |