lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

I thought long and hard about this problem when writing luv.  It's a hard requirement that the userdata must be referenced in lua somewhere as long as there is any change the callback will be called and require the uv handle.  There are two possible solutions to this.

The first is what I do in Luv currently.  I ref the userdata upon handle creation and unref it during the close callback.  This means that the user has to remember to call close on the handle or it will leak uv and lua resources.  But as long as they remember to call close, the lua side will be able to be garbage collected.  This method is simple and not prone to errors, or segfaults.  It's trivial for unit tests to check the list of handles in a loop before and after a piece of code and fail the unit test if there are any unclosed handles.  This find any library calls that forget to cleanup after themselves.

The other idea is much more complicated.  There are times when a handle has no references in any lua code and will never emit any callbacks either.  In this case, it would be nice to trigger the GC somehow and then call uv_close for the user.  The problem is this is complex and different for each type.  I went down this path but gave up because it was too much complex code.  The basic idea is to only ref the userdata when there is at least one possible callback pending and to unref it as soon as you know no callbacks can happen.  For timers, for example, `uv_timer_start` would require a ref, you can't then unref it till the user calls `uv_timer_stop`.  But then what about timers with an interval of 0 after the first timeout?  What about uv_timer_again?  It gets very complex very quick and in many cases you can't unref before the close callback anyway.

If you go the second route, you still have the problem of how to hold the reference between the time of `uv_close` and it's callback.  Lua will free the memory right after your close returns if using full userdata.  Then in your close callback you will have to be very careful because the handle will probably be an invalid pointer.  Some code internal to libuv might assume the handle is good any time before calling uv_close and segfault on it's own.

For these reasons, I went with the first path and simply require the user to call close on all handles.

On Mon, Dec 29, 2014 at 11:42 PM, <> wrote:
> I work on Luvit and Luv and we store the ref then in the callback
> call the unref.
I also do that in my binding, but it prevents collect handles by Lua GC. I need to Lua calls gc method but until that I want be able find out Lua object by C handle.
The problem is that remove value from weak table and call finalizer is not atomic and there may be time when value removes from table and finalizer is not called yet.

Here my testcase
uv.timer() -- put timer to weak table(handle=>Lua object)
assert(#uv.handles() == 1) -- use uv_walk to enumerate all handles
The problem is Lua GC remove timer from table but did not call __gc method and uv_walk's callback can not find Lua object.

Это сообщение проверено на вирусы антивирусом Avast.