<div dir="ltr">I think I have found what causes deadlock. I have made sort of cache for binaries and use global lock as first testing solution to prove concept. There is a scenario when I return enif_make_resource_binary and then make sub-binary of this binary (in erlang code) and then store this code again in cache. Then reference sub-binary reaches zero, it calls resource destructor, locks mutex and removes from cache which calls enif_free_env() witch causes calling destructor of its resource which tries lock mutex again. It can't happen when I have used fresh new binary in mine previous version.<br>
I have tested to remove the only possible place in erlang where any sub-binary of existing binary can be stored in cache and it works. So now I have to wrap head around how call enif_free_env() outside mutex-locked code part.<br>
Anyway thanks a lot for your help.<div>    Hynek</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Sep 1, 2014 at 7:26 PM, Sverker Eriksson <span dir="ltr"><<a href="mailto:sverker.eriksson@ericsson.com" target="_blank">sverker.eriksson@ericsson.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Looks like that should work if you're doing it right.<br>
<br>
* Do you update shared data (like your reference counters) in a thread safe manner?<br>
<br>
* Another way is to store the copied binary term and then use enif_make_copy(env, entry->content.bin.term)<br>
to return the binary. You can also combine it with enif_make_sub_binary if you want to return part of the binary.<br>
<br>
* Use debug built VM to ease trouble shooting:<br>
<br>
cd $ERL_TOP/erts/emulator && make TYPE=debug smp plain<br>
$ERL_TOP/bin/cerl -debug<br>
<br>
<br>
/Sverker, Erlang/OTP<div class="HOEnZb"><div class="h5"><br>
<br>
<br>
On 08/30/2014 07:07 AM, Hynek Vychodil wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Thanks for your answer very much. If I understand it correctly this way it<br>
should be safe:<br>
<br>
      ErlNifBinary bin;<br>
      if (!enif_is_binary(env, argv[0]))<br>
          return enif_make_badarg(env);<br>
<br>
      ErlNifEnv *priv_env = enif_alloc_env();<br>
      ERL_NIF_TERM term = enif_make_copy(priv_env, argv[0]);<br>
      ErlNifBinary bin;<br>
      enif_inspect_binary(priv_env, term, &bin);<br>
      entry->content.bin = (struct my_bin){.env = priv_env, .size =<br>
bin.size, .data = bin.data};<br>
<br>
And now mine entry->content.bin.data should be safe but unfortunately it<br>
still eventually hangs whole VM after few thousands cycles of referencing<br>
this data<br>
<br>
         CacheEntryRes_t *res = enif_alloc_resource(dc_entry_<u></u>type,<br>
sizeof(CacheEntryRes_t));<br>
         unless (res) return insufficient_memory(env);<br>
         res->entry = entry;<br>
         ERL_NIF_TERM result = enif_make_resource_binary(env, res,<br>
                 entry->content.bin.data, entry->content.bin.size);<br>
         enif_release_resource(res);<br>
         return result;<br>
<br>
I do mine own reference count and release by<br>
<br>
        enif_free_env(entry->content.<u></u>bin.env);<br>
<br>
It hangs only if I replace enif_alloc() + memcpy() and enif_free() version<br>
with above one :-(<br>
<br>
Thanks<br>
      Hynek<br>
<br>
<br>
On Fri, Aug 29, 2014 at 3:02 PM, Sverker Eriksson <<br>
<a href="mailto:sverker.eriksson@ericsson.com" target="_blank">sverker.eriksson@ericsson.com</a>> wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On 08/28/2014 03:09 PM, Hynek Vychodil wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi all,<br>
I would like to know if binaries are relocatable. If I have binary<br>
parameter<br>
<br>
      ErlNifBinary bin;<br>
      if (!enif_inspect_binary(env, argv[0], &bin))<br>
          return enif_make_badarg(env);<br>
<br>
I store binary in mine own environment<br>
<br>
      ErlNifEnv *priv_env = enif_alloc_env();<br>
      enif_make_copy(priv_env, argv[0]);<br>
<br>
Can I then rely on bin.data pointing into same memory until I free<br>
enif_free_env(priv_env) ?<br>
<br>
</blockquote>
No.<br>
Your bin.data is refering to the original term argv[0] in 'env' which is<br>
only valid until the NIF returns.<br>
You must do enif_inspect_binary on the copy in order to get a safe pointer<br>
that is valid until you do enif_free_env(priv_env).<br>
<br>
<br>
<br>
    I'm asking because I would like to avoid copying<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
and share data or even return it using enif_make_resource_binary to catch<br>
and<br>
count references.<br>
<br>
</blockquote>
Whether a copied binary share data with its original is implementation<br>
dependent. Today big binaries (>64 bytes) are shared<br>
and small binaries are copied between environments.<br>
<br>
<br>
  I have code which makes copy of binary data but when I switch to reference<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
bin.data it hangs whole VM. I would like to know if I make some mistake in<br>
mine code and it should work or it is wrong idea at all.<br>
<br>
<br>
  There is a known bug when calling enif_make_copy after<br>
</blockquote>
enif_inspect_binary<br>
that can cause the binary to get reallocated and thus the bin.data pointer<br>
to get invalid<br>
before the NIF returns. To detect this bug, you can call<br>
enif_inspect_binary(env,argv[<u></u>0],&bin2)<br>
after enif_make_copy and check if bin2.data != bin.data.<br>
<br>
This bug has been lingering as I thought it was an exotic scenario<br>
(apparently not) and I have<br>
been a bit unsure how to fix it without ruin performance.<br>
<br>
<br>
/Sverker, Erlang/OTP<br>
<br>
<br>
</blockquote></blockquote>
<br>
</div></div></blockquote></div><br></div>