packages feed

fb-util-0.1.0.1: Util/STM.hs

{-
  Copyright (c) Meta Platforms, Inc. and affiliates.
  All rights reserved.

  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree.
-}

-- | Reexports 'Control.Concurrent.STM'
--   adding logging for deadlocks and utility functions
module Util.STM
 ( updateTVar
 , atomicallyWithLabel
 , Util.STM.atomically
 , module Control.Concurrent.STM
 ) where

import qualified Control.Concurrent.STM as STM
import Control.Concurrent.STM hiding (atomically)
import Control.Exception (Exception, BlockedIndefinitelyOnSTM, catch, throwIO)
import GHC.Stack
import Data.Typeable (Typeable)

-- | version of @modifyTVar'@ that returns the new value
updateTVar :: TVar a -> (a -> a) -> STM a
updateTVar var f = do
  x <- readTVar var
  let !x' = f x
  writeTVar var x'
  return x'

-- | Version of 'atomically' that takes a label
atomicallyWithLabel :: String -> STM a -> IO a
atomicallyWithLabel label stm = do
  STM.atomically stm `catch` (\(_::BlockedIndefinitelyOnSTM) ->
    throwIO (BlockedIndefinitelyOnNamedSTM label))

-- | Version of 'atomically' that labels the transaction using the call site
atomically :: HasCallStack => STM a -> IO a
atomically =
  atomicallyWithLabel (getCaller $ getCallStack callStack)

-- | The calling point is actually right next to the head as the head is the
-- current function (in this case it would be logInfo/Warning/Error/Fatal).
getCaller :: [(String, SrcLoc)] -> String
getCaller cs =
  case cs of
    -- Take the first element of the stack if it exists
    ((_,sl):_) -> prettySrcLoc sl
    _       -> "Unknown stack trace"

-- | 'atomicallyWithLabel' replaces occurrences of 'BlockedIndefinitelyOnSTM' w/
-- 'BlockedIndefinitelyOnNamedSTM', carrying the name of the transaction and
-- thus giving more helpful error messages.
newtype BlockedIndefinitelyOnNamedSTM = BlockedIndefinitelyOnNamedSTM String
    deriving (Typeable)

instance Show BlockedIndefinitelyOnNamedSTM where
    showsPrec _ (BlockedIndefinitelyOnNamedSTM name) =
        showString $ "thread blocked indefinitely in STM transaction: " ++ name

instance Exception BlockedIndefinitelyOnNamedSTM