Type inference seems to fall down with the rank-n type of
`forkWithUnmask` + `const`:
Control/Monad/Conc/Class.hs:525:27: error:
• Couldn't match type ‘b5’ with ‘forall a. m a -> m a’
Expected: (forall a. m a -> m a) -> m ()
Actual: b5 -> m ()
Cannot instantiate unification variable ‘b5’
with a type involving polytypes: forall a. m a -> m a
• In the first argument of ‘forkWithUnmask’, namely ‘(const ma)’
In the expression: forkWithUnmask (const ma)
In an equation for ‘fork’: fork ma = forkWithUnmask (const ma)
• Relevant bindings include
ma :: m () (bound at Control/Monad/Conc/Class.hs:525:6)
fork :: m () -> m (ThreadId m)
(bound at Control/Monad/Conc/Class.hs:525:1)
|
525 | fork ma = forkWithUnmask (const ma)
This adds the overhead of constructing the effect to every STM
transaction, which I worried would be a large cost; but it turns out
that the overhead is negligible.
This is for transactions which throw an exception, rather than
stuffing that information into the `STM` action. This makes the
traces a bit clearer (eg, you can now tell without needing to inspect
the STM trace if an exception was thrown by a transaction).
I've called this "ThrownSTM" rather than "ThrowSTM" because it's like
"BlockedSTM" (just another failure case), and that's also past tense.
In this excerpt:
uninterruptibleMask $ \restore -> fork $ do
result <- try (restore (throw ThreadKilled))
...
The `throw` jumps to an exception handler registered outside the
`restore`, which means there is a masking state change. Previously,
dejafu handled this by inserting an `AResetMask` action as the first
action of the handler; but this is incorrect, as it opens a potential
race condition with another thread calling `throwTo`. As `throw` (and
`throwTo`, and an uncaught `throwSTM`) "use up" the exception handler,
this is not a benign race: the thread will be killed!
The solution is to atomically restore the masking state.
This commit implements that, and changes `Throw`, `ThrowTo`, and `STM`
to include the new masking state (if it changed). I think this is a
bit confusing, so I'll make a follow-up commit to split out a new
`ThrownSTM` action.