Movatterモバイル変換
[0]ホーム
{-# LANGUAGE Unsafe #-}{-# LANGUAGE NoImplicitPrelude , BangPatterns , MagicHash , UnboxedTuples #-}{-# OPTIONS_HADDOCK hide #-}{-# LANGUAGE 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.-------------------------------------------------------------------------------moduleGHC.ForeignPtr(ForeignPtr(..),ForeignPtrContents(..),FinalizerPtr,FinalizerEnvPtr,newForeignPtr_,mallocForeignPtr,mallocPlainForeignPtr,mallocForeignPtrBytes,mallocPlainForeignPtrBytes,mallocForeignPtrAlignedBytes,mallocPlainForeignPtrAlignedBytes,addForeignPtrFinalizer,addForeignPtrFinalizerEnv,touchForeignPtr,unsafeForeignPtrToPtr,castForeignPtr,plusForeignPtr,newConcForeignPtr,addForeignPtrConcFinalizer,finalizeForeignPtr)whereimportForeign.StorableimportData.Foldable(sequence_)importGHC.ShowimportGHC.BaseimportGHC.IORefimportGHC.STRef(STRef(..))importGHC.Ptr(Ptr(..),FunPtr(..))-- |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-- The Addr# in the ForeignPtr object is intentionally stored-- separately from the finalizer. The primary 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. As a secondary benefit, this representation-- allows pointers to subregions within the same overall block-- to share the same finalizer (see 'plusForeignPtr'). Note-- that touchForeignPtr only has to touch the ForeignPtrContents-- object, because that ensures that whatever the finalizer is-- attached to is kept alive.dataFinalizers=NoFinalizers|CFinalizers(Weak#())|HaskellFinalizers[IO()]dataForeignPtrContents=PlainForeignPtr!(IORefFinalizers)|MallocPtr(MutableByteArray#RealWorld)!(IORefFinalizers)|PlainPtr(MutableByteArray#RealWorld)-- | @since 2.01instanceEq(ForeignPtra)wherep==q=unsafeForeignPtrToPtrp==unsafeForeignPtrToPtrq-- | @since 2.01instanceOrd(ForeignPtra)wherecomparepq=compare(unsafeForeignPtrToPtrp)(unsafeForeignPtrToPtrq)-- | @since 2.01instanceShow(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.---- Note that the foreign function /must/ use the @ccall@ calling convention.--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=errorWithoutStackTrace"mallocForeignPtr: size must be >= 0"|otherwise=dor<-newIORefNoFinalizersIO$\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=errorWithoutStackTrace"mallocForeignPtrBytes: size must be >= 0"mallocForeignPtrBytes(I#size)=dor<-newIORefNoFinalizersIO$\s->casenewPinnedByteArray#sizesof{(#s',mbarr##)->(#s',ForeignPtr(byteArrayContents#(unsafeCoerce#mbarr#))(MallocPtrmbarr#r)#)}-- | This function is similar to 'mallocForeignPtrBytes', except that the-- size and alignment of the memory required is given explicitly as numbers of-- bytes.mallocForeignPtrAlignedBytes::Int->Int->IO(ForeignPtra)mallocForeignPtrAlignedBytessize_align|size<0=errorWithoutStackTrace"mallocForeignPtrAlignedBytes: size must be >= 0"mallocForeignPtrAlignedBytes(I#size)(I#align)=dor<-newIORefNoFinalizersIO$\s->casenewAlignedPinnedByteArray#sizealignsof{(#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=errorWithoutStackTrace"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=errorWithoutStackTrace"mallocPlainForeignPtrBytes: size must be >= 0"mallocPlainForeignPtrBytes(I#size)=IO$\s->casenewPinnedByteArray#sizesof{(#s',mbarr##)->(#s',ForeignPtr(byteArrayContents#(unsafeCoerce#mbarr#))(PlainPtrmbarr#)#)}-- | This function is similar to 'mallocForeignPtrAlignedBytes', 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.mallocPlainForeignPtrAlignedBytes::Int->Int->IO(ForeignPtra)mallocPlainForeignPtrAlignedBytessize_align|size<0=errorWithoutStackTrace"mallocPlainForeignPtrAlignedBytes: size must be >= 0"mallocPlainForeignPtrAlignedBytes(I#size)(I#align)=IO$\s->casenewAlignedPinnedByteArray#sizealignsof{(#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->insertCFinalizerrfp0#nullAddr#p()MallocPtr_r->insertCFinalizerrfp0#nullAddr#pc_->errorWithoutStackTrace"GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"-- Note [MallocPtr finalizers] (#10904)---- When we have C finalizers for a MallocPtr, the memory is-- heap-resident and would normally be recovered by the GC before the-- finalizers run. To prevent the memory from being reused too early,-- we attach the MallocPtr constructor to the "value" field of the-- weak pointer when we call mkWeak# in ensureCFinalizerWeak below.-- The GC will keep this field alive until the finalizers have run.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->insertCFinalizerrfp1#epp()MallocPtr_r->insertCFinalizerrfp1#eppc_->errorWithoutStackTrace"GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"addForeignPtrConcFinalizer::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<-insertHaskellFinalizerrfinalizerifnoFinalizersthenIO$\s->caserof{IORef(STRefr#)->casemkWeak#r#()(unIO$foreignPtrFinalizerr)sof{(#s1,_#)->(#s1,()#)}}elsereturn()addForeignPtrConcFinalizer_f@(MallocPtrfor)finalizer=donoFinalizers<-insertHaskellFinalizerrfinalizerifnoFinalizersthenIO$\s->casemkWeak#fo()finalizer'sof(#s1,_#)->(#s1,()#)elsereturn()wherefinalizer'::State#RealWorld->(#State#RealWorld,()#)finalizer'=unIO(foreignPtrFinalizerr>>touchf)addForeignPtrConcFinalizer___=errorWithoutStackTrace"GHC.ForeignPtr: attempt to add a finalizer to plain pointer"insertHaskellFinalizer::IORefFinalizers->IO()->IOBoolinsertHaskellFinalizerrf=do!wasEmpty<-atomicModifyIORefr$\finalizers->casefinalizersofNoFinalizers->(HaskellFinalizers[f],True)HaskellFinalizersfs->(HaskellFinalizers(f:fs),False)_->noMixingErrorreturnwasEmpty-- | A box around Weak#, private to this module.dataMyWeak=MyWeak(Weak#())insertCFinalizer::IORefFinalizers->Addr#->Int#->Addr#->Addr#->value->IO()insertCFinalizerrfpflageppval=doMyWeakw<-ensureCFinalizerWeakrvalIO$\s->caseaddCFinalizerToWeak#fppflagepwsof(#s1,1##)->(#s1,()#)-- Failed to add the finalizer because some other thread-- has finalized w by calling foreignPtrFinalizer. We retry now.-- This won't be an infinite loop because that thread must have-- replaced the content of r before calling finalizeWeak#.(#s1,_#)->unIO(insertCFinalizerrfpflageppval)s1ensureCFinalizerWeak::IORefFinalizers->value->IOMyWeakensureCFinalizerWeakref@(IORef(STRefr#))value=dofin<-readIORefrefcasefinofCFinalizersweak->return(MyWeakweak)HaskellFinalizers{}->noMixingErrorNoFinalizers->IO$\s->casemkWeakNoFinalizer#r#(unsafeCoerce#value)sof{(#s1,w#)->-- See Note [MallocPtr finalizers] (#10904)caseatomicModifyMutVar#r#(updatew)s1of{(#s2,(weak,needKill)#)->ifneedKillthencasefinalizeWeak#ws2of{(#s3,_,_#)->(#s3,weak#)}else(#s2,weak#)}}whereupdate_fin@(CFinalizersw)=(fin,(MyWeakw,True))updatewNoFinalizers=(CFinalizersw,(MyWeakw,False))update__=noMixingErrornoMixingError::anoMixingError=errorWithoutStackTrace$"GHC.ForeignPtr: attempt to mix Haskell and C finalizers "++"in the same ForeignPtr"foreignPtrFinalizer::IORefFinalizers->IO()foreignPtrFinalizerr=dofs<-atomicModifyIORefr$\fs->(NoFinalizers,fs)-- atomic, see #7170casefsofNoFinalizers->return()CFinalizersw->IO$\s->casefinalizeWeak#wsof(#s1,1#,f#)->fs1(#s1,_,_#)->(#s1,()#)HaskellFinalizersactions->sequence_actionsnewForeignPtr_::Ptra->IO(ForeignPtra)-- ^Turns a plain memory reference into a foreign pointer that may be-- associated with finalizers by using 'addForeignPtrFinalizer'.newForeignPtr_(Ptrobj)=dor<-newIORefNoFinalizersreturn(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.castForeignPtr=coerceplusForeignPtr::ForeignPtra->Int->ForeignPtrb-- ^Advances the given address by the given offset in bytes.---- The new 'ForeignPtr' shares the finalizer of the original,-- equivalent from a finalization standpoint to just creating another-- reference to the original. That is, the finalizer will not be-- called before the new 'ForeignPtr' is unreachable, nor will it be-- called an additional time due to this call, and the finalizer will-- be called with the same address that it would have had this call-- not happened, *not* the new address.---- @since 4.10.0.0plusForeignPtr(ForeignPtraddrc)(I#d)=ForeignPtr(plusAddr#addrd)c-- | Causes the finalizers associated with a foreign pointer to be run-- immediately.finalizeForeignPtr::ForeignPtra->IO()finalizeForeignPtr(ForeignPtr_(PlainPtr_))=return()-- no effectfinalizeForeignPtr(ForeignPtr_foreignPtr)=foreignPtrFinalizerrefFinalizerswhererefFinalizers=caseforeignPtrof(PlainForeignPtrref)->ref(MallocPtr_ref)->refPlainPtr_->errorWithoutStackTrace"finalizeForeignPtr PlainPtr"
[8]ページ先頭