Search code examples
elixirerlang-ports

Port messages returning to an unexpected process


I have a simple ports app (literally the example from the Erlang -- Ports documentation) and a GenServer controlling its use.

The GenServer can communicate with the C app just fine but it doesn't receive the responses, iex or its supervisor does. If I call flush from iex, I see the expected message.

If I create a separate module and spawn a receive loop from it, it still doesn't receive the port response messages.

I have a feeling I'm incorrectly opening the Port but cannot prove it. Is there anything obvious I'm screwing up?

port = Port.open({:spawn, "./extprg"}, [{:packet, 2}, :exit_status])
collect = fun () -> collect_results(port) end
spawn(collect)


def collect_results(port) do
   receive do
      {^port, {:data, data}} -> 
          #never gets called despite matching messages in flush
      {^port, {:exit_status, status}} ->
          #never gets called...

      {:increment, value} ->
          Port.command(port, [1, value])
          collect_results(port)
   end
end

Solution

  • When opening a port from a module that uses GenServer, ensure you are calling Port.open in the init function and not the start or start_link functions. init is ran by the new process, where start and start_link are both still the calling process.

    Here is an example of a GenServer that uses a port:

    https://github.com/fhunleth/elixir_ale/blob/master/lib/i2c.ex