[project @ 2002-09-25 14:46:31 by simonmar]
authorsimonmar <unknown>
Wed, 25 Sep 2002 14:46:34 +0000 (14:46 +0000)
committersimonmar <unknown>
Wed, 25 Sep 2002 14:46:34 +0000 (14:46 +0000)
Fix a scheduling/GC bug, spotted by Wolfgang Thaller.  If a main
thread completes, and a GC runs before the return (from rts_evalIO())
happens, then the thread might be GC'd before we get a chance to
extract its return value, leading to barf("main thread has been GC'd")
from the garbage collector.

The fix is to treat all main threads which have completed as roots:
this is logically the right thing to do, because these threads must be
retained by virtue of holding the return value, and this is a property of
main threads only.

ghc/rts/GC.c
ghc/rts/Schedule.c

index c0e1a4a..853d548 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.143 2002/09/18 06:34:07 mthomas Exp $
+ * $Id: GC.c,v 1.144 2002/09/25 14:46:34 simonmar Exp $
  *
  * (c) The GHC Team 1998-1999
  *
@@ -1306,14 +1306,17 @@ isAlive(StgClosure *p)
     if (LOOKS_LIKE_STATIC(p) || bd->gen_no > N) {
        return p;
     }
-    // large objects have an evacuated flag
+
+    // if it's a pointer into to-space, then we're done
+    if (bd->flags & BF_EVACUATED) {
+       return p;
+    }
+
+    // large objects use the evacuated flag
     if (bd->flags & BF_LARGE) {
-       if (bd->flags & BF_EVACUATED) {
-           return p;
-       } else {
-           return NULL;
-       }
+       return NULL;
     }
+
     // check the mark bit for compacted steps
     if (bd->step->is_compacted && is_marked((P_)p,bd)) {
        return p;
index 6973954..9759b55 100644 (file)
@@ -1,5 +1,5 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.155 2002/09/18 06:34:07 mthomas Exp $
+ * $Id: Schedule.c,v 1.156 2002/09/25 14:46:31 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -2477,6 +2477,25 @@ GetRoots(evac_fn evac)
   // mark the signal handlers (signals should be already blocked)
   markSignalHandlers(evac);
 #endif
+
+  // main threads which have completed need to be retained until they
+  // are dealt with in the main scheduler loop.  They won't be
+  // retained any other way: the GC will drop them from the
+  // all_threads list, so we have to be careful to treat them as roots
+  // here.
+  { 
+      StgMainThread *m;
+      for (m = main_threads; m != NULL; m = m->link) {
+         switch (m->tso->what_next) {
+         case ThreadComplete:
+         case ThreadKilled:
+             evac((StgClosure **)&m->tso);
+             break;
+         default:
+             break;
+         }
+      }
+  }
 }
 
 /* -----------------------------------------------------------------------------