From 7a1f8fbdbab99465793c50bd9fb376c950e7e9d7 Mon Sep 17 00:00:00 2001 From: Simon Marlow Date: Wed, 24 May 2006 12:28:39 +0000 Subject: [PATCH] Better control of the IO manager thread; improvements to deadlock checking In the threaded RTS on *nix platforms: - we now start the IO manager thread eagerly at startup time (previously was started on demand). - we now ask the IO manager thread to stop at shutdown - In Timer.c:handle_tick, if it looks like we might be in a deadlock, instead of calling prodOneCapability() which was known to be wrong, we now send a byte down the IO manager's pipe to wake it up. This also avoids a case of double-acquisition of a mutex, which happened if prodOneCapability() was called while the current thread was holding a mutex. --- rts/Prelude.h | 4 ++++ rts/RtsStartup.c | 8 ++++++++ rts/Timer.c | 8 ++++++++ rts/package.conf.in | 8 ++++++++ rts/posix/Signals.c | 38 ++++++++++++++++++++++++++++++++++++++ rts/posix/Signals.h | 6 +++++- 6 files changed, 71 insertions(+), 1 deletion(-) diff --git a/rts/Prelude.h b/rts/Prelude.h index c209b2b..35d62b2 100644 --- a/rts/Prelude.h +++ b/rts/Prelude.h @@ -42,6 +42,10 @@ PRELUDE_CLOSURE(GHCziIOBase_BlockedIndefinitely_closure); PRELUDE_CLOSURE(GHCziIOBase_NonTermination_closure); PRELUDE_CLOSURE(GHCziIOBase_NestedAtomically_closure); +#if !defined(mingw32_HOST_OS) +PRELUDE_CLOSURE(GHCziConc_ensureIOManagerIsRunning_closure); +#endif + PRELUDE_INFO(GHCziBase_Czh_static_info); PRELUDE_INFO(GHCziBase_Izh_static_info); PRELUDE_INFO(GHCziFloat_Fzh_static_info); diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index 147de7b..7197800 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -228,6 +228,10 @@ hs_init(int *argc, char **argv[]) x86_init_fpu(); #endif +#if defined(THREADED_RTS) && !defined(mingw32_HOST_OS) + ioManagerStart(); +#endif + /* Record initialization times */ stat_endInit(); } @@ -325,6 +329,10 @@ hs_exit(void) /* start timing the shutdown */ stat_startExit(); +#if defined(THREADED_RTS) && !defined(mingw32_HOST_OS) + ioManagerDie(); +#endif + /* stop all running tasks */ exitScheduler(); diff --git a/rts/Timer.c b/rts/Timer.c index 0bfea2d..4b13be4 100644 --- a/rts/Timer.c +++ b/rts/Timer.c @@ -21,6 +21,7 @@ #include "Timer.h" #include "Ticker.h" #include "Capability.h" +#include "RtsSignals.h" /* ticks left before next pre-emptive context switch */ static int ticks_to_ctxt_switch = 0; @@ -71,12 +72,19 @@ handle_tick(int unused STG_UNUSED) blackholes_need_checking = rtsTrue; /* hack: re-use the blackholes_need_checking flag */ +#if !defined(mingw32_HOST_OS) + // This forces the IO Manager thread to wakeup, which will + // in turn ensure that some OS thread wakes up and runs the + // scheduler loop, which will cause a GC and deadlock check. + ioManagerWakeup(); +#else /* ToDo: this doesn't work. Can't invoke * pthread_cond_signal from a signal handler. * Furthermore, we can't prod a capability that we * might be holding. What can we do? */ prodOneCapability(); +#endif } break; default: diff --git a/rts/package.conf.in b/rts/package.conf.in index 935b71d..293d2a3 100644 --- a/rts/package.conf.in +++ b/rts/package.conf.in @@ -139,6 +139,14 @@ ld-options: , "-u", "GHCziWeak_runFinalizzerBatch_closure" #endif +#ifndef mingw32_HOST_OS +#ifdef LEADING_UNDERSCORE + , "-u", "_GHCziConc_ensureIOManagerIsRunning_closure" +#else + , "-u", "GHCziConc_ensureIOManagerIsRunning_closure" +#endif +#endif + framework-dirs: #ifdef HAVE_FRAMEWORK_GMP diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c index 5f5f77f..2303d9f 100644 --- a/rts/posix/Signals.c +++ b/rts/posix/Signals.c @@ -16,6 +16,7 @@ #include "posix/Signals.h" #include "RtsUtils.h" #include "RtsFlags.h" +#include "Prelude.h" #ifdef alpha_HOST_ARCH # if defined(linux_HOST_OS) @@ -107,6 +108,9 @@ more_handlers(I_ sig) // Here's the pipe into which we will send our signals static int io_manager_pipe = -1; +#define IO_MANAGER_WAKEUP 0xff +#define IO_MANAGER_DIE 0xfe + void setIOManagerPipe (int fd) { @@ -115,6 +119,40 @@ setIOManagerPipe (int fd) io_manager_pipe = fd; } +#if defined(THREADED_RTS) +void +ioManagerWakeup (void) +{ + // 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); + } +} + +void +ioManagerDie (void) +{ + // Ask the IO Manager thread to exit + if (io_manager_pipe >= 0) { + StgWord8 byte = (StgWord8)IO_MANAGER_DIE; + write(io_manager_pipe, &byte, 1); + } +} + +void +ioManagerStart (void) +{ + // Make sure the IO manager thread is running + Capability *cap; + if (io_manager_pipe < 0) { + cap = rts_lock(); + rts_evalIO(cap,&GHCziConc_ensureIOManagerIsRunning_closure,NULL); + rts_unlock(cap); + } +} +#endif + #if !defined(THREADED_RTS) #define N_PENDING_HANDLERS 16 diff --git a/rts/posix/Signals.h b/rts/posix/Signals.h index 39477f8..b005abb 100644 --- a/rts/posix/Signals.h +++ b/rts/posix/Signals.h @@ -12,12 +12,16 @@ extern rtsBool anyUserHandlers(void); #if !defined(THREADED_RTS) - extern StgPtr pending_handler_buf[]; extern StgPtr *next_pending_handler; #define signals_pending() (next_pending_handler != pending_handler_buf) void startSignalHandlers(Capability *cap); +#endif +#if defined(THREADED_RTS) +void ioManagerWakeup (void); +void ioManagerDie (void); +void ioManagerStart (void); #endif extern StgInt *signal_handlers; -- 1.7.10.4