fpco / inline-c

284 stars 50 forks source link

Howto call haskell functions from internal C callbacks? #96

Closed alaendle closed 4 years ago

alaendle commented 4 years ago

Maybe this is more a general Haskell FFI question. But what is the recommended way to call a haskell function within a C callback. Conceptual this shouldn't be a problem since the haskell function - in this case adderIO is somehow constant and not part of a "closure". However the FFI call inside the callback fails with a segmentation fault, while the second call within the scope succeeds. My guess is that this has to do with the internal workings of the FFI, but since I tried to find a workaround for some time, I really hope that someone here is able come up with a elegant solution just like that :wink:

Here is a small sample that should illustrate my problem - please let me know if I was unclear! Thanks in advance for any assistance.

adderIO a b =  return $ a + b

setMessageCallback :: ModuleClient -> (String -> IO ()) -> IO ()
setMessageCallback (ModuleClient client) callback = do
  let handle = fromIntegral client
  result <- [C.block| int { 
      IOTHUBMESSAGE_DISPOSITION_RESULT messageHandler(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback) { 
        printf("adder: [%i]\r\n",$fun:(long (*adderIO)(long, long))(4, 4));  // <- seg fault
        return IOTHUBMESSAGE_ACCEPTED;
      };

      IoTHubModuleClient_LL_SetMessageCallback($(int handle), messageHandler, NULL);
      printf("adder: [%i]\r\n",$fun:(long (*adderIO)(long, long))(4, 4));  // <- succeeds
      return 0;
    } |]
  pure ()
alaendle commented 4 years ago

Don't worry - I found the $fun-allow quoter in combination with freeHaskellFunPtr. Now things work as expected; many thanks for providing such a useful library to simplify FFI code!