packages feed

fb-util-0.1.0.1: Util/RWVar.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.
-}

module Util.RWVar
  ( RWVar
  , newRWVar
  , withReadRWVar
  , withWriteRWVar
  ) where

import qualified Control.Concurrent.ReadWriteLock as L
import Data.IORef

-- | Var holding a value that's only accessible given access to the lock
-- The lock implementation can starve writers
data RWVar a = RWVar (IORef a) L.RWLock

-- -----------------------------------------------------------------------------
-- Creation

-- | Creates a new var that can be read from or written to
newRWVar :: a -> IO (RWVar a)
newRWVar value = do
  lock <- L.new
  ref <- newIORef value
  return $ RWVar ref lock

-- -----------------------------------------------------------------------------
-- Reading

-- | Obtains a read lock and runs the action with the held value
withReadRWVar :: RWVar a -> (a -> IO b) -> IO b
withReadRWVar (RWVar value lock) action =
  L.withRead lock $ action =<< readIORef value

-- -----------------------------------------------------------------------------
-- Writing

-- | Obtains a write lock and runs the action with the held value.
-- Overwrites the internal value with the newly computed value.
withWriteRWVar :: RWVar a -> (a -> IO (a, b)) -> IO b
withWriteRWVar (RWVar value lock) action =
  L.withWrite lock $ do
    old <- readIORef value
    (new, ret) <- action old
    writeIORef value new
    return ret