5
5
{-# LANGUAGE GADTs #-}
6
6
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7
7
{-# LANGUAGE MultiParamTypeClasses #-}
8
+ {-# LANGUAGE RankNTypes #-}
8
9
{-# LANGUAGE StandaloneDeriving #-}
9
10
{-# LANGUAGE TypeFamilies #-}
10
11
{-# LANGUAGE TypeFamilyDependencies #-}
14
15
module Control.Monad.Class.MonadSTM
15
16
( MonadSTM (.. )
16
17
, MonadLabelledSTM (.. )
18
+ , MonadInspectSTM (.. )
19
+ , MonadTraceSTM (.. )
17
20
, LazyTVar
18
21
, LazyTMVar
19
22
-- * Default 'TMVar' implementation
20
23
, TMVarDefault (.. )
21
24
, labelTMVarDefault
25
+ , traceTMVarDefault
22
26
, newTMVarDefault
23
27
, newTMVarIODefault
24
28
, newEmptyTMVarDefault
@@ -90,6 +94,7 @@ import Control.Applicative (Alternative (..))
90
94
import Control.Exception
91
95
import Data.Function (on )
92
96
import Data.Kind (Type )
97
+ import Data.Typeable (Typeable )
93
98
import GHC.Stack
94
99
import Numeric.Natural (Natural )
95
100
@@ -238,6 +243,130 @@ class MonadSTM m
238
243
default labelTBQueueIO :: TBQueue m a -> String -> m ()
239
244
labelTBQueueIO = \ v l -> atomically (labelTBQueue v l)
240
245
246
+
247
+ -- | This type class is indented for 'io-sim', where one might want to access
248
+ -- 'TVar' in the underlying 'ST' monad.
249
+ --
250
+ class ( MonadSTM m
251
+ , Monad (InspectMonad m )
252
+ )
253
+ => MonadInspectSTM m where
254
+ type InspectMonad m :: Type -> Type
255
+ inspectTVar :: proxy m -> TVar m a -> InspectMonad m a
256
+ inspectTMVar :: proxy m -> TMVar m a -> InspectMonad m (Maybe a )
257
+ -- TODO: inspectTQueue, inspectTBQueue
258
+
259
+ instance MonadInspectSTM IO where
260
+ type InspectMonad IO = IO
261
+ inspectTVar _ = readTVarIO
262
+ -- issue #3198: tryReadTMVarIO
263
+ inspectTMVar _ = atomically . tryReadTMVar
264
+
265
+
266
+ -- | 'MonadTraceSTM' allows to trace values of stm variables when stm
267
+ -- transaction is commited. This allows to verify invariants when a variable
268
+ -- is commited.
269
+ --
270
+ class MonadInspectSTM m
271
+ => MonadTraceSTM m where
272
+ -- | Construct a trace out of previous & new value of a 'TVar'. The callback
273
+ -- is called whenever an stm transaction which modifies the 'TVar' is
274
+ -- commited.
275
+ --
276
+ -- This is supported by 'IOSim' and 'IOSimPOR'; 'IO' has a trivial instance.
277
+ --
278
+ {-# MINIMAL traceTVar, traceTQueue, traceTBQueue #-}
279
+
280
+ traceTVar :: Typeable tr
281
+ => proxy m
282
+ -> TVar m a
283
+ -> (Maybe a -> a -> InspectMonad m tr )
284
+ -- ^ callback which receives initial value or 'Nothing' (if it
285
+ -- is a newly created 'TVar'), and the commited value.
286
+ -> STM m ()
287
+
288
+
289
+ traceTMVar :: Typeable tr
290
+ => proxy m
291
+ -> TMVar m a
292
+ -> (Maybe (Maybe a ) -> (Maybe a ) -> InspectMonad m tr )
293
+ -> STM m ()
294
+
295
+ traceTQueue :: Typeable tr
296
+ => proxy m
297
+ -> TQueue m a
298
+ -> (Maybe [a ] -> [a ] -> InspectMonad m tr )
299
+ -> STM m ()
300
+
301
+ traceTBQueue :: Typeable tr
302
+ => proxy m
303
+ -> TBQueue m a
304
+ -> (Maybe [a ] -> [a ] -> InspectMonad m tr )
305
+ -> STM m ()
306
+
307
+ default traceTMVar :: ( TMVar m a ~ TMVarDefault m a
308
+ , Typeable tr
309
+ )
310
+ => proxy m
311
+ -> TMVar m a
312
+ -> (Maybe (Maybe a) -> (Maybe a) -> InspectMonad m tr)
313
+ -> STM m ()
314
+ traceTMVar = traceTMVarDefault
315
+
316
+
317
+ traceTVarIO :: Typeable tr
318
+ => proxy m
319
+ -> TVar m a
320
+ -> (Maybe a -> a -> InspectMonad m tr )
321
+ -> m ()
322
+
323
+ traceTMVarIO :: Typeable tr
324
+ => proxy m
325
+ -> TMVar m a
326
+ -> (Maybe (Maybe a ) -> (Maybe a ) -> InspectMonad m tr )
327
+ -> m ()
328
+
329
+ traceTQueueIO :: Typeable tr
330
+ => proxy m
331
+ -> TQueue m a
332
+ -> (Maybe [a ] -> [a ] -> InspectMonad m tr )
333
+ -> m ()
334
+
335
+ traceTBQueueIO :: Typeable tr
336
+ => proxy m
337
+ -> TBQueue m a
338
+ -> (Maybe [a ] -> [a ] -> InspectMonad m tr )
339
+ -> m ()
340
+
341
+ default traceTVarIO :: Typeable tr
342
+ => proxy m
343
+ -> TVar m a
344
+ -> (Maybe a -> a -> InspectMonad m tr)
345
+ -> m ()
346
+ traceTVarIO = \ p v f -> atomically (traceTVar p v f)
347
+
348
+ default traceTMVarIO :: Typeable tr
349
+ => proxy m
350
+ -> TMVar m a
351
+ -> (Maybe (Maybe a) -> (Maybe a) -> InspectMonad m tr)
352
+ -> m ()
353
+ traceTMVarIO = \ p v f -> atomically (traceTMVar p v f)
354
+
355
+ default traceTQueueIO :: Typeable tr
356
+ => proxy m
357
+ -> TQueue m a
358
+ -> (Maybe [a] -> [a] -> InspectMonad m tr)
359
+ -> m ()
360
+ traceTQueueIO = \ p v f -> atomically (traceTQueue p v f)
361
+
362
+ default traceTBQueueIO :: Typeable tr
363
+ => proxy m
364
+ -> TBQueue m a
365
+ -> (Maybe [a] -> [a] -> InspectMonad m tr)
366
+ -> m ()
367
+ traceTBQueueIO = \ p v f -> atomically (traceTBQueue p v f)
368
+
369
+
241
370
--
242
371
-- Instance for IO uses the existing STM library implementations
243
372
--
@@ -310,6 +439,19 @@ instance MonadLabelledSTM IO where
310
439
labelTQueueIO = \ _ _ -> return ()
311
440
labelTBQueueIO = \ _ _ -> return ()
312
441
442
+ -- | noop instance
443
+ --
444
+ instance MonadTraceSTM IO where
445
+ traceTVar = \ _ _ _ -> return ()
446
+ traceTMVar = \ _ _ _ -> return ()
447
+ traceTQueue = \ _ _ _ -> return ()
448
+ traceTBQueue = \ _ _ _ -> return ()
449
+
450
+ traceTVarIO = \ _ _ _ -> return ()
451
+ traceTMVarIO = \ _ _ _ -> return ()
452
+ traceTQueueIO = \ _ _ _ -> return ()
453
+ traceTBQueueIO = \ _ _ _ -> return ()
454
+
313
455
-- | Wrapper around 'BlockedIndefinitelyOnSTM' that stores a call stack
314
456
data BlockedIndefinitely = BlockedIndefinitely {
315
457
blockedIndefinitelyCallStack :: CallStack
@@ -327,7 +469,7 @@ wrapBlockedIndefinitely :: HasCallStack => IO a -> IO a
327
469
wrapBlockedIndefinitely = handle (throwIO . BlockedIndefinitely callStack)
328
470
329
471
--
330
- -- Default TMVar implementation in terms of TVars (used by sim)
472
+ -- Default TMVar implementation in terms of TVars
331
473
--
332
474
333
475
newtype TMVarDefault m a = TMVar (TVar m (Maybe a ))
@@ -337,6 +479,14 @@ labelTMVarDefault
337
479
=> TMVarDefault m a -> String -> STM m ()
338
480
labelTMVarDefault (TMVar tvar) = labelTVar tvar
339
481
482
+ traceTMVarDefault
483
+ :: (MonadTraceSTM m , Typeable tr )
484
+ => proxy m
485
+ -> TMVarDefault m a
486
+ -> (Maybe (Maybe a ) -> Maybe a -> InspectMonad m tr )
487
+ -> STM m ()
488
+ traceTMVarDefault p (TMVar t) f = traceTVar p t f
489
+
340
490
newTMVarDefault :: MonadSTM m => a -> STM m (TMVarDefault m a )
341
491
newTMVarDefault a = do
342
492
t <- newTVar (Just a)
@@ -486,7 +636,7 @@ tryPeekTQueueDefault (TQueue read _write) = do
486
636
_ -> return Nothing
487
637
488
638
--
489
- -- Default TBQueue implementation in terms of TVars (used by sim)
639
+ -- Default TBQueue implementation in terms of TVars
490
640
--
491
641
492
642
data TBQueueDefault m a = TBQueue
0 commit comments