foreign-0.1.0.0: src/HsForeign/AsyncFFI.hs
module HsForeign.AsyncFFI
( withAsyncFFI
, withAsyncFFI'
, withPrimAsyncFFI
) where
import Control.Concurrent.MVar (newEmptyMVar, takeMVar)
import Control.Exception (mask_, onException)
import Control.Monad (void)
import Foreign.ForeignPtr
import Foreign.StablePtr
import GHC.Conc
import HsForeign.Primitive
withAsyncFFI
:: Int
-- ^ Size of callback data
-> (Ptr a -> IO a)
-- ^ Peek callback data
-> (StablePtr PrimMVar -> Int -> Ptr a -> IO b)
-- ^ Normal async foreign function: sp -> cap -> ptr -> ()
-> IO a
withAsyncFFI = withAsyncFFI' []
withPrimAsyncFFI
:: Prim a
=> (StablePtr PrimMVar -> Int -> Ptr a -> IO b)
-> IO a
withPrimAsyncFFI f = mask_ $ do
(ret, _) <- allocPrim $ \ret' -> do
mvar <- newEmptyMVar
sp <- newStablePtrPrimMVar mvar
(cap, _) <- threadCapability =<< myThreadId
void $ f sp cap ret'
takeMVar mvar `onException` forkIO (do takeMVar mvar;)
pure ret
{-# INLINABLE withPrimAsyncFFI #-}
-- NOTE: memory allocated by haskell and pass to async cpp function must be
-- pinned.
withAsyncFFI'
:: [MutableByteArray RealWorld]
-- ^ A list of extra Bytes we will touch, usually it's empty
-> Int
-- ^ Size of callback data
-> (Ptr a -> IO a)
-- ^ Peek callback data
-> (StablePtr PrimMVar -> Int -> Ptr a -> IO b)
-- ^ Normal async foreign function: sp -> cap -> ptr -> ()
-> IO a
withAsyncFFI' bas size peek_fun f = mask_ $ do
mvar <- newEmptyMVar
sp <- newStablePtrPrimMVar mvar
fp <- mallocForeignPtrBytes size
withForeignPtr fp $ \data' -> do
(cap, _) <- threadCapability =<< myThreadId
void $ f sp cap data'
takeMVar mvar `onException` forkIO (do takeMVar mvar; touchForeignPtr fp; touch bas)
peek_fun data'
{-# INLINABLE withAsyncFFI' #-}