summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Marlow <simonmar@microsoft.com>2006-05-24 12:28:39 +0000
committerSimon Marlow <simonmar@microsoft.com>2006-05-24 12:28:39 +0000
commit7a1f8fbdbab99465793c50bd9fb376c950e7e9d7 (patch)
tree04e40cc95c37d452ed26ca9909b1ff97abe8aeac
parent3065ea2499deee8d4152eaf0804cc92c7217a2ba (diff)
downloadhaskell-7a1f8fbdbab99465793c50bd9fb376c950e7e9d7.tar.gz
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.
-rw-r--r--rts/Prelude.h4
-rw-r--r--rts/RtsStartup.c8
-rw-r--r--rts/Timer.c8
-rw-r--r--rts/package.conf.in8
-rw-r--r--rts/posix/Signals.c38
-rw-r--r--rts/posix/Signals.h6
6 files changed, 71 insertions, 1 deletions
diff --git a/rts/Prelude.h b/rts/Prelude.h
index c209b2b800..35d62b2310 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 147de7b857..71978007f3 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 0bfea2d6fd..4b13be4556 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 935b71d6a6..293d2a3b47 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 5f5f77fd39..2303d9f89b 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 39477f8c6a..b005abb5b5 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;