
I need a onCommit functionality for stm. I know there is the stm-io-hooks [1] package. But it seems so big for such a small thing and then I have to translate everything to their monad. lift lift lift ... So I thought of a little hack to solve the issue and I'm wondering if this is safe to use. My understanding of stm internals is very limited. It's basically just a TChan with IO actions in it and there is another thread waiting to execute anything inserted into it. import Control.Concurrent.STM.TChan onCommitChan :: TChan (IO ()) {-# NOINLINE onCommit #-} onCommitChan = unsafePerformIO $ do chan <- newTChanIO forkIO $ forever $ atomically $ readTChan chan return chan onCommit :: IO () -> STM () onCommit = writeTChan onCommitChan It would be cool if an onCommit hook could be directly added to the stm package. Silvio [1] https://hackage.haskell.org/package/stm-io-hooks-1.0.1

Sorry the line with fork in it should have been forkIO $ forever $ join $ atomically $ readTChan chan of course. Silvio

On 22:54 Sun 05 Jul , Silvio Frischknecht wrote:
I need a onCommit functionality for stm. I know there is the stm-io-hooks [1] package. But it seems so big for such a small thing and then I have to translate everything to their monad. lift lift lift ...
So I thought of a little hack to solve the issue and I'm wondering if this is safe to use. My understanding of stm internals is very limited. It's basically just a TChan with IO actions in it and there is another thread waiting to execute anything inserted into it.
import Control.Concurrent.STM.TChan
onCommitChan :: TChan (IO ()) {-# NOINLINE onCommit #-} onCommitChan = unsafePerformIO $ do chan <- newTChanIO forkIO $ forever $ atomically $ readTChan chan return chan
onCommit :: IO () -> STM () onCommit = writeTChan onCommitChan
It would be cool if an onCommit hook could be directly added to the stm package.
Silvio
[1] https://hackage.haskell.org/package/stm-io-hooks-1.0.1 _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
You can't use atomically inside unsafePerformIO.

Right, it looks like the atomically is inside unsafePerformIO, but it is in the fork. This is part of why it is better to avoid the unsafePerformIO here. Anything it buys is at great cost to clarity. On Mon, Jul 6, 2015 at 7:55 AM, Silvio Frischknecht < silvio.frischi@gmail.com> wrote:
You can't use atomically inside unsafePerformIO.
It's not really inside unsafePerformIO. It's in a separate thread spawned by unsafePerformIO. Anyway, it seems to work correctly.
Silvio _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

Hello, Isn't using unsafePerformIO to create toplevel variables/channels/whatever considered okay by the docs? https://hackage.haskell.org/package/stm-2.4.4/docs/Control-Concurrent-STM-TC... Best regards, Marcin Mrotek

Yes, but in my opinion passing variables is clearer and more robust
then global variables.
On Mon, Jul 6, 2015 at 10:48 AM, Marcin Mrotek
Hello,
Isn't using unsafePerformIO to create toplevel variables/channels/whatever considered okay by the docs? https://hackage.haskell.org/package/stm-2.4.4/docs/Control-Concurrent-STM-TC...
Best regards, Marcin Mrotek

Explicitly pass the TChan that handles on commit actions requiring
that it is initialized at some point prior.
On Mon, Jul 6, 2015 at 10:40 AM, Silvio Frischknecht
Right, it looks like the atomically is inside unsafePerformIO, but it is in the fork. This is part of why it is better to avoid the unsafePerformIO here. Anything it buys is at great cost to clarity.
How would you start the thread without using unsafePerformIO?

On 05/07/15 21:54, Silvio Frischknecht wrote:
I need a onCommit functionality for stm. I know there is the stm-io-hooks [1] package. But it seems so big for such a small thing and then I have to translate everything to their monad. lift lift lift ...
So I thought of a little hack to solve the issue and I'm wondering if this is safe to use. My understanding of stm internals is very limited. It's basically just a TChan with IO actions in it and there is another thread waiting to execute anything inserted into it.
import Control.Concurrent.STM.TChan
onCommitChan :: TChan (IO ()) {-# NOINLINE onCommit #-} onCommitChan = unsafePerformIO $ do chan <- newTChanIO forkIO $ forever $ atomically $ readTChan chan return chan
onCommit :: IO () -> STM () onCommit = writeTChan onCommitChan
Leaving aside the question of unsafePerformIO, which is a bad idea, this will more-or-less work, but I suppose the question is what you mean by "safe to use". You might want to think about exception safety: for example, if one of the IO actions written to the channel throws an exception, it will bring down the worker thread, and subsequent onCommit actions will be silently lost. Or if an IO action blocks (or just runs slowly) other actions may be arbitrarily delayed. Depending on your application, this may or may not be acceptable. Hope this helps, Adam -- Adam Gundry, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/
participants (5)
-
Adam Gundry
-
Lana Black
-
Marcin Mrotek
-
Ryan Yates
-
Silvio Frischknecht