STM: "nested atomically" error

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

STM: "nested atomically" error

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?

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
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM: "nested atomically" error

Antoine Latter-2
On Thu, Jan 12, 2012 at 6:48 AM, Johan Brinch <[hidden email]> wrote:
> 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
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM: "nested atomically" error

Johan Brinch
On Thu, Jan 12, 2012 at 14:56, Antoine Latter <[hidden email]> wrote:
> Where is 'evalCacheSTM' defined?

Here you go:
https://gist.github.com/8dbff672a14533c70aa2

--
Johan Brinch

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM: "nested atomically" error

Andrew Coppin
In reply to this post by 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...

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM: "nested atomically" error

Brandon Allbery
On Thu, Jan 12, 2012 at 16:50, Andrew Coppin <[hidden email]> 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.  

--
brandon s allbery                                      [hidden email]
wandering unix systems administrator (available)     (412) 475-9364 vm/sms


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM: "nested atomically" error

Joey Adams
In reply to this post by Johan Brinch
On Thu, Jan 12, 2012 at 7:48 AM, Johan Brinch <[hidden email]> wrote:
> 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

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM: "nested atomically" error

Johan Brinch
In reply to this post by Brandon Allbery
On Thu, Jan 12, 2012 at 22:56, Brandon Allbery <[hidden email]> wrote:

> On Thu, Jan 12, 2012 at 16:50, Andrew Coppin <[hidden email]>
> 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

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: STM: "nested atomically" error

Johan Brinch
On Fri, Jan 13, 2012 at 00:14, Johan Brinch <[hidden email]> wrote:
> 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

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe