
Sebastian Sylvan wrote:
Ben Rudiak-Gould wrote:
Why not spawn a thread which starts the playback, waits for it to finish, and then exits, and wrap the whole thread in a call to withForeignPtr? Then your finalizer won't be called prematurely.
Well I could do this, but for one it would be cumbersome to stop playback.
I don't think it is. Let me try to specify the problem precisely to make sure we're talking about the same thing. We have an interface something like this: loadSong :: String -> IO (Ptr SongRep) playSong :: Ptr SongRep -> IO () stopPlaying :: Ptr SongRep -> IO () -- it will also stop by itself isPlaying :: Ptr SongRep -> IO Bool freeSong :: Ptr SongRep -> IO () -- unsafe if song is playing and we want an interface like this: loadSong' :: String -> IO Song playSong' :: Song -> IO () stopPlaying' :: Song -> IO () isPlaying' :: Song -> IO Bool I think this implementation will work: type Song = ForeignPtr SongRep loadSong' name = loadSong name >>= newForeignPtr freeSong playSong' song = forkIO (withForeignPtr song (\s -> playSong s >> waitForSilence s)) waitForSilence s = do threadDelay 500000 b <- isPlaying s when b (waitForSilence s) stopPlaying' song = withForeignPtr song stopPlaying isPlaying' song = withForeignPtr song isPlaying If you need the return value from playSong, this should also work: playSong' song = do rtn <- withForeignPtr song playSong forkIO (withForeignPtr song waitForSilence) return rtn But this won't work, because the withForeignPtr call will return before the thread exits: brokenPlaySong' song = withForeignPtr song (\s -> playSong >> forkIO (waitForSilence s)) -- Ben