Repository : ssh://darcs.haskell.org//srv/darcs/ghc

On branch  : master

http://hackage.haskell.org/trac/ghc/changeset/a006ecdfd381fa75ab16ddb66c3a2b247f359eb8

>---------------------------------------------------------------

commit a006ecdfd381fa75ab16ddb66c3a2b247f359eb8
Author: Simon Marlow <marlo...@gmail.com>
Date:   Tue Dec 18 09:10:26 2012 +0000

    A better fix for #7493 (see comment for details)

>---------------------------------------------------------------

 rts/STM.c |   60 ++++++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/rts/STM.c b/rts/STM.c
index 0a4d0b2..62ced25 100644
--- a/rts/STM.c
+++ b/rts/STM.c
@@ -705,32 +705,56 @@ static void merge_update_into(Capability *cap,
 /*......................................................................*/
 
 static void merge_read_into(Capability *cap,
-                           StgTRecHeader *t,
+                            StgTRecHeader *trec,
                            StgTVar *tvar,
-                           StgClosure *expected_value) {
+                            StgClosure *expected_value)
+{
   int found;
+  StgTRecHeader *t;
   
-  // Look for an entry in this trec
   found = FALSE;
-  FOR_EACH_ENTRY(t, e, {
-    StgTVar *s;
-    s = e -> tvar;
-    if (s == tvar) {
-      found = TRUE;
-      if (e -> expected_value != expected_value) {
-        // Must abort if the two entries start from different values
-        TRACE("%p : read entries inconsistent at %p (%p vs %p)", 
-              t, tvar, e -> expected_value, expected_value);
-        t -> state = TREC_CONDEMNED;
+
+  //
+  // See #7493
+  //
+  // We need to look for an existing entry *anywhere* in the stack of
+  // nested transactions.  Otherwise, in stmCommitNestedTransaction()
+  // we can't tell the difference between
+  //
+  //   (1) a read-only entry
+  //   (2) an entry that writes back the original value
+  //
+  // Since in both cases e->new_value == e->expected_value. But in (1)
+  // we want to do nothing, and in (2) we want to update e->new_value
+  // in the outer transaction.
+  //
+  // Here we deal with the first possibility: we never create a
+  // read-only entry in an inner transaction if there is an existing
+  // outer entry; so we never have an inner read and an outer update.
+  // So then in stmCommitNestedTransaction() we know we can always
+  // write e->new_value over the outer entry, because the inner entry
+  // is the most up to date.
+  //
+  for (t = trec; !found && t != NO_TREC; t = t -> enclosing_trec)
+  {
+    FOR_EACH_ENTRY(t, e, {
+      if (e -> tvar == tvar) {
+        found = TRUE;
+        if (e -> expected_value != expected_value) {
+            // Must abort if the two entries start from different values
+            TRACE("%p : read entries inconsistent at %p (%p vs %p)",
+                  t, tvar, e -> expected_value, expected_value);
+            t -> state = TREC_CONDEMNED;
+        }
+        BREAK_FOR_EACH;
       } 
-      BREAK_FOR_EACH;
-    }
-  });
+    });
+  }
 
   if (!found) {
-    // No entry so far in this trec
+    // No entry found
     TRecEntry *ne;
-    ne = get_new_entry(cap, t);
+    ne = get_new_entry(cap, trec);
     ne -> tvar = tvar;
     ne -> expected_value = expected_value;
     ne -> new_value = expected_value;



_______________________________________________
Cvs-ghc mailing list
Cvs-ghc@haskell.org
http://www.haskell.org/mailman/listinfo/cvs-ghc

Reply via email to