More sched_mutex related cleanup & fixes; little bit
too delicate for my liking, this.
* Revert lock assumptions for raiseAsync(); now assumed
to run with sched_mutex held (as it mucks about with a
TSO).
* stodgily release / acquire sched_mutex around calls
to startSignalHandlers() (as is done in Signals.c)
* in the presence of user-installed signal handlers, the
MT-enabled RTS failed to shutdown -- all queues empty
causes a lone RTS worker thread to pause() waiting for
signals. This is not the right thing to do; I (temporarily?)
disabled this signal-wait fallback in MT mode and shut
down instead. We need to be clearer as to what is a shutdown
condition in MT mode.
* The use of sched_mutex to protect next_thread_id increments
is causing headaches; disabled in non-SMP mode right now until
I've figured out the pthreads-correct way of doing atomic
increments.
* There's still a ^C-related problem which causes the Haskell
handler to sometimes induce a SEGV when run. Feel free to debug :)
/* -----------------------------------------------------------------------------
/* -----------------------------------------------------------------------------
- * $Id: Exception.hc,v 1.24 2002/02/28 18:44:28 sof Exp $
+ * $Id: Exception.hc,v 1.25 2002/04/23 06:34:26 sof Exp $
*
* (c) The GHC Team, 1998-2000
*
*
* (c) The GHC Team, 1998-2000
*
*/
if (R1.t == CurrentTSO) {
SaveThreadState(); /* inline! */
*/
if (R1.t == CurrentTSO) {
SaveThreadState(); /* inline! */
- STGCALL2(raiseAsync, R1.t, R2.cl);
+ STGCALL2(raiseAsyncWithLock, R1.t, R2.cl);
if (CurrentTSO->what_next == ThreadKilled) {
R1.w = ThreadFinished;
JMP_(StgReturn);
if (CurrentTSO->what_next == ThreadKilled) {
R1.w = ThreadFinished;
JMP_(StgReturn);
barf("killThreadzh_fast");
}
} else {
barf("killThreadzh_fast");
}
} else {
- STGCALL2(raiseAsync, R1.t, R2.cl);
+ STGCALL2(raiseAsyncWithLock, R1.t, R2.cl);
}
JMP_(ENTRY_CODE(Sp[0]));
}
JMP_(ENTRY_CODE(Sp[0]));
/* -----------------------------------------------------------------------------
/* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.134 2002/04/19 10:25:00 simonmar Exp $
+ * $Id: GC.c,v 1.135 2002/04/23 06:34:27 sof Exp $
*
* (c) The GHC Team 1998-1999
*
*
* (c) The GHC Team 1998-1999
*
// start any pending finalizers
scheduleFinalizers(old_weak_ptr_list);
// start any pending finalizers
scheduleFinalizers(old_weak_ptr_list);
- ACQUIRE_LOCK(&sched_mutex);
-
// send exceptions to any threads which were about to die
resurrectThreads(resurrected_threads);
// send exceptions to any threads which were about to die
resurrectThreads(resurrected_threads);
+ ACQUIRE_LOCK(&sched_mutex);
+
// Update the stable pointer hash table.
updateStablePtrTable(major_gc);
// Update the stable pointer hash table.
updateStablePtrTable(major_gc);
/* ---------------------------------------------------------------------------
/* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.137 2002/04/13 05:33:02 sof Exp $
+ * $Id: Schedule.c,v 1.138 2002/04/23 06:34:27 sof Exp $
*
* (c) The GHC Team, 1998-2000
*
*
* (c) The GHC Team, 1998-2000
*
/* Check to see whether there are any worker threads
waiting to deposit external call results. If so,
yield our capability */
/* Check to see whether there are any worker threads
waiting to deposit external call results. If so,
yield our capability */
- yieldToReturningWorker(&sched_mutex, cap);
+ yieldToReturningWorker(&sched_mutex, &cap);
#endif
/* If we're interrupted (the user pressed ^C, or some other
#endif
/* If we're interrupted (the user pressed ^C, or some other
/* check for signals each time around the scheduler */
#ifndef mingw32_TARGET_OS
if (signals_pending()) {
/* check for signals each time around the scheduler */
#ifndef mingw32_TARGET_OS
if (signals_pending()) {
+ RELEASE_LOCK(&sched_mutex); /* ToDo: kill */
+ ACQUIRE_LOCK(&sched_mutex);
* for signals to arrive rather then bombing out with a
* deadlock.
*/
* for signals to arrive rather then bombing out with a
* deadlock.
*/
+#if defined(RTS_SUPPORTS_THREADS)
+ if ( 0 ) { /* hmm..what to do? Simply stop waiting for
+ a signal with no runnable threads (or I/O
+ suspended ones) leads nowhere quick.
+ For now, simply shut down when we reach this
+ condition.
+
+ ToDo: define precisely under what conditions
+ the Scheduler should shut down in an MT setting.
+ */
+#else
if ( anyUserHandlers() ) {
if ( anyUserHandlers() ) {
IF_DEBUG(scheduler,
sched_belch("still deadlocked, waiting for signals..."));
IF_DEBUG(scheduler,
sched_belch("still deadlocked, waiting for signals..."));
if (interrupted) { continue; }
if (signals_pending()) {
if (interrupted) { continue; }
if (signals_pending()) {
+ RELEASE_LOCK(&sched_mutex);
+ ACQUIRE_LOCK(&sched_mutex);
}
ASSERT(!EMPTY_RUN_QUEUE());
goto not_deadlocked;
}
ASSERT(!EMPTY_RUN_QUEUE());
goto not_deadlocked;
for (m = main_threads; m != NULL; m = m->link) {
switch (m->tso->why_blocked) {
case BlockedOnBlackHole:
for (m = main_threads; m != NULL; m = m->link) {
switch (m->tso->why_blocked) {
case BlockedOnBlackHole:
- raiseAsyncWithLock(m->tso, (StgClosure *)NonTermination_closure);
+ raiseAsync(m->tso, (StgClosure *)NonTermination_closure);
break;
case BlockedOnException:
case BlockedOnMVar:
break;
case BlockedOnException:
case BlockedOnMVar:
- raiseAsyncWithLock(m->tso, (StgClosure *)Deadlock_closure);
+ raiseAsync(m->tso, (StgClosure *)Deadlock_closure);
break;
default:
barf("deadlock: main thread blocked in a strange way");
break;
default:
barf("deadlock: main thread blocked in a strange way");
m = main_threads;
switch (m->tso->why_blocked) {
case BlockedOnBlackHole:
m = main_threads;
switch (m->tso->why_blocked) {
case BlockedOnBlackHole:
- raiseAsyncWithLock(m->tso, (StgClosure *)NonTermination_closure);
+ raiseAsync(m->tso, (StgClosure *)NonTermination_closure);
break;
case BlockedOnException:
case BlockedOnMVar:
break;
case BlockedOnException:
case BlockedOnMVar:
- raiseAsyncWithLock(m->tso, (StgClosure *)Deadlock_closure);
+ raiseAsync(m->tso, (StgClosure *)Deadlock_closure);
break;
default:
barf("deadlock: main thread blocked in a strange way");
break;
default:
barf("deadlock: main thread blocked in a strange way");
*
* This is used when we catch a user interrupt (^C), before performing
* any necessary cleanups and running finalizers.
*
* This is used when we catch a user interrupt (^C), before performing
* any necessary cleanups and running finalizers.
+ *
+ * Locks: sched_mutex held.
* ------------------------------------------------------------------------- */
void deleteAllThreads ( void )
* ------------------------------------------------------------------------- */
void deleteAllThreads ( void )
/* Reset blocking status */
tso->why_blocked = NotBlocked;
/* Reset blocking status */
tso->why_blocked = NotBlocked;
- RELEASE_LOCK(&sched_mutex);
-
cap->r.rCurrentTSO = tso;
cap->r.rCurrentTSO = tso;
+ RELEASE_LOCK(&sched_mutex);
* protect the increment operation on next_thread_id.
* In future, we could use an atomic increment instead.
*/
* protect the increment operation on next_thread_id.
* In future, we could use an atomic increment instead.
*/
if (!have_lock) { ACQUIRE_LOCK(&sched_mutex); }
if (!have_lock) { ACQUIRE_LOCK(&sched_mutex); }
tso->id = next_thread_id++;
tso->id = next_thread_id++;
if (!have_lock) { RELEASE_LOCK(&sched_mutex); }
if (!have_lock) { RELEASE_LOCK(&sched_mutex); }
tso->why_blocked = NotBlocked;
tso->blocked_exceptions = NULL;
tso->why_blocked = NotBlocked;
tso->blocked_exceptions = NULL;
{
StgBlockingQueueElement *t, **last;
{
StgBlockingQueueElement *t, **last;
- ACQUIRE_LOCK(&sched_mutex);
switch (tso->why_blocked) {
case NotBlocked:
switch (tso->why_blocked) {
case NotBlocked:
tso->why_blocked = NotBlocked;
tso->block_info.closure = NULL;
PUSH_ON_RUN_QUEUE(tso);
tso->why_blocked = NotBlocked;
tso->block_info.closure = NULL;
PUSH_ON_RUN_QUEUE(tso);
- RELEASE_LOCK(&sched_mutex);
- ACQUIRE_LOCK(&sched_mutex);
switch (tso->why_blocked) {
case BlockedOnMVar:
switch (tso->why_blocked) {
case BlockedOnMVar:
tso->why_blocked = NotBlocked;
tso->block_info.closure = NULL;
PUSH_ON_RUN_QUEUE(tso);
tso->why_blocked = NotBlocked;
tso->block_info.closure = NULL;
PUSH_ON_RUN_QUEUE(tso);
- RELEASE_LOCK(&sched_mutex);
* CATCH_FRAME on the stack. In either case, we strip the entire
* stack and replace the thread with a zombie.
*
* CATCH_FRAME on the stack. In either case, we strip the entire
* stack and replace the thread with a zombie.
*
- * Locks: sched_mutex not held upon entry nor exit.
+ * Locks: sched_mutex held upon entry nor exit.
*
* -------------------------------------------------------------------------- */
*
* -------------------------------------------------------------------------- */
void
raiseAsyncWithLock(StgTSO *tso, StgClosure *exception)
{
void
raiseAsyncWithLock(StgTSO *tso, StgClosure *exception)
{
- /* When raising async exs from contexts where sched_mutex is held;
+ /* When raising async exs from contexts where sched_mutex isn't held;
use raiseAsyncWithLock(). */
use raiseAsyncWithLock(). */
- RELEASE_LOCK(&sched_mutex);
- raiseAsync(tso,exception);
ACQUIRE_LOCK(&sched_mutex);
ACQUIRE_LOCK(&sched_mutex);
+ raiseAsync(tso,exception);
+ RELEASE_LOCK(&sched_mutex);
case BlockedOnMVar:
case BlockedOnException:
/* Called by GC - sched_mutex lock is currently held. */
case BlockedOnMVar:
case BlockedOnException:
/* Called by GC - sched_mutex lock is currently held. */
- raiseAsyncWithLock(tso,(StgClosure *)BlockedOnDeadMVar_closure);
+ raiseAsync(tso,(StgClosure *)BlockedOnDeadMVar_closure);
break;
case BlockedOnBlackHole:
break;
case BlockedOnBlackHole:
- raiseAsyncWithLock(tso,(StgClosure *)NonTermination_closure);
+ raiseAsync(tso,(StgClosure *)NonTermination_closure);
break;
case NotBlocked:
/* This might happen if the thread was blocked on a black hole
break;
case NotBlocked:
/* This might happen if the thread was blocked on a black hole
*/
IF_DEBUG(scheduler,
sched_belch("thread %d is blocked on itself", t->id));
*/
IF_DEBUG(scheduler,
sched_belch("thread %d is blocked on itself", t->id));
- raiseAsyncWithLock(t, (StgClosure *)NonTermination_closure);
+ raiseAsync(t, (StgClosure *)NonTermination_closure);