lua-users home
lua-l archive

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


2008/10/10 Wesley Smith <wesley.hoke@gmail.com>:
> There was a thread not too long ago regarding the issue of the order
> in which __gc is called on userdata.  The manual states:
>
> "At the end of each garbage-collection cycle, the finalizers for
> userdata are called in reverse order of their creation, among those
> collected in that cycle. That is, the first finalizer to be called is
> the one associated with the userdata created last in the program. The
> userdata itself is freed only in the next garbage-collection cycle. "
>
> but I wonder if this condition is sufficient.  It was mentioned in the
> thread that Lua 5.2 might end up going off of the order in which
> metatables are attached to an object instead of being based on
> creation.  Here's an example:
>
>
> local udata1 = Udata()
> local udata2 = Udata()
>
> local filename = "path/to/file.lua"
> function udata1:closing()
>    udata2:serialize(filename)
> end
>
>
> Now let's say that the script is closed via lua_close(L) and that
> udata1's __gc metamethod calls udata1:closing().  In the current
> version of Lua, the variable udata2 will be invalid because it will be
> collected before udata1 despite udata2 being an upvalue in udata1's
> closing function.  Would it be possible to handle such a case with a
> few tweaks to Lua or is situation too tricky to bother dealing with?
> It seems somehow logically inconsistent that userdata as upvalues in
> functions wouldn't be collected as long as the function exists while a
> script is running, but suddenly when the script is closed the fact
> that it is an upvalue in a function has no bearing on the order of
> collection.  The basic reference diagram looks like:
>
>
> getfenv(udata1)[closing] -> a function with udata2 as an upvalue
>
> so wouldn't the GC be able to tell that udata2 is referenced (at root)
> with udata1 and be able to collect that first.

You may have cyclic references, especially since upvalues can be
updated (from nil to a userdata created afterwards). Using an
imperative order (order of creation of userdata or order of assignment
of metatables) prevent such cycle problems.

Such an order is simple enough to understand so you can take it into
account in your code to avoid the problem you have in your example.
Here you would have to create the serializer before any userdata that
may use it in their finalizer.