[Haskell] using the ffi with callbacks

Evan Martin martine at danga.com
Thu Jul 20 06:51:58 EDT 2006


Suppose I have a C function like this:
  void register_callback(
    void (*callback_fcn)(void *data),
    void *callback_data,
    void (*free_fcn)(void *data));
I think this is pretty common in C libraries.  The idea is that you
can register a callback along with a pointer to some data to pass to
it, and when the C code is done with the callback+data it'll call your
free_fcn, again passing the same data.

I'd like to wrap this in Haskell, allowing me to pass in a Haskell
function as a callback.
The tricky part is that to pass in Haskell functions, I need to use
the FFI "wrapper" import, which means I need to later free them.  But
the only place I can free them is within the "free" callback, and I've
just discovered this isn't allowed!

To elaborate, the code setting this up looks something like this:
  callback_fcn <- ... -- get a FunPtr using "wrapper" from the ffi
  free_fcn <- ... -- as above
  -- the callback data is just stuff that needs freeing
  callback_data <- newStablePtr (callback_fcn, free_fcn)
  register_callback callback_fcn callback_data free_fcn
And my plan was: within the function free_fcn wraps, free
callback_fcn, free the StablePtr, and then finally free free_fcn
itself.

However, I discovered this thread, which indicates that having a
function free its FunPtr is not allowed:
http://www.haskell.org//pipermail/glasgow-haskell-users/2006-March/009907.html

I've poked around a bit online, and so far, the only solutions I've seen are
1) http://darcs.haskell.org/packages/GLUT/Graphics/UI/GLUT/Callbacks/Registration.hs
, which seems to involve three extra IORefs and unsafePerformIOs as
well as an external library function for registering the scavenger.
2) http://darcs.haskell.org/gtk2hs/glib/System/Glib/ , which seems to
either use a bunch of Haskell-specific C code I don't quite follow or
use the self-delete pattern I described above (see
mkFunPtrDestroyNotify in
http://darcs.haskell.org/gtk2hs/glib/System/Glib/GObject.chs.pp).

So my question is: is there really no simple way to support this
pattern (which I would broadly refer to as "callbacks in general"), or
am I missing something?


More information about the Haskell mailing list