[project @ 2004-05-27 15:18:31 by simonmar]
authorsimonmar <unknown>
Thu, 27 May 2004 15:18:31 +0000 (15:18 +0000)
committersimonmar <unknown>
Thu, 27 May 2004 15:18:31 +0000 (15:18 +0000)
Fix a nasty bug: when saving errno in the TSO after running a thread,
beware that the TSO might have moved, e.g. if the thread made a safe
foreign call in the threaded RTS and a GC happened.

We have to grab the new location of the TSO *before* saving errno.

MERGE TO STABLE

This was the most interesting bug hunt I've had in a while.  The crash
only showed up in about 1 in 4 runs of a program with 1000 Haskell
threads, running on the threaded RTS.  To make things worse, gdb
doesn't support watchpoints in programs with multiple threads... :-/

ghc/rts/Schedule.c

index e20eae2..9f5a7cc 100644 (file)
@@ -1,5 +1,5 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.196 2004/05/06 12:20:04 wolfgang Exp $
+ * $Id: Schedule.c,v 1.197 2004/05/27 15:18:31 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2003
  *
@@ -395,7 +395,7 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
 
 #endif
 
-     IF_DEBUG(scheduler, printAllThreads());
+//     IF_DEBUG(scheduler, printAllThreads());
 
 #if defined(RTS_SUPPORTS_THREADS)
       // Yield the capability to higher-priority tasks if necessary.
@@ -897,23 +897,35 @@ run_thread:
     /* Run the current thread 
      */
     prev_what_next = t->what_next;
+
+    errno = t->saved_errno;
+
     switch (prev_what_next) {
+
     case ThreadKilled:
     case ThreadComplete:
        /* Thread already finished, return to scheduler. */
        ret = ThreadFinished;
        break;
+
     case ThreadRunGHC:
-       errno = t->saved_errno;
        ret = StgRun((StgFunPtr) stg_returnToStackTop, &cap->r);
-       t->saved_errno = errno;
        break;
+
     case ThreadInterpret:
        ret = interpretBCO(cap);
        break;
+
     default:
       barf("schedule: invalid what_next field");
     }
+
+    // The TSO might have moved, so find the new location:
+    t = cap->r.rCurrentTSO;
+
+    // And save the current errno in this thread.
+    t->saved_errno = errno;
+
     /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
     
     /* Costs for the scheduler are assigned to CCS_SYSTEM */
@@ -929,7 +941,6 @@ run_thread:
 #elif !defined(GRAN) && !defined(PAR)
     IF_DEBUG(scheduler,fprintf(stderr,"sched: "););
 #endif
-    t = cap->r.rCurrentTSO;
     
 #if defined(PAR)
     /* HACK 675: if the last thread didn't yield, make sure to print a