leonardorame
Long running C++ NIF segfaults
Hi, I built a NIF out of a well known C++ Dicom library called DCMTK. The purpouse of this NIF is to stay loaded for the whole life of my Elixir/Phoenix application, where it’s functions are called many times.
The module that loads this NIF is called from an Agent and I thought it stay there forever, but as it is segfaulting after using it for a while I’m starting to think it is removed from memory after some time…
Let me show my code:
defmodule Prueba3.ImageCache do
use Agent
def start_link(_opts) do
Dcmtknif.initialize()
Agent.start_link(fn -> %{} end, name: :imagecache)
end
def get(key) do
Agent.get(:imagecache, &Map.get(&1, key))
end
def put(key, value) do
Agent.update(:imagecache, &Map.put(&1, key, value))
end
end
defmodule Dcmtknif do
@on_load :load_nifs
def load_nifs do
:erlang.load_nif('./ssr/libssr', 0)
end
def _loadDicomFile(_dicomfile) do
raise "NIF _loadDicomFile/1 not implemented"
end
def _getTagValue(_dcmff, _group, _element) do
raise "NIF getTagValue/1 not implemented"
end
def _getHeader(_dcmff) do
raise "NIF getHeader/1 not implemented"
end
def _getPNG(_dcmff) do
raise "NIF getPNG/1 not implemented"
end
def _setMinMaxWindow(_dcmff) do
raise "NIF setMinMaxWindow/1 not implemented"
end
def _createScaledImage(_dcmff, _width, _height, _interpolate, _aspect) do
raise "NIF createScaledImage/5 not implemented"
end;
def _initialize() do
IO.puts("Dcmtknif.initialize()")
raise "NIF initialize/0 not implemented"
end
def _finalize() do
raise "NIF finalize/0 not implemented"
end
... more functions
end
Do you see something wrong?
Most Liked
whatyouhide
I’m not an expert in NIFs, but in general the VM yields execution to the NIF when you call it, so you’re really not supposed to have “long-running NIFs”. When you enter a NIF, the VM cannot do GC, context, switching, and so on anymore.
I think a common solution in a case like yours, where you have essentially an external program that needs to run continuously, is to use ports. You spawn the program you want to run and you let your Elixir application manage its lifetime. Then, you communicate with the spawned program through stdout.
Does that make sense?
leonardorame
Hi @whatyouhide, I think I wrongly explained what this NIF does. With “long-running” I mean it has state (internal variables pointing to data structures that can be accessed from the parent Elixir process), please don’t confuse with long loops or heavy processes inside it.
Regarding your ports suggestion, I can do that, but it adds complexity on the C++ side and I’m trying to maintain that part as small as possible.
jhogberg
I can assure you that the NIF hasn’t been unloaded. You would need to do that manually, and even then the VM takes great care not to pull the rug while anything references it.
I think I can see why it crashes though. What’s preventing image/2 from being called concurrently?
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









