wkhere / reprise

Simplified module reloader for Elixir
hex.pm/packages/reprise
BSD 2-Clause "Simplified" License
43 stars 10 forks source link

Reloading of nif modules #12

Open tinglei8 opened 9 years ago

tinglei8 commented 9 years ago

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.

wkhere commented 9 years ago

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.

tinglei8 commented 9 years ago

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 commented 9 years ago

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.

wkhere commented 8 years ago

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.

tinglei8 commented 8 years ago

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