[project @ 2001-10-31 10:34:29 by simonmar]
[ghc-hetmet.git] / ghc / rts / Schedule.c
index 5451cc5..35b9b79 100644 (file)
@@ -1,5 +1,5 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.95 2001/03/23 16:36:21 simonmar Exp $
+ * $Id: Schedule.c,v 1.104 2001/10/31 10:34:29 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -74,6 +74,7 @@
 //@node Includes, Variables and Data structures, Main scheduling code, Main scheduling code
 //@subsection Includes
 
+#include "PosixSource.h"
 #include "Rts.h"
 #include "SchedAPI.h"
 #include "RtsUtils.h"
@@ -81,7 +82,6 @@
 #include "Storage.h"
 #include "StgRun.h"
 #include "StgStartup.h"
-#include "GC.h"
 #include "Hooks.h"
 #include "Schedule.h"
 #include "StgMiscClosures.h"
@@ -181,7 +181,7 @@ StgTSO *all_threads;
  */
 static StgTSO *suspended_ccalling_threads;
 
-static void GetRoots(void);
+static void GetRoots(evac_fn);
 static StgTSO *threadStackOverflow(StgTSO *tso);
 
 /* KH: The following two flags are shared memory locations.  There is no need
@@ -445,6 +445,7 @@ schedule( void )
          pthread_cond_broadcast(&m->wakeup);
          break;
        case ThreadKilled:
+         if (m->ret) *(m->ret) = NULL;
          *prev = m->link;
          if (was_interrupted) {
            m->stat = Interrupted;
@@ -477,6 +478,7 @@ schedule( void )
          m->stat = Success;
          return;
        } else {
+         if (m->ret) { *(m->ret) = NULL; };
          if (was_interrupted) {
            m->stat = Interrupted;
          } else {
@@ -527,6 +529,13 @@ schedule( void )
     }
 #endif /* SMP */
 
+    /* check for signals each time around the scheduler */
+#ifndef mingw32_TARGET_OS
+    if (signals_pending()) {
+      startSignalHandlers();
+    }
+#endif
+
     /* Check whether any waiting threads need to be woken up.  If the
      * run queue is empty, and there are no other tasks running, we
      * can wait indefinitely for something to happen.
@@ -544,13 +553,6 @@ schedule( void )
     /* we can be interrupted while waiting for I/O... */
     if (interrupted) continue;
 
-    /* check for signals each time around the scheduler */
-#ifndef mingw32_TARGET_OS
-    if (signals_pending()) {
-      start_signal_handlers();
-    }
-#endif
-
     /* 
      * Detect deadlock: when we have no threads to run, there are no
      * threads waiting on I/O or sleeping, and all the other tasks are
@@ -562,41 +564,44 @@ schedule( void )
      * If no threads are black holed, we have a deadlock situation, so
      * inform all the main threads.
      */
-#ifdef SMP
+#ifndef PAR
     if (blocked_queue_hd == END_TSO_QUEUE
        && run_queue_hd == END_TSO_QUEUE
        && sleeping_queue == END_TSO_QUEUE
-       && (n_free_capabilities == RtsFlags.ParFlags.nNodes))
+#ifdef SMP
+       && (n_free_capabilities == RtsFlags.ParFlags.nNodes)
+#endif
+       )
     {
-       IF_DEBUG(scheduler, sched_belch("deadlocked, checking for black holes..."));
-       detectBlackHoles();
-       if (run_queue_hd == END_TSO_QUEUE) {
-           StgMainThread *m;
-           for (m = main_threads; m != NULL; m = m->link) {
+       IF_DEBUG(scheduler, sched_belch("deadlocked, forcing major GC..."));
+       GarbageCollect(GetRoots,rtsTrue);
+       if (blocked_queue_hd == END_TSO_QUEUE
+           && run_queue_hd == END_TSO_QUEUE
+           && sleeping_queue == END_TSO_QUEUE) {
+           IF_DEBUG(scheduler, sched_belch("still deadlocked, checking for black holes..."));
+           detectBlackHoles();
+           if (run_queue_hd == END_TSO_QUEUE) {
+               StgMainThread *m = main_threads;
+#ifdef SMP
+               for (; m != NULL; m = m->link) {
+                   deleteThread(m->tso);
+                   m->ret = NULL;
+                   m->stat = Deadlock;
+                   pthread_cond_broadcast(&m->wakeup);
+               }
+               main_threads = NULL;
+#else
+               deleteThread(m->tso);
                m->ret = NULL;
                m->stat = Deadlock;
-               pthread_cond_broadcast(&m->wakeup);
+               main_threads = m->link;
+               return;
+#endif
            }
-           main_threads = NULL;
        }
     }
 #elif defined(PAR)
     /* ToDo: add deadlock detection in GUM (similar to SMP) -- HWL */
-#else /* ! SMP */
-    if (blocked_queue_hd == END_TSO_QUEUE
-       && run_queue_hd == END_TSO_QUEUE
-       && sleeping_queue == END_TSO_QUEUE)
-    {
-       IF_DEBUG(scheduler, sched_belch("deadlocked, checking for black holes..."));
-       detectBlackHoles();
-       if (run_queue_hd == END_TSO_QUEUE) {
-           StgMainThread *m = main_threads;
-           m->ret = NULL;
-           m->stat = Deadlock;
-           main_threads = m->link;
-           return;
-       }
-    }
 #endif
 
 #ifdef SMP
@@ -910,7 +915,7 @@ schedule( void )
 #else
     cap = &MainRegTable;
 #endif
-    
+
     cap->rCurrentTSO = t;
     
     /* context switches are now initiated by the timer signal, unless
@@ -1394,6 +1399,16 @@ int cmp_thread(const StgTSO *tso1, const StgTSO *tso2)
 }
 
 /* ---------------------------------------------------------------------------
+ * Fetching the ThreadID from an StgTSO.
+ *
+ * This is used in the implementation of Show for ThreadIds.
+ * ------------------------------------------------------------------------ */
+int rts_getThreadId(const StgTSO *tso) 
+{
+  return tso->id;
+}
+
+/* ---------------------------------------------------------------------------
    Create a new thread.
 
    The new thread starts with the given stack size.  Before the
@@ -2092,7 +2107,8 @@ take_off_run_queue(StgTSO *tso) {
        KH @ 25/10/99
 */
 
-static void GetRoots(void)
+static void
+GetRoots(evac_fn evac)
 {
   StgMainThread *m;
 
@@ -2101,16 +2117,16 @@ static void GetRoots(void)
     nat i;
     for (i=0; i<=RtsFlags.GranFlags.proc; i++) {
       if ((run_queue_hds[i] != END_TSO_QUEUE) && ((run_queue_hds[i] != NULL)))
-       run_queue_hds[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_hds[i]);
+         evac((StgClosure **)&run_queue_hds[i]);
       if ((run_queue_tls[i] != END_TSO_QUEUE) && ((run_queue_tls[i] != NULL)))
-       run_queue_tls[i]    = (StgTSO *)MarkRoot((StgClosure *)run_queue_tls[i]);
+         evac((StgClosure **)&run_queue_tls[i]);
       
       if ((blocked_queue_hds[i] != END_TSO_QUEUE) && ((blocked_queue_hds[i] != NULL)))
-       blocked_queue_hds[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hds[i]);
+         evac((StgClosure **)&blocked_queue_hds[i]);
       if ((blocked_queue_tls[i] != END_TSO_QUEUE) && ((blocked_queue_tls[i] != NULL)))
-       blocked_queue_tls[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tls[i]);
+         evac((StgClosure **)&blocked_queue_tls[i]);
       if ((ccalling_threadss[i] != END_TSO_QUEUE) && ((ccalling_threadss[i] != NULL)))
-       ccalling_threadss[i] = (StgTSO *)MarkRoot((StgClosure *)ccalling_threadss[i]);
+         evac((StgClosure **)&ccalling_threads[i]);
     }
   }
 
@@ -2118,31 +2134,31 @@ static void GetRoots(void)
 
 #else /* !GRAN */
   if (run_queue_hd != END_TSO_QUEUE) {
-    ASSERT(run_queue_tl != END_TSO_QUEUE);
-    run_queue_hd      = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
-    run_queue_tl      = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
+      ASSERT(run_queue_tl != END_TSO_QUEUE);
+      evac((StgClosure **)&run_queue_hd);
+      evac((StgClosure **)&run_queue_tl);
   }
-
+  
   if (blocked_queue_hd != END_TSO_QUEUE) {
-    ASSERT(blocked_queue_tl != END_TSO_QUEUE);
-    blocked_queue_hd  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
-    blocked_queue_tl  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
+      ASSERT(blocked_queue_tl != END_TSO_QUEUE);
+      evac((StgClosure **)&blocked_queue_hd);
+      evac((StgClosure **)&blocked_queue_tl);
   }
-
+  
   if (sleeping_queue != END_TSO_QUEUE) {
-    sleeping_queue  = (StgTSO *)MarkRoot((StgClosure *)sleeping_queue);
+      evac((StgClosure **)&sleeping_queue);
   }
 #endif 
 
   for (m = main_threads; m != NULL; m = m->link) {
-    m->tso = (StgTSO *)MarkRoot((StgClosure *)m->tso);
+      evac((StgClosure **)&m->tso);
+  }
+  if (suspended_ccalling_threads != END_TSO_QUEUE) {
+      evac((StgClosure **)&suspended_ccalling_threads);
   }
-  if (suspended_ccalling_threads != END_TSO_QUEUE)
-    suspended_ccalling_threads = 
-      (StgTSO *)MarkRoot((StgClosure *)suspended_ccalling_threads);
 
 #if defined(SMP) || defined(PAR) || defined(GRAN)
-  markSparkQueue();
+  markSparkQueue(evac);
 #endif
 }
 
@@ -2159,7 +2175,7 @@ static void GetRoots(void)
    This needs to be protected by the GC condition variable above.  KH.
    -------------------------------------------------------------------------- */
 
-void (*extra_roots)(void);
+void (*extra_roots)(evac_fn);
 
 void
 performGC(void)
@@ -2174,17 +2190,16 @@ performMajorGC(void)
 }
 
 static void
-AllRoots(void)
+AllRoots(evac_fn evac)
 {
-  GetRoots();                  /* the scheduler's roots */
-  extra_roots();               /* the user's roots */
+    GetRoots(evac);            // the scheduler's roots
+    extra_roots(evac);         // the user's roots
 }
 
 void
-performGCWithRoots(void (*get_roots)(void))
+performGCWithRoots(void (*get_roots)(evac_fn))
 {
   extra_roots = get_roots;
-
   GarbageCollect(AllRoots,rtsFalse);
 }
 
@@ -2247,7 +2262,7 @@ threadStackOverflow(StgTSO *tso)
   dest->stack_size = new_stack_size;
        
   /* and relocate the update frame list */
-  relocate_TSO(tso, dest);
+  relocate_stack(dest, diff);
 
   /* Mark the old TSO as relocated.  We have to check for relocated
    * TSOs in the garbage collector and any primops that deal with TSOs.
@@ -2921,7 +2936,7 @@ raiseAsync(StgTSO *tso, StgClosure *exception)
   }
 
   while (1) {
-    int words = ((P_)su - (P_)sp) - 1;
+    nat words = ((P_)su - (P_)sp) - 1;
     nat i;
     StgAP_UPD * ap;