common/util/Util/RequestContext.hs (67 lines of code) (raw):
-- Copyright (c) Facebook, Inc. and its affiliates.
{-# LANGUAGE TemplateHaskell #-}
module Util.RequestContext (
RequestContext,
CRequestContextPtr,
saveRequestContext,
setRequestContext,
withRequestContext,
finalizeRequestContext,
forkIOWithRequestContext,
forkOnWithRequestContext,
RequestContextHolder(..),
DefaultRequestContextHolder,
) where
import Control.Concurrent
import Control.DeepSeq
import Control.Exception
import Foreign.CPP.Marshallable.TH
import Foreign.ForeignPtr
import Foreign.Ptr
data CRequestContextPtr
$(deriveDestructibleUnsafe "RequestContextPtr" [t|CRequestContextPtr|])
newtype RequestContext = RequestContext (ForeignPtr CRequestContextPtr)
instance NFData RequestContext where
rnf (RequestContext rc) = rc `seq` ()
-- | 'saveRequestContext' should only be used in bound thread created by
-- 'forkOS', 'main' or @foreign export@.
saveRequestContext :: IO RequestContext
saveRequestContext = mask_ $ fmap RequestContext $ toSharedPtr =<< c_saveContext
-- | 'setRequestContext' should only be used in bound thread created by
-- 'forkOS', 'main' or @foreign export@.
setRequestContext :: RequestContext -> IO ()
setRequestContext (RequestContext rc) = withForeignPtr rc c_setContext
withRequestContext :: RequestContext -> (Ptr CRequestContextPtr -> IO a) -> IO a
withRequestContext (RequestContext rc) = withForeignPtr rc
finalizeRequestContext :: RequestContext -> IO ()
finalizeRequestContext (RequestContext rc) = finalizeForeignPtr rc
foreign import ccall unsafe "hs_request_context_saveContext"
c_saveContext :: IO (Ptr CRequestContextPtr)
foreign import ccall unsafe "hs_request_context_setContext"
c_setContext :: Ptr CRequestContextPtr -> IO ()
-- The returned 'IO ()' can only be called at most once.
restorableRequestContext :: IO (IO ())
restorableRequestContext = do
rc <- saveRequestContext
return $ do
setRequestContext rc
finalizeRequestContext rc
forkIOWithRequestContext :: IO () -> IO ThreadId
forkIOWithRequestContext f = do
restore <- restorableRequestContext
forkIO $ restore >> f
forkOnWithRequestContext :: Int -> IO () -> IO ThreadId
forkOnWithRequestContext cap f = do
restore <- restorableRequestContext
forkOn cap $ restore >> f
class RequestContextHolder a where
trySaveRequestContextFrom :: a -> IO (Maybe RequestContext)
trySetRequestContextTo :: Maybe RequestContext -> a -> IO a
data DefaultRequestContextHolder = DefaultRequestContextHolder
deriving (Eq, Show)
instance RequestContextHolder DefaultRequestContextHolder where
trySaveRequestContextFrom _ = Just <$> saveRequestContext
trySetRequestContextTo rc a = mapM_ setRequestContext rc *> return a
instance RequestContextHolder () where
trySaveRequestContextFrom _ = return Nothing
trySetRequestContextTo _ = return