[Haskell-cafe] FFI woes!

Robert Dockins robdockins at fastmail.fm
Thu Dec 16 11:08:13 EST 2004

Sebastian Sylvan wrote:

> On Thu, 16 Dec 2004 08:56:15 -0500, Robert Dockins
> <robdockins at fastmail.fm> wrote:
>>Return the high level value to the user; when the enclosed
>>ForeignPtr is garbage collected deRefWeak on the weak pointer will
>>return Nothing.  Then the clean-up thread can begin polling the song
>>object to see if it is finished.
> But if the ForeignPtr has been garbage collected, it's too late! The
> sound data is *gone* and the channel can no longer play the sound.

If you look closely at the code I posted, I do something tricky; I form 
a ForeignPtr (without a finalizer) from a Ptr, and then _keep them 
both_.  So, when the ForeignPtr is GCed, I still have the original 
pointer.  I detect the fact that the ForeignPtr is GCed by using a weak 
pointer.  Because of the way I set up my code, I know that when the 
ForeignPtr is gone, my clean-up thread is the only place that I have a 
pointer to the original C object.  So then I start polling the sound 
object to see if it is done playing, and only then free the C object.

> -- play a sample
> samplePlay :: SoundSample -> IO SamplePlayback
> samplePlay sample = do ch <- withForeignPtr sample (fsound_PlaySound (-1))
> 		       let spb = SP ch sample -- SamplePlaybackRaw
>                        mkWeakPtr spb (Just (samplePlaybackFinalizer spb))

Ahh... look.  You are returning a weak pointer!  Those specifically 
allow the referenced object to be garbage collected.  So the only 
references left to your SamplePlaybackRaw are (a) inside a weak pointer 
and (b) inside a finalizer closure.  Such references are NOT considered 
reachable from the root set, and can thus be GCed (I am about 90% sure 
this is true about finalizers).  You have arranged it so that the RTS 
can garbage collect spb, and thus the ch and sample, whenever it likes.

More information about the Haskell-Cafe mailing list