I’m building a project that controls a quad copter via usb dongle. I have a cpp api to interact with it via various methods and callbacks, so i went about writing a NIF that uses a thread and enif_send
to send data back to Elixir/Erlang.
It all works pretty good, but it seems like the GC is calling the dtor function on my resource (which stops my thread) after a pretty short amount of time, which causes me to loose a connection to the copter causing it to fall out of the air. Is there any info out there on what causes ERTS to garbage collect enif_resources? I know of at least one situation where the reference count goes to zero ie:
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, cf} = Crazyflie.connect("radio://0/80/250k") # nif call that starts a `enif_thread`
iex(2)> respawn()
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> rt_dtor called
cleaning up thread
now since nothing holds a reference to cf
anymore, it gets destructed. Ideally that should be the only time i would think, but something is causing my cf
variable to be garbage collected, then restarted for some reason.
I’m wrapping it in a simple gen_server currently:
defmodule Crazyflie.Server do
use GenServer
def start_link(args \\ ["radio://0/80/250k"]) do
[uri] = args
GenServer.start_link(__MODULE__, args, name: name(uri))
end
def subscribe(uri \\ "radio://0/80/250k") do
GenServer.call(name(uri), {:subscribe, self()})
end
def init([uri]) do
{:ok, cf} = Crazyflie.connect(uri)
{:ok, %{cf: cf, uri: uri, reg: nil}}
end
def terminate(reason, _) do
IO.inspect(reason, label: "Server died")
end
def handle_info(info, %{reg: nil} = state) do
{:noreply, state}
end
def handle_info(info, state) do
send(state.reg, {__MODULE__, {state.uri, info}})
{:noreply, state}
end
def handle_call({:subscribe, pid}, _, state) do
{:reply, :ok, %{state | reg: pid}}
end
defp name(uri) do
:"#{uri}"
end
end
The genserver itself (which is started in a supervision tree) never exits, but the nif destructor still is being called.