Better control of the IO manager thread; improvements to deadlock checking
authorSimon Marlow <simonmar@microsoft.com>
Wed, 24 May 2006 12:28:39 +0000 (12:28 +0000)
committerSimon Marlow <simonmar@microsoft.com>
Wed, 24 May 2006 12:28:39 +0000 (12:28 +0000)
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
rts/RtsStartup.c
rts/Timer.c
rts/package.conf.in
rts/posix/Signals.c
rts/posix/Signals.h

index c209b2b..35d62b2 100644 (file)
@@ -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);
index 147de7b..7197800 100644 (file)
@@ -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();
     
index 0bfea2d..4b13be4 100644 (file)
@@ -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:
index 935b71d..293d2a3 100644 (file)
@@ -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
index 5f5f77f..2303d9f 100644 (file)
@@ -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
index 39477f8..b005abb 100644 (file)
 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;