
Hi all, I'm seeing the "Control.Concurrent.STM.atomically was nested" error, but I just can't figure out what's happening. I'm not using any unsafe IO (only for debug printing), and the test program is only running one thread. Where is a transaction being nested? What are the scenarios where this error is reported? The behaviour is consistent on GHC 7.4.0 RC and GHC 7.2.2 (stable). That function that's being run can be found here: https://gist.github.com/30b94760abc27b05ec7c And here is the last output from the runtime system: https://gist.github.com/4356ae541895becb4169 Any ideas to track this down will be greatly appreciated! -- Johan Brinch, Dept. of Computer Science, University of Copenhagen

On Thu, Jan 12, 2012 at 6:48 AM, Johan Brinch
Hi all,
I'm seeing the "Control.Concurrent.STM.atomically was nested" error, but I just can't figure out what's happening. I'm not using any unsafe IO (only for debug printing), and the test program is only running one thread. Where is a transaction being nested?
What are the scenarios where this error is reported?
Where is 'evalCacheSTM' defined?
The behaviour is consistent on GHC 7.4.0 RC and GHC 7.2.2 (stable).
That function that's being run can be found here: https://gist.github.com/30b94760abc27b05ec7c
And here is the last output from the runtime system: https://gist.github.com/4356ae541895becb4169
Any ideas to track this down will be greatly appreciated!
-- Johan Brinch, Dept. of Computer Science, University of Copenhagen
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, Jan 12, 2012 at 14:56, Antoine Latter
Where is 'evalCacheSTM' defined?
Here you go: https://gist.github.com/8dbff672a14533c70aa2 -- Johan Brinch

On 12/01/2012 12:48 PM, Johan Brinch wrote:
I'm not using any unsafe IO
OK, good...
(only for debug printing)
...ah. It seems we have reached a contradiction.
Where is a transaction being nested?
My guess is that your "debug printing" is causing something to be evaluated when it otherwise wouldn't be, causing a transaction to begin within a transaction. I could, however, be horribly wrong about that...

On Thu, Jan 12, 2012 at 16:50, Andrew Coppin
My guess is that your "debug printing" is causing something to be evaluated when it otherwise wouldn't be, causing a transaction to begin within a transaction.
My guess is something is being lazily evaluated as usual, but if that is forced within a transaction, well, last I checked the GHC I/O system used STM internally so unsafePerformIO debug prints could well cause nested transactions. -- brandon s allbery allbery.b@gmail.com wandering unix systems administrator (available) (412) 475-9364 vm/sms

On Thu, Jan 12, 2012 at 22:56, Brandon Allbery
On Thu, Jan 12, 2012 at 16:50, Andrew Coppin
wrote: My guess is that your "debug printing" is causing something to be evaluated when it otherwise wouldn't be, causing a transaction to begin within a transaction.
My guess is something is being lazily evaluated as usual, but if that is forced within a transaction, well, last I checked the GHC I/O system used STM internally so unsafePerformIO debug prints could well cause nested transactions.
This could be it. If I'm computing a value atomically and then using this value in another transaction, I may nest transactions if the value isn't forced? x <- atomically $ foo let x' = someOp x atomically $ bar x' Is it necessary to use seq here, or is it merely the debug printing that's getting in the way? Also, if the GHC IO system is using STM internally, what would be the correct way to say write a file? (where the IO action can be retried safely but have to run at least once, idempotent?). Please don't say "don't" :-) -- Johan Brinch

On Fri, Jan 13, 2012 at 00:14, Johan Brinch
Also, if the GHC IO system is using STM internally, what would be the correct way to say write a file? (where the IO action can be retried safely but have to run at least once, idempotent?). Please don't say "don't" :-)
I now believe that the correct answer is simply "don't". For anyone who finds this thread later and wonder what happened: I refactored the code to never use IO inside of STM transactions. Instead, I'm now using the ErrorT IO STM to abort the transaction early with an IO action that needs to be run before a retry. Aborting with throwError doesn't rollback the transaction, which means one has to be extremely careful as to what state is manipulated before entering clean code (without any throwErrors). This seems a lot more safe than doing IO inside the STM transactions which has completely unpredictable (for me, at least) side effects. -- Johan Brinch

On Thu, Jan 12, 2012 at 7:48 AM, Johan Brinch
Hi all,
I'm seeing the "Control.Concurrent.STM.atomically was nested" error, but I just can't figure out what's happening. I'm not using any unsafe IO (only for debug printing), and the test program is only running one thread. Where is a transaction being nested?
What are the scenarios where this error is reported?
I might as well state the obvious. The type system prevents this from happening under normal circumstances. However, it is possible to circumvent the type system using, for example, unsafePerformIO or unsafeInterleaveIO: nest1 :: IO () nest1 = let x = unsafePerformIO $ atomically $ return () in atomically (x `seq` return ()) nest2 :: IO () nest2 = do x <- unsafeInterleaveIO $ atomically $ return () atomically (x `seq` return ()) In both nest1 and nest2, x is a thunk whose evaluation performs an STM transaction. In both cases, this produces an "atomically was nested" error. On GHC, the Debug.Trace functions internally call a C function called debugBelch (defined in RtsMessages.c). These don't appear to use 'atomically' at all. Thus, I doubt using trace will produce an "atomically was nested" error. - Joey
participants (5)
-
Andrew Coppin
-
Antoine Latter
-
Brandon Allbery
-
Joey Adams
-
Johan Brinch