X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=rts%2Fposix%2FSignals.c;h=660065734b84ff07dbc8442edb9603092f1897fe;hp=e34190c4393790f80c6880a2835a8af1382b3b55;hb=a2a67cd520b9841114d69a87a423dabcb3b4368e;hpb=addff19a9c6ee89e36cb966988aa9f868ae2e4a6 diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c index e34190c..6600657 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) @@ -35,7 +32,12 @@ # include #endif +#ifdef HAVE_ERRNO_H +# include +#endif + #include +#include /* 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 +62,7 @@ static nat n_haskell_handlers = 0; * -------------------------------------------------------------------------- */ static void -more_handlers(I_ sig) +more_handlers(int sig) { StgInt i; @@ -79,33 +81,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; @@ -117,27 +92,35 @@ setIOManagerPipe (int fd) { // only called when THREADED_RTS, but unconditionally // compiled here because GHC.Conc depends on it. - io_manager_pipe = fd; + if (io_manager_pipe < 0) { + io_manager_pipe = 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) { StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP; - write(io_manager_pipe, &byte, 1); + r = write(io_manager_pipe, &byte, 1); + if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); } } } void ioManagerDie (void) { + int r; // Ask the IO Manager thread to exit if (io_manager_pipe >= 0) { StgWord8 byte = (StgWord8)IO_MANAGER_DIE; - write(io_manager_pipe, &byte, 1); + r = write(io_manager_pipe, &byte, 1); + if (r == -1) { sysErrorBelch("ioManagerDie: write"); } + close(io_manager_pipe); + io_manager_pipe = -1; } } @@ -148,7 +131,7 @@ ioManagerStart (void) Capability *cap; if (io_manager_pipe < 0) { cap = rts_lock(); - rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL); + cap = rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL); rts_unlock(cap); } } @@ -158,8 +141,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,18 +154,24 @@ 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; - #if defined(THREADED_RTS) 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 +207,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]) { @@ -226,14 +217,9 @@ generic_handler(int sig) stg_exit(EXIT_FAILURE); } -#endif /* THREADED_RTS */ - - // re-establish the signal handler, and carry on - sigemptyset(&signals); - sigaddset(&signals, sig); - sigprocmask(SIG_UNBLOCK, &signals, NULL); + contextSwitchCapability(&MainCapability); - context_switch = 1; +#endif /* THREADED_RTS */ } /* ----------------------------------------------------------------------------- @@ -247,6 +233,10 @@ void initUserSignals(void) { sigemptyset(&userSignals); +#ifndef THREADED_RTS + getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure); + // needed to keep runHandler alive +#endif } void @@ -279,10 +269,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 +297,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 +323,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 +365,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 +399,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");