Can you help me use a C function, from F#, that expects a callback? I am using F#, mono and Arch Linux, on the ARM processor based Raspberry Pi 2.
My original problem, understanding the signature to use for the callback, was answered which you can read for more context.
I have reached an impasse. When using the library, the program crashes with a segmentation fault.
I believe that this is because of a marshalling mismatch. The "the clr supports only the std calling convention for marshalling function pointers" according to the book Expert F# 3.0. The CLR assumes that the callee will clean the stack (StdCall) and the C library expects that the caller will clean the stack (Cdecl) according to the definition on MSDN. Hence the memory leak.
Sadly, I can find no way to make the CLR use Cdecl for this delegate nor for C to use StdCall on an ARM processor. I haven't written the C library but I do have access to the source code.
Here is the function signature in C
int wiringPiISR (int pin, int edgeType, void (*function)(void)) ;
and part of my F# code:
type ISRCallback = delegate of unit -> unit
[<DllImport(wiringPiLib, EntryPoint = "wiringPiISR", CallingConvention = CallingConvention.Cdecl, SetLastError=true)>]
extern int wiringPiISR(int pin, int mode, [<MarshalAs(UnmanagedType.FunctionPtr)>]ISRCallback callBack);
Decorating the delegate with [<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
doesn't help. The compiler silently ignores it, which I think is how these attributes are designed to work.
Is there another way to do this - perhaps editing the C code, or wrapping it in another way? (C++ perhaps?)
Note: there is an interesting article on the mono-project website titled Interop with Native Libraries
In the meantime, I have written a little loop to poll the GPIO pins. Not ideal but it works.
EDIT: I was wrong in my memory leak assumption but, thanks to the comments and the research it prompted, I learnt a lot and found answers.