Re: [GHC] #13615: Nondeterminism in ‘pure’ function w/ parallel evaluation & memo combinators
GHC
ghc-devs at haskell.org
Sun Jun 25 00:45:20 UTC 2017
#13615: Nondeterminism in ‘pure’ function w/ parallel evaluation & memo combinators
-------------------------------------+-------------------------------------
Reporter: pacak | Owner: bgamari
Type: bug | Status: new
Priority: highest | Milestone: 8.2.1
Component: Compiler | Version: 7.10.3
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
Type of failure: Incorrect result | Unknown/Multiple
at runtime | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by bgamari):
I have confirmed that we indeed hit the codepath in `raiseAsync`
responsible for updating the thunk under evaluation. I believe this fills
the final question in comment:36.
To recap, what is happening is the following,
1. Thread A enters a `fromListWith` closure and begins folding over the
insertions
2. At some point during this fold we need to garbage collect (usually due
to a stack overflow, judging from the eventlog); the garbage collector
construct an `AP_STACK` closure capturing the state of Thread A, including
the partially-finished `fromListWith` computation. The `fromListWith`
thunk is updated to point to this `AP_STACK`.
3. Garbage collection commences and finishes, evaluation resumes
4. At some point Thread A is resumed, entering the previously saved
`AP_STACK` computation which we prepared in step (2); we are blackholing
lazily so no update to the `AP_STACK` closure is made
5. At some later point Thread B tries to force the same `AP_STACK`
computation; finding that it's not blackholed, it enters
We now have two mutator threads performing evaluation on the same,
effectful computation with shared, mutable state.
My first intuition says that the easiest way to avoid this would be to
unconditionally eagerly blackhole `AP_STACK`s. I believe this can be done
straightforwardly,
{{{#!diff
diff --git a/rts/Apply.cmm b/rts/Apply.cmm
index f14bb8f331..a35b41e5b0 100644
--- a/rts/Apply.cmm
+++ b/rts/Apply.cmm
@@ -464,6 +464,16 @@ INFO_TABLE(stg_AP_STACK,/*special
layout*/0,0,AP_STACK,"AP_STACK","AP_STACK")
Words = StgAP_STACK_size(ap);
+ W_ old_info;
+ (old_info) = prim %cmpxchgW(ap, stg_AP_STACK_info, stg_WHITEHOLE_info);
+ if (old_info != stg_AP_STACK_info) {
+ /* someone else beat us to it */
+ jump ENTRY_LBL(stg_WHITEHOLE) (ap);
+ }
+ StgInd_indirectee(ap) = CurrentTSO;
+ W_[ap] = stg_EAGER_BLACKHOLE_info;
+
/*
* Check for stack overflow. IMPORTANT: use a _ENTER check here,
* because if the check fails, we might end up blackholing this very
}}}
However, in doing this I'm seeing `<<loops>>` in the testcase. I haven't
yet worked out why.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13615#comment:45>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list