packages feed

hhlo-0.11.0.0: src/HHLO/Runtime/PJRT/Registry.hs

{-# LANGUAGE Unsafe #-}

-- | Process-wide registry tracking which 'PJRTApi' pointers are currently
-- alive (i.e. have an open session).  Buffer finalizers use this to avoid
-- calling 'PJRT_Buffer_Destroy' after the client has been torn down,
-- which would segfault because the buffer's internal state references
-- client-owned resources (CUDA context, StreamExecutor, etc.) that are
-- destroyed when the client closes.
--
-- This module is marked @Unsafe@ because it uses 'unsafePerformIO' for
-- the top-level 'IORef'.  It is only imported by internal hhlo modules.
module HHLO.Runtime.PJRT.Registry
    ( registerApi
    , unregisterApi
    , isApiAlive
    ) where

import Data.IORef (IORef, atomicModifyIORef', newIORef, readIORef)
import qualified Data.Map.Strict as Map
import Foreign.Ptr (Ptr)
import System.IO.Unsafe (unsafePerformIO)

import HHLO.Runtime.PJRT.Types (PJRTApi(..))

-- | Global registry of alive API pointers.
apiRegistry :: IORef (Map.Map (Ptr PJRTApi) ())
apiRegistry = unsafePerformIO $ newIORef Map.empty
{-# NOINLINE apiRegistry #-}

-- | Register a 'PJRTApi' as alive.  Called by 'withPJRT' when a session
-- opens.
registerApi :: PJRTApi -> IO ()
registerApi api =
    atomicModifyIORef' apiRegistry $ \m ->
        (Map.insert (unApi api) () m, ())

-- | Unregister a 'PJRTApi'.  Called by 'withPJRT' when a session closes.
-- After this, buffer finalizers that reference this API will skip their
-- destroy call.
unregisterApi :: PJRTApi -> IO ()
unregisterApi api =
    atomicModifyIORef' apiRegistry $ \m ->
        (Map.delete (unApi api) m, ())

-- | Check whether a raw 'PJRTApi' pointer is currently registered as
-- alive.
isApiAlive :: Ptr PJRTApi -> IO Bool
isApiAlive p =
    Map.member p <$> readIORef apiRegistry

unApi :: PJRTApi -> Ptr PJRTApi
unApi (PJRTApi p) = p