{-# LANGUAGE CPP
, NoImplicitPrelude
, BangPatterns
, MagicHash
, UnboxedTuples
#-}{-# OPTIONS_HADDOCK hide #-}{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}------------------------------------------------------------------------------- |-- Module : GHC.ForeignPtr-- Copyright : (c) The University of Glasgow, 1992-2003-- License : see libraries/base/LICENSE-- -- Maintainer : cvs-ghc@haskell.org-- Stability : internal-- Portability : non-portable (GHC extensions)---- GHC's implementation of the 'ForeignPtr' data type.-- ------------------------------------------------------------------------------- #hidemoduleGHC.ForeignPtr(ForeignPtr(..),FinalizerPtr,FinalizerEnvPtr,newForeignPtr_,mallocForeignPtr,mallocPlainForeignPtr,mallocForeignPtrBytes,mallocPlainForeignPtrBytes,addForeignPtrFinalizer,addForeignPtrFinalizerEnv,touchForeignPtr,unsafeForeignPtrToPtr,castForeignPtr,newConcForeignPtr,addForeignPtrConcFinalizer,finalizeForeignPtr)whereimportControl.Monad(sequence_)importForeign.StorableimportData.TypeableimportGHC.ShowimportGHC.List(null)importGHC.BaseimportGHC.IORefimportGHC.STRef(STRef(..))importGHC.Ptr(Ptr(..),FunPtr(..))importGHC.Err#include "Typeable.h"-- |The type 'ForeignPtr' represents references to objects that are-- maintained in a foreign language, i.e., that are not part of the-- data structures usually managed by the Haskell storage manager.-- The essential difference between 'ForeignPtr's and vanilla memory-- references of type @Ptr a@ is that the former may be associated-- with /finalizers/. A finalizer is a routine that is invoked when-- the Haskell storage manager detects that - within the Haskell heap-- and stack - there are no more references left that are pointing to-- the 'ForeignPtr'. Typically, the finalizer will, then, invoke-- routines in the foreign language that free the resources bound by-- the foreign object.---- The 'ForeignPtr' is parameterised in the same way as 'Ptr'. The-- type argument of 'ForeignPtr' should normally be an instance of-- class 'Storable'.--dataForeignPtra=ForeignPtrAddr#ForeignPtrContents-- we cache the Addr# in the ForeignPtr object, but attach-- the finalizer to the IORef (or the MutableByteArray# in-- the case of a MallocPtr). The aim of the representation-- is to make withForeignPtr efficient; in fact, withForeignPtr-- should be just as efficient as unpacking a Ptr, and multiple-- withForeignPtrs can share an unpacked ForeignPtr. Note-- that touchForeignPtr only has to touch the ForeignPtrContents-- object, because that ensures that whatever the finalizer is-- attached to is kept alive.INSTANCE_TYPEABLE1(ForeignPtr,foreignPtrTc,"ForeignPtr")dataFinalizers=NoFinalizers|CFinalizers|HaskellFinalizersderivingEqdataForeignPtrContents=PlainForeignPtr!(IORef(Finalizers,[IO()]))|MallocPtr(MutableByteArray#RealWorld)!(IORef(Finalizers,[IO()]))|PlainPtr(MutableByteArray#RealWorld)instanceEq(ForeignPtra)wherep==q=unsafeForeignPtrToPtrp==unsafeForeignPtrToPtrqinstanceOrd(ForeignPtra)wherecomparepq=compare(unsafeForeignPtrToPtrp)(unsafeForeignPtrToPtrq)instanceShow(ForeignPtra)whereshowsPrecpf=showsPrecp(unsafeForeignPtrToPtrf)-- |A finalizer is represented as a pointer to a foreign function that, at-- finalisation time, gets as an argument a plain pointer variant of the-- foreign pointer that the finalizer is associated with.-- typeFinalizerPtra=FunPtr(Ptra->IO())typeFinalizerEnvPtrenva=FunPtr(Ptrenv->Ptra->IO())newConcForeignPtr::Ptra->IO()->IO(ForeignPtra)---- ^Turns a plain memory reference into a foreign object by-- associating a finalizer - given by the monadic operation - with the-- reference. The storage manager will start the finalizer, in a-- separate thread, some time after the last reference to the-- @ForeignPtr@ is dropped. There is no guarantee of promptness, and-- in fact there is no guarantee that the finalizer will eventually-- run at all.---- Note that references from a finalizer do not necessarily prevent-- another object from being finalized. If A's finalizer refers to B-- (perhaps using 'touchForeignPtr', then the only guarantee is that-- B's finalizer will never be started before A's. If both A and B-- are unreachable, then both finalizers will start together. See-- 'touchForeignPtr' for more on finalizer ordering.--newConcForeignPtrpfinalizer=dofObj<-newForeignPtr_paddForeignPtrConcFinalizerfObjfinalizerreturnfObjmallocForeignPtr::Storablea=>IO(ForeignPtra)-- ^ Allocate some memory and return a 'ForeignPtr' to it. The memory-- will be released automatically when the 'ForeignPtr' is discarded.---- 'mallocForeignPtr' is equivalent to---- > do { p <- malloc; newForeignPtr finalizerFree p }-- -- although it may be implemented differently internally: you may not-- assume that the memory returned by 'mallocForeignPtr' has been-- allocated with 'Foreign.Marshal.Alloc.malloc'.---- GHC notes: 'mallocForeignPtr' has a heavily optimised-- implementation in GHC. It uses pinned memory in the garbage-- collected heap, so the 'ForeignPtr' does not require a finalizer to-- free the memory. Use of 'mallocForeignPtr' and associated-- functions is strongly recommended in preference to 'newForeignPtr'-- with a finalizer.-- mallocForeignPtr=doMallocundefinedwheredoMalloc::Storableb=>b->IO(ForeignPtrb)doMalloca|I#size<0=error"mallocForeignPtr: size must be >= 0"|otherwise=dor<-newIORef(NoFinalizers,[])IO$\s->casenewAlignedPinnedByteArray#sizealignsof{(#s',mbarr##)->(#s',ForeignPtr(byteArrayContents#(unsafeCoerce#mbarr#))(MallocPtrmbarr#r)#)}where!(I#size)=sizeOfa!(I#align)=alignmenta-- | This function is similar to 'mallocForeignPtr', except that the-- size of the memory required is given explicitly as a number of bytes.mallocForeignPtrBytes::Int->IO(ForeignPtra)mallocForeignPtrBytessize|size<0=error"mallocForeignPtrBytes: size must be >= 0"mallocForeignPtrBytes(I#size)=dor<-newIORef(NoFinalizers,[])IO$\s->casenewPinnedByteArray#sizesof{(#s',mbarr##)->(#s',ForeignPtr(byteArrayContents#(unsafeCoerce#mbarr#))(MallocPtrmbarr#r)#)}-- | Allocate some memory and return a 'ForeignPtr' to it. The memory-- will be released automatically when the 'ForeignPtr' is discarded.---- GHC notes: 'mallocPlainForeignPtr' has a heavily optimised-- implementation in GHC. It uses pinned memory in the garbage-- collected heap, as for mallocForeignPtr. Unlike mallocForeignPtr, a-- ForeignPtr created with mallocPlainForeignPtr carries no finalizers.-- It is not possible to add a finalizer to a ForeignPtr created with-- mallocPlainForeignPtr. This is useful for ForeignPtrs that will live-- only inside Haskell (such as those created for packed strings).-- Attempts to add a finalizer to a ForeignPtr created this way, or to-- finalize such a pointer, will throw an exception.-- mallocPlainForeignPtr::Storablea=>IO(ForeignPtra)mallocPlainForeignPtr=doMallocundefinedwheredoMalloc::Storableb=>b->IO(ForeignPtrb)doMalloca|I#size<0=error"mallocForeignPtr: size must be >= 0"|otherwise=IO$\s->casenewAlignedPinnedByteArray#sizealignsof{(#s',mbarr##)->(#s',ForeignPtr(byteArrayContents#(unsafeCoerce#mbarr#))(PlainPtrmbarr#)#)}where!(I#size)=sizeOfa!(I#align)=alignmenta-- | This function is similar to 'mallocForeignPtrBytes', except that-- the internally an optimised ForeignPtr representation with no-- finalizer is used. Attempts to add a finalizer will cause an-- exception to be thrown.mallocPlainForeignPtrBytes::Int->IO(ForeignPtra)mallocPlainForeignPtrBytessize|size<0=error"mallocPlainForeignPtrBytes: size must be >= 0"mallocPlainForeignPtrBytes(I#size)=IO$\s->casenewPinnedByteArray#sizesof{(#s',mbarr##)->(#s',ForeignPtr(byteArrayContents#(unsafeCoerce#mbarr#))(PlainPtrmbarr#)#)}addForeignPtrFinalizer::FinalizerPtra->ForeignPtra->IO()-- ^This function adds a finalizer to the given foreign object. The-- finalizer will run /before/ all other finalizers for the same-- object which have already been registered.addForeignPtrFinalizer(FunPtrfp)(ForeignPtrpc)=casecofPlainForeignPtrr->fr>>return()MallocPtr_r->fr>>return()_->error"GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"wherefr=noMixingCFinalizersr$IO$\s->caserof{IORef(STRefr#)->casemkWeakForeignEnv#r#()fpp0#nullAddr#sof{(#s1,w#)->(#s1,finalizeForeignw#)}}addForeignPtrFinalizerEnv::FinalizerEnvPtrenva->Ptrenv->ForeignPtra->IO()-- ^ Like 'addForeignPtrFinalizerEnv' but allows the finalizer to be-- passed an additional environment parameter to be passed to the-- finalizer. The environment passed to the finalizer is fixed by the-- second argument to 'addForeignPtrFinalizerEnv'addForeignPtrFinalizerEnv(FunPtrfp)(Ptrep)(ForeignPtrpc)=casecofPlainForeignPtrr->fr>>return()MallocPtr_r->fr>>return()_->error"GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"wherefr=noMixingCFinalizersr$IO$\s->caserof{IORef(STRefr#)->casemkWeakForeignEnv#r#()fpp1#epsof{(#s1,w#)->(#s1,finalizeForeignw#)}}finalizeForeign::Weak#()->IO()finalizeForeignw=IO$\s->casefinalizeWeak#wsof(#s1,0#,_#)->(#s1,()#)(#s1,_,f#)->fs1addForeignPtrConcFinalizer::ForeignPtra->IO()->IO()-- ^This function adds a finalizer to the given @ForeignPtr@. The-- finalizer will run /before/ all other finalizers for the same-- object which have already been registered.---- This is a variant of @addForeignPtrFinalizer@, where the finalizer-- is an arbitrary @IO@ action. When it is invoked, the finalizer-- will run in a new thread.---- NB. Be very careful with these finalizers. One common trap is that-- if a finalizer references another finalized value, it does not-- prevent that value from being finalized. In particular, 'Handle's-- are finalized objects, so a finalizer should not refer to a 'Handle'-- (including @stdout@, @stdin@ or @stderr@).--addForeignPtrConcFinalizer(ForeignPtr_c)finalizer=addForeignPtrConcFinalizer_cfinalizeraddForeignPtrConcFinalizer_::ForeignPtrContents->IO()->IO()addForeignPtrConcFinalizer_(PlainForeignPtrr)finalizer=donoFinalizers<-noMixingHaskellFinalizersr(returnfinalizer)ifnoFinalizersthenIO$\s->caserof{IORef(STRefr#)->casemkWeak#r#()(foreignPtrFinalizerr)sof{(#s1,_#)->(#s1,()#)}}elsereturn()addForeignPtrConcFinalizer_f@(MallocPtrfor)finalizer=donoFinalizers<-noMixingHaskellFinalizersr(returnfinalizer)ifnoFinalizersthenIO$\s->casemkWeak#fo()(doforeignPtrFinalizerr;touchf)sof(#s1,_#)->(#s1,()#)elsereturn()addForeignPtrConcFinalizer___=error"GHC.ForeignPtr: attempt to add a finalizer to plain pointer"noMixing::Finalizers->IORef(Finalizers,[IO()])->IO(IO())->IOBoolnoMixingftype0rmkF=do(ftype,fs)<-readIORefrifftype/=NoFinalizers&&ftype/=ftype0thenerror("GHC.ForeignPtr: attempt to mix Haskell and C finalizers "++"in the same ForeignPtr")elsedof<-mkFwriteIORefr(ftype0,f:fs)return(nullfs)foreignPtrFinalizer::IORef(Finalizers,[IO()])->IO()foreignPtrFinalizerr=do(_,fs)<-readIORefr;sequence_fsnewForeignPtr_::Ptra->IO(ForeignPtra)-- ^Turns a plain memory reference into a foreign pointer that may be-- associated with finalizers by using 'addForeignPtrFinalizer'.newForeignPtr_(Ptrobj)=dor<-newIORef(NoFinalizers,[])return(ForeignPtrobj(PlainForeignPtrr))touchForeignPtr::ForeignPtra->IO()-- ^This function ensures that the foreign object in-- question is alive at the given place in the sequence of IO-- actions. In particular 'Foreign.ForeignPtr.withForeignPtr'-- does a 'touchForeignPtr' after it-- executes the user action.-- -- Note that this function should not be used to express dependencies-- between finalizers on 'ForeignPtr's. For example, if the finalizer-- for a 'ForeignPtr' @F1@ calls 'touchForeignPtr' on a second-- 'ForeignPtr' @F2@, then the only guarantee is that the finalizer-- for @F2@ is never started before the finalizer for @F1@. They-- might be started together if for example both @F1@ and @F2@ are-- otherwise unreachable, and in that case the scheduler might end up-- running the finalizer for @F2@ first.---- In general, it is not recommended to use finalizers on separate-- objects with ordering constraints between them. To express the-- ordering robustly requires explicit synchronisation using @MVar@s-- between the finalizers, but even then the runtime sometimes runs-- multiple finalizers sequentially in a single thread (for-- performance reasons), so synchronisation between finalizers could-- result in artificial deadlock. Another alternative is to use-- explicit reference counting.--touchForeignPtr(ForeignPtr_r)=touchrtouch::ForeignPtrContents->IO()touchr=IO$\s->casetouch#rsofs'->(#s',()#)unsafeForeignPtrToPtr::ForeignPtra->Ptra-- ^This function extracts the pointer component of a foreign-- pointer. This is a potentially dangerous operations, as if the-- argument to 'unsafeForeignPtrToPtr' is the last usage-- occurrence of the given foreign pointer, then its finalizer(s) will-- be run, which potentially invalidates the plain pointer just-- obtained. Hence, 'touchForeignPtr' must be used-- wherever it has to be guaranteed that the pointer lives on - i.e.,-- has another usage occurrence.---- To avoid subtle coding errors, hand written marshalling code-- should preferably use 'Foreign.ForeignPtr.withForeignPtr' rather-- than combinations of 'unsafeForeignPtrToPtr' and-- 'touchForeignPtr'. However, the latter routines-- are occasionally preferred in tool generated marshalling code.unsafeForeignPtrToPtr(ForeignPtrfo_)=PtrfocastForeignPtr::ForeignPtra->ForeignPtrb-- ^This function casts a 'ForeignPtr'-- parameterised by one type into another type.castForeignPtrf=unsafeCoerce#f-- | Causes the finalizers associated with a foreign pointer to be run-- immediately.finalizeForeignPtr::ForeignPtra->IO()finalizeForeignPtr(ForeignPtr_(PlainPtr_))=return()-- no effectfinalizeForeignPtr(ForeignPtr_foreignPtr)=do(ftype,finalizers)<-readIORefrefFinalizerssequence_finalizerswriteIORefrefFinalizers(ftype,[])whererefFinalizers=caseforeignPtrof(PlainForeignPtrref)->ref(MallocPtr_ref)->refPlainPtr_->error"finalizeForeignPtr PlainPtr"