fpco / inline-c

284 stars 50 forks source link

Add easy way to declare `FunPtr`s for newForeignPtr #77

Closed nh2 closed 5 years ago

nh2 commented 5 years ago

Please add functionality that allows me to declare FunPtrs inline, so that I can directly write newForeignPtr code easily.

For example something like:

fp <- newForeignPtr [C.funPtr| void myfree(char * ptr) { puts("freeing"); free(ptr); } |] ptr

Because this isn't easily doable currently, many people resolve to Foreign.Concurrent.addForeignPtr which is an antipattern because it calls its finaliser even later than the normal addForeignPtr (or worse, not at all if the program terminates, which creates spurious memory leak reports in valgrind).

This even-later finalisation can lead to excessive memory usage in real-world applications, because the normal newForeignPtr triggers under GC caused by memory pressure, but the Foreign.Concurrent one does not (it depends on its thread being run, which is even less likely under memory pressure).


As a reminder, the normal one has a FunPtr finaliser because that allows calling straight back to C, while the Concurrent one has IO (), which is Haskell and can't be guaranteed to be callable from GC.

That is explained here: "C finalizers are run on the spot during GC, while Haskell finalizers are batched together into a list and then shunted off to a freshly created thread to be run".

The types involved in newForeignPtr are:

newForeignPtr :: FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)

type FinalizerPtr a = FunPtr (Ptr a -> IO ()) 

so what I'm looking for is a quasiquoter that creates TExp (FunPtr (Ptr a -> IO ())) from some anonymous, inline C function void myfree(char * ptr){ ... } (ideally it wouldn't even need a name, but in C you have to give it one and it's good for debugging with gdb if it has a name).


By making the normal newForeignPtr easy to write with inline-c FunPtrs, we can ensure that more people use the normal, safer one.

nh2 commented 5 years ago

CC @basvandijk

basvandijk commented 5 years ago

This would be a great feature to have. In haskell-opencv we have a specific solution to opencv. It's called like this.

nh2 commented 5 years ago

Thanks!