I’m trying to figure out a way to initiate a call to the Elixir application from a linked port driver. I have a library in C, which functions as a server. It creates a thread when it’s initialised from Elixir, which sevices network requests in C. I can make calls from Elixir down to the driver and send messages to it. However, if the server needs to respond to a request, it cannot make calls back up to Elixir. I thought this would be straightfoward with driver_output() function, but then I don’t have the driver handle and I suppose the message in Elixir would be handled asynchronously too.
Any suggestions as to how this can be done?
You cannot call Erlang/Elixir from a driver or nif.
The thread that does the request could wait on a futex (or similar) after sending a message to the process that needs to run some Erlang/Elixir code. Then when the process is done it can call the driver/nif again and deliver the response and trigger the futex.
It is not easy to do things this way, but it is possible. For instance, I think that the wx application in Erlang handles some of the wx callbacks this way.
thank you very much for confirming this for me.
Will take a look at the futex. Otherwise, we may need to rething our design.
I have a cracking idea.
• You might be able to cheat by passing a reference to a separately handled UNIX socket.
• Alternatively, make your external thing a C node and integrate Erlang Distribution (i.e. change the design). Still, have your Elixir app spawn & manage it, possibly via saleyn/erlexec or some other libraries that were proven to be robust.
Making the external thing into its own C / Java node, is a viable option, and I have used this approach with great success.
I recently asked about a very similar situation (calling a function from a NIF) over on the Erlang forums. There is no straightforward way to do this, but there are a number of interesting workarounds.
The core approach is similar to what @garazdawi also mentions: Use a separate Elixir/Erlang process which you exchange messages with. To hide this async communication inside a function that expects to run in a normal synchronious fashion, using any kind of mutex to wait for a reply (/or crash) from the process.