
Sebastian Sylvan wrote:
On Thu, 16 Dec 2004 08:56:15 -0500, Robert Dockins
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.