module NHC.FFI ( ForeignPtr -- abstract, instance of: Eq,Ord,Show , FinalizerPtr -- synonym: FunPtr ( Ptr a -> IO ()) , FinalizerEnvPtr -- synonym: FunPtr (Ptr env -> Ptr a -> IO ()) , newForeignPtr -- :: FinalizerPtr a -> -- Ptr a -> IO (ForeignPtr a) , newForeignPtrEnv -- :: FinalizerEnvPtr a -> Ptr env -> -- Ptr a -> IO (ForeignPtr a) , newForeignPtr_ -- :: Ptr a -> IO (ForeignPtr a) , addForeignPtrFinalizer -- :: FinalizerPtr a -> ForeignPtr a -> IO () , addForeignPtrFinalizerEnv -- :: FinalizerEnvPtr a -> Ptr env -- -> ForeignPtr a -> IO () , withForeignPtr -- :: ForeignPtr a -> (Ptr a -> IO b) -> IO b , touchForeignPtr -- :: ForeignPtr a -> IO () , unsafeForeignPtrToPtr -- :: ForeignPtr a -> Ptr a , castForeignPtr -- :: ForeignPtr a -> ForeignPtr b , newConcForeignPtr -- :: IO () -> Ptr a -> IO (ForeignPtr a) , addConcForeignPtrFinalizer-- :: IO () -> ForeignPtr a -> IO () ) where {- -- old implementation in terms of ForeignObj import Ptr import ForeignObj newtype ForeignPtr a = ForeignPtr ForeignObj newForeignPtr :: Ptr a -> IO () -> IO (ForeignPtr a) newForeignPtr (Ptr p) finalizer = do fo <- newForeignObj p finalizer return (ForeignPtr fo) touchForeignPtr :: ForeignPtr a -> IO () touchForeignPtr (ForeignPtr fo) = touchForeignObj fo withForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b withForeignPtr fo io = do r <- io (foreignPtrToPtr fo) touchForeignPtr fo return r foreignPtrToPtr :: ForeignPtr a -> Ptr a foreignPtrToPtr (ForeignPtr fo) = Ptr (foreignObjToAddr fo) castForeignPtr :: ForeignPtr a -> ForeignPtr b castForeignPtr (ForeignPtr a) = ForeignPtr a -} import Ptr import FunPtr import NonStdUnsafeCoerce import Numeric (showHex) import NHC.Internal (unsafePerformIO) data ForeignPtr a; -- primitive type known to the compiler internals foreign import cast foreignPtrToInt :: ForeignPtr a -> Int instance Eq (ForeignPtr a) where a == b = (unsafeForeignPtrToPtr a) == (unsafeForeignPtrToPtr b) instance Ord (ForeignPtr a) where compare a b = compare (unsafeForeignPtrToPtr a) (unsafeForeignPtrToPtr b) instance Show (ForeignPtr a) where showsPrec p f = showsPrec p (unsafeForeignPtrToPtr f) type FinalizerPtr a = FunPtr (Ptr a -> IO ()) type FinalizerEnvPtr env a = FunPtr (Ptr env -> Ptr a -> IO ()) -- Note that `newForeignPtr' is not a strictly legal FFI function. -- It is not usually possible to return a ForeignPtr as the result of -- a foreign import. However, in order to implement ForeignPtrs, we -- need one single instance of returning a ForeignPtr, and this is it. -- *** Do not do it elsewhere! foreign import ccall "primForeignPtrC" newForeignPtr :: FinalizerPtr a -> Ptr a -> IO (ForeignPtr a) -- newForeignPtr_ creates a ForeignPtr without a finaliser. newForeignPtr_ :: Ptr a -> IO (ForeignPtr a) newForeignPtr_ p = newForeignPtr nullFunPtr p -- newForeignPtrEnv creates a ForeignPtr with an environment finaliser. newForeignPtrEnv :: FinalizerEnvPtr env a -> Ptr env -> Ptr a -> IO (ForeignPtr a) newForeignPtrEnv f p env = error "Foreign.newForeignPtrEnv not supported" -- addForeignPtrFinalizer is not implemented in nhc98. addForeignPtrFinalizer :: FinalizerPtr a -> ForeignPtr a -> IO () addForeignPtrFinalizer free p = return () addForeignPtrFinalizerEnv :: FinalizerEnvPtr a -> Ptr env -> ForeignPtr a -> IO () addForeignPtrFinalizerEnv free env p = return () -- `withForeignPtr' is a safer way to use `unsafeForeignPtrToPtr'. withForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b withForeignPtr p k = k (unsafeForeignPtrToPtr p) {- GHC implementation: do x <- k (foreignPtrToPtr p) touchForeignPtr p return x -} -- `unsafeForeignPtrToPtr' is a highly dangerous operation. If the last -- reference to the ForeignPtr disappears before the Ptr that has -- been extracted from it is used, then the finaliser could run -- rendering the Ptr invalid. foreign import cast unsafeForeignPtrToPtr :: ForeignPtr a -> Ptr a -- `Touching' a foreignPtr is just intended to keep it alive across -- calls which might otherwise allow it to be GC'ed. Only really -- an issue in GHC - for nhc98 a null-op is sufficient. touchForeignPtr :: ForeignPtr a -> IO () touchForeignPtr p = return () castForeignPtr :: ForeignPtr a -> ForeignPtr b castForeignPtr a = unsafeCoerce a {- GHC extensions mallocForeignPtr :: Storable a => IO (ForeignPtr a) mallocForeignPtrBytes :: Int -> IO (ForeignPtr a) -} ---------------- -- It was once the case that the finaliser on a ForeignPtr was a -- Haskell IO action. These are the remnants of that implementation. -- (It was eventually decided that, for safety, IO finalisers require -- concurrency.) foreign import ccall "primForeignObjC" primForeignPtr :: Ptr a -> b -> IO (ForeignPtr a) data _E a = _E a -- just a box to protect arg from evaluation newConcForeignPtr :: IO () -> Ptr a -> IO (ForeignPtr a) newConcForeignPtr f p = primForeignPtr p (_E (unsafePerformIO f)) addConcForeignPtrFinalizer :: IO () -> ForeignPtr a -> IO () addConcForeignPtrFinalizer free p = return () ----------------