{-# LANGUAGE ForeignFunctionInterface #-} -- | Internals of global locking. -- -- Use with caution! module System.GlobalLock.Internal ( get ) where import Foreign import Foreign.C import Control.Monad import Control.Concurrent.MVar {- Importing c_get_global with 'unsafe' decreases locking latency by about 50%. The C function just reads a static variable, so it's okay to use 'unsafe'. c_set_global must not be imported 'unsafe' because it uses GCC atomic-operation builtins which, in the worst case, might call a blocking library function. -} {- If you are copying this file to your own Haskell project, see the note in cbits/global.c regarding naming. -} foreign import ccall unsafe "hs_globalzmlock_get_global" c_get_global :: IO (Ptr ()) foreign import ccall "hs_globalzmlock_set_global" c_set_global :: Ptr () -> IO CInt set :: IO () set = do mv <- newMVar () ptr <- newStablePtr mv ret <- c_set_global (castStablePtrToPtr ptr) when (ret == 0) $ -- The variable was already set; our StablePtr is unused. freeStablePtr ptr -- | Get the single @'MVar'@ used for global locking. get :: IO (MVar ()) get = do p <- c_get_global if p == nullPtr then set >> get else deRefStablePtr (castPtrToStablePtr p)