{- 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