[Haskell-cafe] FFI woes!

Ben Rudiak-Gould Benjamin.Rudiak-Gould at cl.cam.ac.uk
Thu Dec 16 10:08:57 EST 2004

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

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

More information about the Haskell-Cafe mailing list