How to access hs_free_fun_ptr from a Visual Studio DLL

Brian Hulley brianh at metamilk.com
Sun Mar 26 17:56:00 EST 2006


Sven Panne wrote:
> Am Samstag, 25. März 2006 20:00 schrieb Brian Hulley:
>> I've found a workaround to the problem below: instead of trying to
>> use hs_free_fun_ptr, I instead pass a FunPtr to the Haskell function
>> freeHaskellFunPtr into my DLL, and use this to free everything,
>> finally using it to free itself (!) which I assume should be safe.
>> [...]
>
> It has been quite some time since I've worked on GHC's Adjustor.c and
> Hugs'
> FFI, but IIRC it is in general *not* safe to do this. On some
> platforms code
> is being generated dynamically for these kind of callbacks, which has
> already
> been freed by the time the callback returns. This might appear to
> work,
> depending on your processor architecture and dynamic memory management
> behaviour, but it's better not to rely on this. Perhaps the FFI spec
> should
> be clearer here.
>
> I had a similar problem in for timer callbacks in my GLUT binding.
> They are
> one-shot and have to clean themselves up after the callback executes.
> The
> solution was to register the FunPtrs to be cleaned up only and do the
> real
> work in another "scavenger" callback, see
> http://darcs.haskell.org/packages/GLUT/Graphics/UI/GLUT/Callbacks/Registration.hs

Thanks Sven for saving me from a horrible bug! :-) I've changed my code so 
that the DLL now only uses the FunPtr to freeHaskellFunPtr to release other 
callbacks, then I use freeHaskellFunPtr to free the FunPtr I passed in to 
the DLL from the Haskell side of the API to avoid a closure freeing itself 
ie:

foreign import ccall duma_begin :: FunPtr (FunPtr a -> IO ()) -> IO Bool
foreign import ccall duma_run :: IO ()
foreign import ccall duma_end :: IO ()

foreign import ccall "wrapper" mkFreeFunPtr :: (FunPtr a -> IO ()) -> IO 
(FunPtr (FunPtr a -> IO ()))

run :: IO a -> IO ()
run f = bracket
              (mkFreeFunPtr freeHaskellFunPtr
              )
              (\freeFunPtrFn -> do
                  duma_end
                  freeHaskellFunPtr freeFunPtrFn
              )
              (\freeFunPtrFn -> do
                  initialized <- duma_begin freeFunPtrFn
                  if (initialized)
                      then f >> duma_run
                      else return ()
              )

Thanks, Brian. 



More information about the Glasgow-haskell-users mailing list