Commit a62d5cd2 authored by sof's avatar sof
Browse files

[project @ 2002-02-12 15:38:08 by sof]

Snapshot (before heading into work):
- thread_ready_aux_mutex is no more; use sched_mutex instead.
- gc_pending_cond only used in SMP mode.
- document the condition that thread_ready_cond captures.
parent 3fa80568
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
* $Id: Schedule.c,v 1.120 2002/02/08 03:44:01 sof Exp $ * $Id: Schedule.c,v 1.121 2002/02/12 15:38:08 sof Exp $
* *
* (c) The GHC Team, 1998-2000 * (c) The GHC Team, 1998-2000
* *
...@@ -294,29 +294,32 @@ Mutex rts_mutex = INIT_MUTEX_VAR; ...@@ -294,29 +294,32 @@ Mutex rts_mutex = INIT_MUTEX_VAR;
*/ */
static nat threads_waiting = 0; static nat threads_waiting = 0;
/*
* thread_ready_aux_mutex is used to handle the scenario where the
* the RTS executing thread runs out of work, but there are
* active external threads. The RTS executing thread gives up
* its RTS mutex, and blocks waiting for the thread_ready_cond.
* Unfortunately, a condition variable needs to be associated
* with a mutex in pthreads, so rts_thread_waiting_mutex is
* used for just this purpose.
*
*/
Mutex thread_ready_aux_mutex = INIT_MUTEX_VAR;
#endif #endif
/* thread_ready_cond: when signalled, a thread has /* thread_ready_cond: when signalled, a thread has become runnable for a
* become runnable. When used? * task to execute.
*
* In the non-SMP case, it also implies that the thread that is woken up has
* exclusive access to the RTS and all its DS (that are not under sched_mutex's
* control).
*
* thread_ready_cond is signalled whenever COND_NO_THREADS_READY doesn't hold.
*
*/ */
Condition thread_ready_cond = INIT_COND_VAR; Condition thread_ready_cond = INIT_COND_VAR;
Condition gc_pending_cond = INIT_COND_VAR; #if 0
/* For documentation purposes only */
#define COND_NO_THREADS_READY() (noCapabilities() || EMPTY_RUN_QUEUE())
#endif
#if defined(SMP)
Condition gc_pending_cond = INIT_COND_VAR;
nat await_death; nat await_death;
#endif #endif
#endif
#if defined(PAR) #if defined(PAR)
StgTSO *LastTSO; StgTSO *LastTSO;
rtsTime TimeOfLastYield; rtsTime TimeOfLastYield;
...@@ -621,9 +624,8 @@ schedule( void ) ...@@ -621,9 +624,8 @@ schedule( void )
* ToDo: what if another client comes along & requests another * ToDo: what if another client comes along & requests another
* main thread? * main thread?
*/ */
if (blocked_queue_hd != END_TSO_QUEUE || sleeping_queue != END_TSO_QUEUE) { if ( !EMPTY_QUEUE(blocked_queue_hd) || !EMPTY_QUEUE(sleeping_queue) ) {
awaitEvent( awaitEvent( EMPTY_RUN_QUEUE()
(run_queue_hd == END_TSO_QUEUE)
#if defined(SMP) #if defined(SMP)
&& allFreeCapabilities() && allFreeCapabilities()
#endif #endif
...@@ -644,13 +646,13 @@ schedule( void ) ...@@ -644,13 +646,13 @@ schedule( void )
* inform all the main threads. * inform all the main threads.
*/ */
#ifndef PAR #ifndef PAR
if (blocked_queue_hd == END_TSO_QUEUE if ( EMPTY_QUEUE(blocked_queue_hd)
&& run_queue_hd == END_TSO_QUEUE && EMPTY_RUN_QUEUE()
&& sleeping_queue == END_TSO_QUEUE && EMPTY_QUEUE(sleeping_queue)
#if defined(SMP) #if defined(SMP)
&& allFreeCapabilities() && allFreeCapabilities()
#elif defined(THREADED_RTS) #elif defined(THREADED_RTS)
&& suspended_ccalling_threads == END_TSO_QUEUE && EMPTY_QUEUE(suspended_ccalling_threads)
#endif #endif
) )
{ {
...@@ -659,9 +661,9 @@ schedule( void ) ...@@ -659,9 +661,9 @@ schedule( void )
GarbageCollect(GetRoots,rtsTrue); GarbageCollect(GetRoots,rtsTrue);
ACQUIRE_LOCK(&sched_mutex); ACQUIRE_LOCK(&sched_mutex);
IF_DEBUG(scheduler, sched_belch("GC done.")); IF_DEBUG(scheduler, sched_belch("GC done."));
if (blocked_queue_hd == END_TSO_QUEUE if ( EMPTY_QUEUE(blocked_queue_hd)
&& run_queue_hd == END_TSO_QUEUE && EMPTY_RUN_QUEUE()
&& sleeping_queue == END_TSO_QUEUE) { && EMPTY_QUEUE(sleeping_queue) ) {
IF_DEBUG(scheduler, sched_belch("still deadlocked, checking for black holes...")); IF_DEBUG(scheduler, sched_belch("still deadlocked, checking for black holes..."));
detectBlackHoles(); detectBlackHoles();
...@@ -671,7 +673,7 @@ schedule( void ) ...@@ -671,7 +673,7 @@ schedule( void )
* build, send *all* main threads the deadlock exception, * build, send *all* main threads the deadlock exception,
* since none of them can make progress). * since none of them can make progress).
*/ */
if (run_queue_hd == END_TSO_QUEUE) { if ( EMPTY_RUN_QUEUE() ) {
StgMainThread *m; StgMainThread *m;
#if defined(RTS_SUPPORTS_THREADS) #if defined(RTS_SUPPORTS_THREADS)
for (m = main_threads; m != NULL; m = m->link) { for (m = main_threads; m != NULL; m = m->link) {
...@@ -703,13 +705,13 @@ schedule( void ) ...@@ -703,13 +705,13 @@ schedule( void )
#endif #endif
} }
#if defined(RTS_SUPPORTS_THREADS) #if defined(RTS_SUPPORTS_THREADS)
if ( run_queue_hd == END_TSO_QUEUE ) { if ( EMPTY_RUN_QUEUE() ) {
IF_DEBUG(scheduler, sched_belch("all done, it seems...shut down.")); IF_DEBUG(scheduler, sched_belch("all done, it seems...shut down."));
shutdownHaskellAndExit(0); shutdownHaskellAndExit(0);
} }
#endif #endif
ASSERT( run_queue_hd != END_TSO_QUEUE ); ASSERT( !EMPTY_RUN_QUEUE() );
} }
} }
#elif defined(PAR) #elif defined(PAR)
...@@ -730,26 +732,22 @@ schedule( void ) ...@@ -730,26 +732,22 @@ schedule( void )
/* block until we've got a thread on the run queue and a free /* block until we've got a thread on the run queue and a free
* capability. * capability.
*/ */
while ( run_queue_hd == END_TSO_QUEUE while ( noCapabilities() || EMPTY_RUN_QUEUE() ) {
|| noFreeCapabilities()
) {
IF_DEBUG(scheduler, sched_belch("waiting for work")); IF_DEBUG(scheduler, sched_belch("waiting for work"));
waitCondition( &thread_ready_cond, &sched_mutex ); waitCondition( &thread_ready_cond, &sched_mutex );
IF_DEBUG(scheduler, sched_belch("work now available")); IF_DEBUG(scheduler, sched_belch("work now available"));
} }
#elif defined(THREADED_RTS) #elif defined(THREADED_RTS)
if ( run_queue_hd == END_TSO_QUEUE ) { if ( EMPTY_RUN_QUEUErun_queue_hd == END_TSO_QUEUE ) {
/* no work available, wait for external calls to complete. */ /* no work available, wait for external calls to complete. */
IF_DEBUG(scheduler, sched_belch("worker thread (%d): waiting for external thread to complete..", osThreadId())); IF_DEBUG(scheduler, sched_belch("worker thread (%d): waiting for external thread to complete..", osThreadId()));
taskAvailable(); taskAvailable();
RELEASE_LOCK(&sched_mutex);
RELEASE_LOCK(&rts_mutex); RELEASE_LOCK(&rts_mutex);
/* Sigh - need to have a mutex locked in order to wait on the while ( EMPTY_RUN_QUEUE() ) {
condition variable. */ waitCondition(&thread_ready_cond, &sched_mutex);
ACQUIRE_LOCK(&thread_ready_aux_mutex); };
waitCondition(&thread_ready_cond, &thread_ready_aux_mutex); RELEASE_LOCK(&sched_mutex);
RELEASE_LOCK(&thread_ready_aux_mutex);
IF_DEBUG(scheduler, sched_belch("worker thread (%d): re-awakened from no-work slumber..\n", osThreadId())); IF_DEBUG(scheduler, sched_belch("worker thread (%d): re-awakened from no-work slumber..\n", osThreadId()));
/* ToDo: longjmp() */ /* ToDo: longjmp() */
...@@ -1539,8 +1537,9 @@ suspendThread( StgRegTable *reg ) ...@@ -1539,8 +1537,9 @@ suspendThread( StgRegTable *reg )
#endif #endif
THREAD_RUNNABLE();
RELEASE_LOCK(&sched_mutex); RELEASE_LOCK(&sched_mutex);
RELEASE_LOCK(&rts_mutex); // RELEASE_LOCK(&rts_mutex);
return tok; return tok;
} }
...@@ -1584,8 +1583,8 @@ resumeThread( StgInt tok ) ...@@ -1584,8 +1583,8 @@ resumeThread( StgInt tok )
} }
tso->link = END_TSO_QUEUE; tso->link = END_TSO_QUEUE;
#if defined(SMP) #if defined(RTS_SUPPORTS_THREADS)
while ( noFreeCapabilities() ) { while ( noCapabilities() ) {
IF_DEBUG(scheduler, sched_belch("waiting to resume")); IF_DEBUG(scheduler, sched_belch("waiting to resume"));
waitCondition(&thread_ready_cond, &sched_mutex); waitCondition(&thread_ready_cond, &sched_mutex);
IF_DEBUG(scheduler, sched_belch("resuming thread %d", tso->id)); IF_DEBUG(scheduler, sched_belch("resuming thread %d", tso->id));
...@@ -1976,14 +1975,14 @@ initScheduler(void) ...@@ -1976,14 +1975,14 @@ initScheduler(void)
#if defined(RTS_SUPPORTS_THREADS) #if defined(RTS_SUPPORTS_THREADS)
/* Initialise the mutex and condition variables used by /* Initialise the mutex and condition variables used by
* the scheduler. */ * the scheduler. */
initMutex(&rts_mutex);
initMutex(&sched_mutex); initMutex(&sched_mutex);
initMutex(&term_mutex); initMutex(&term_mutex);
initCondition(&thread_ready_cond);
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
initMutex(&thread_ready_aux_mutex); initMutex(&rts_mutex);
#endif #endif
initCondition(&thread_ready_cond);
initCondition(&gc_pending_cond); initCondition(&gc_pending_cond);
#endif #endif
......
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