Commit 7a1f8fbd authored by Simon Marlow's avatar Simon Marlow
Browse files

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.
parent 3065ea24
......@@ -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);
......
......@@ -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();
......
......@@ -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:
......
......@@ -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
......
......@@ -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
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment