reprise icon indicating copy to clipboard operation
reprise copied to clipboard

Reloading of nif modules

Open tinglei8 opened this issue 9 years ago • 5 comments

After a nif module is reloaded, all the nif functions are overwritten by elixir placeholders.

defmodule test_nif do

  require Logger

  @on_load :init

  def init() do
    :erlang.load_nif("./priv/test_nif", 0)
    :ok
  end

  def test_a() do
    Logger.error "NIF library not loaded"
  end

end

After reloading test_a.beam, test_nif.test_a() will call the placeholder instead of nif functions.

One way I can think of to solve the glitch is to add an _on_reprise_reload() function to test_nif:

def _on_reprise_reload() do 
  init()
end

And have reprise call the function after reloading the module

But there might be better ways.

tinglei8 avatar Jun 23 '15 03:06 tinglei8

Hi!

I never worked with NIFs. So what I say is a good practice which comes to mind when handling corner cases like this one - assuming that there might be more similar corner cases around :)

More elegant solution would be to call some configured function on a reloaded NIF module (if it's exported). Name of such function - like _on_reprise_reload would go to your app config.exs.

The question is: how to detect that a module contains NIFs?

Are you able to come up with a prototype PR?

cheers,

W.

wkhere avatar Jun 27 '15 10:06 wkhere

Hi, Thanks for your advice!

I've come up with a simple fix to support a "general reload hook", not made for NIFs. In that case people can do all the things in the hook function, I think it's more general and useful than targeting NIF use cases specifically.

Didn't come up with a unit test yet but I already use it in my project and it worked great.

For my previous example, now it can be fixed like this:

defmodule test_nif do

  require Logger

  @on_load :init

  def init() do
    :erlang.load_nif("./priv/test_nif", 0)
    :ok
  end

  def _reprise_on_reload() do 
    init()
  end

  def test_a() do
    Logger.error "NIF library not loaded"
  end

end

tinglei8 avatar Jun 30 '15 08:06 tinglei8

Hi, turns out there is a built-in reload feature for erlang nifs.

Just implement the 'load', 'upgrade', 'unload' callbacks for ERL_NIF_INIT macro and erlang handles nif reload for you when the module is reloaded, there is no need to call load_nif() again in _reprise_on_reload()

That said, maybe there are other aspects people can use a _reprise_on_reload() callback on reprise. I kept reload mechanism in my project and worked fine.

tinglei8 avatar Jul 13 '15 10:07 tinglei8

Hello!

I hope you don't mind this project evolving rather slowly.. :)

I think you're right that _reprise_on_reload() can be useful. I see no reason in blocking this going to master which then gets "hexified" with all good implications of it.

Still I'm tempted to have a simple regression test for this, as I said previously in the pull request comment. Do you have an idea or a skeleton of how such test for a callback might work?

cheers,

W.

wkhere avatar Oct 20 '15 22:10 wkhere

Hi,

Sorry for the late reply! I was busy with the day jobs.

I've written a simple test to test calling hooks, not a very comprehensive one but I think it's better than nothing.

cheers, Lei

tinglei8 avatar Nov 09 '15 08:11 tinglei8