weak resource reference possible in nif ?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

weak resource reference possible in nif ?

Skype Xu
Hi,

Suppose a nif module is multi-threaded, we keep a pointer to a resource
in the
module's internal list, when the resource is no longer used by erlang
process,
erlang vm calls the resource's destructor, and we remove the pointer from
internal list in the destructor, that's fine.
However a problem arises when the internal list is also used by another
thread
created in the nif module, when some external events were triggered, the
thread
tries to use the resource pointer and sends it to a process in the vm,
problem
is there's a race condition between destructor and the internal thread,
in the destructor we try to remove it from the internal list, at the
time, the
resource's reference count is already zero, and before the destructor is
called,
the internal thread sent the resource to a proecess, by calling
enif_make_resource() to increase the count to 1, but anyway after the
destructor returned, the vm will recycle the memory of the resource
despites
the reference count is 1 again, this leads to corrupted memory.

We can not keep a resource by adding extra reference count in nif module,
if we do, the resource's destructor will never be called even if not any
erlang
process is using the resource, because the reference count will never to
dropped to 0.

It would be perfect if we can keep a weak reference in nif like the one in
C++ does, one can use weak_ptr to get back a shared_ptr object if the
object
is still using, otherwise a null pointer is returned.  if this is
implemented, we
can queue a notification to the internal thread and the thread will remove
any data related to the resource.  enif_monitor_process() is not a solution
because we want vm to recycle the resource when it is not used, not after
a process crashed or exited.

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: weak resource reference possible in nif ?

Max Lapshin-2
The main problem here is with reference count.

You should use this mechanism and properly protect access to data with brackets  inc/dec



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: weak resource reference possible in nif ?

John Högberg
In reply to this post by Skype Xu
Hi,

Why not let the resource hold nothing besides a shared_ptr to the
actual data, and use weak_ptrs in the internal list?

You'd need to allocate a new resource when sending notifications from
that internal thread (Since the original resource could have been
destroyed), but other than that it should be pretty straightforward
unless I've misunderstood something.

Regards,
John Högberg

On ons, 2017-11-08 at 17:32 +0800, Skype Xu wrote:

> Hi,
>
> Suppose a nif module is multi-threaded, we keep a pointer to a
> resource 
> in the
> module's internal list, when the resource is no longer used by
> erlang 
> process,
> erlang vm calls the resource's destructor, and we remove the pointer
> from
> internal list in the destructor, that's fine.
> However a problem arises when the internal list is also used by
> another 
> thread
> created in the nif module, when some external events were triggered,
> the 
> thread
> tries to use the resource pointer and sends it to a process in the
> vm, 
> problem
> is there's a race condition between destructor and the internal
> thread,
> in the destructor we try to remove it from the internal list, at the 
> time, the
> resource's reference count is already zero, and before the destructor
> is 
> called,
> the internal thread sent the resource to a proecess, by calling
> enif_make_resource() to increase the count to 1, but anyway after the
> destructor returned, the vm will recycle the memory of the resource 
> despites
> the reference count is 1 again, this leads to corrupted memory.
>
> We can not keep a resource by adding extra reference count in nif
> module,
> if we do, the resource's destructor will never be called even if not
> any 
> erlang
> process is using the resource, because the reference count will never
> to
> dropped to 0.
>
> It would be perfect if we can keep a weak reference in nif like the
> one in
> C++ does, one can use weak_ptr to get back a shared_ptr object if
> the 
> object
> is still using, otherwise a null pointer is returned.  if this is 
> implemented, we
> can queue a notification to the internal thread and the thread will
> remove
> any data related to the resource.  enif_monitor_process() is not a
> solution
> because we want vm to recycle the resource when it is not used, not
> after
> a process crashed or exited.
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: weak resource reference possible in nif ?

Skype Xu
We don't want to get a new resource term every time when we got a new
notification,
we want to simply use erlang pattern matching without another function
to retrieve
actual data in the resource and matching against the data,  if we do
this,  a programmer
can keep the data around for later matching, and may forget to keep the
resource, then
what's the reason to use erlang resource? we would give up.


On 2017年11月08日 18:59, John Högberg wrote:

> Hi,
>
> Why not let the resource hold nothing besides a shared_ptr to the
> actual data, and use weak_ptrs in the internal list?
>
> You'd need to allocate a new resource when sending notifications from
> that internal thread (Since the original resource could have been
> destroyed), but other than that it should be pretty straightforward
> unless I've misunderstood something.
>
> Regards,
> John Högberg
>
> On ons, 2017-11-08 at 17:32 +0800, Skype Xu wrote:
>> Hi,
>>
>> Suppose a nif module is multi-threaded, we keep a pointer to a
>> resource
>> in the
>> module's internal list, when the resource is no longer used by
>> erlang
>> process,
>> erlang vm calls the resource's destructor, and we remove the pointer
>> from
>> internal list in the destructor, that's fine.
>> However a problem arises when the internal list is also used by
>> another
>> thread
>> created in the nif module, when some external events were triggered,
>> the
>> thread
>> tries to use the resource pointer and sends it to a process in the
>> vm,
>> problem
>> is there's a race condition between destructor and the internal
>> thread,
>> in the destructor we try to remove it from the internal list, at the
>> time, the
>> resource's reference count is already zero, and before the destructor
>> is
>> called,
>> the internal thread sent the resource to a proecess, by calling
>> enif_make_resource() to increase the count to 1, but anyway after the
>> destructor returned, the vm will recycle the memory of the resource
>> despites
>> the reference count is 1 again, this leads to corrupted memory.
>>
>> We can not keep a resource by adding extra reference count in nif
>> module,
>> if we do, the resource's destructor will never be called even if not
>> any
>> erlang
>> process is using the resource, because the reference count will never
>> to
>> dropped to 0.
>>
>> It would be perfect if we can keep a weak reference in nif like the
>> one in
>> C++ does, one can use weak_ptr to get back a shared_ptr object if
>> the
>> object
>> is still using, otherwise a null pointer is returned.  if this is
>> implemented, we
>> can queue a notification to the internal thread and the thread will
>> remove
>> any data related to the resource.  enif_monitor_process() is not a
>> solution
>> because we want vm to recycle the resource when it is not used, not
>> after
>> a process crashed or exited.
>>
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: weak resource reference possible in nif ?

John Högberg
I just thought of a dirty hack that might work; serialize the resource
on creation with enif_term_to_binary and store *that* in your internal
list instead of the resource, then send the result of
enif_binary_to_term in each notification.

The resource won't be kept alive any longer than needed (As the binary
won't keep any references to it), and it won't crash if the resource
has been deallocated as enif_binary_to_term will recognize it as such
and return a stale resource.

It will only work on OTP 20 or later though.

http://erlang.org/doc/man/erl_nif.html#enif_make_resource

/John

On tor, 2017-11-09 at 11:06 +0800, Skype Xu wrote:

> We don't want to get a new resource term every time when we got a
> new 
> notification,
> we want to simply use erlang pattern matching without another
> function 
> to retrieve
> actual data in the resource and matching against the data,  if we do 
> this,  a programmer
> can keep the data around for later matching, and may forget to keep
> the 
> resource, then
> what's the reason to use erlang resource? we would give up.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: weak resource reference possible in nif ?

Skype Xu
Yes, I have tried OTP 20, it works, also the dirty hack is too expensive
to run.

On 2017年11月10日 18:27, John Högberg wrote:

> I just thought of a dirty hack that might work; serialize the resource
> on creation with enif_term_to_binary and store *that* in your internal
> list instead of the resource, then send the result of
> enif_binary_to_term in each notification.
>
> The resource won't be kept alive any longer than needed (As the binary
> won't keep any references to it), and it won't crash if the resource
> has been deallocated as enif_binary_to_term will recognize it as such
> and return a stale resource.
>
> It will only work on OTP 20 or later though.
>
> http://erlang.org/doc/man/erl_nif.html#enif_make_resource
>
> /John
>
> On tor, 2017-11-09 at 11:06 +0800, Skype Xu wrote:
>> We don't want to get a new resource term every time when we got a
>> new
>> notification,
>> we want to simply use erlang pattern matching without another
>> function
>> to retrieve
>> actual data in the resource and matching against the data,  if we do
>> this,  a programmer
>> can keep the data around for later matching, and may forget to keep
>> the
>> resource, then
>> what's the reason to use erlang resource? we would give up.
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions