lua-users home
lua-l archive

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

Dear list,

when a call to lua_close() triggers calls to the the __gc handlers/callbacks, in what condition is the Lua state (given as the lua_State* parameter to the __gc handler) at that time?

That is, will a global variable that held the userdata for which the __gc handler is currently being called still be accessible "normally" as in any other C callback?

More importantly, if there is *another* userdata instance as a value in the globals table or in the registry, and I overwrite it by assigning nil to the same index, is that a valid operation to do in the __gc handler?

I'm asking this because I'm binding C++ objects to Lua using tables, where the tables contain the userdata at a special index. Because I sometimes need to keep instances of such objects in pure C++ code (Example: w=newWindow(); gui:SetRootWindow(w); w=nil; ) I have to prevent Lua from garbage collecting them early. Thus, I "anchor" such objects (w in the example) by putting them into the registry, employing a reference-counting scheme on the C++ side: When the first reference is created, the anchor in the registry is established, when the last reference is gone (count drops to zero), the anchor in the registry is overwritten with nil. The "problem" is that my windows can have child windows (Example: w:AddChild(newWindow()); ), which means that they too establish reference-counted anchors in the C++ instance. Thus, when a window is destroyed, also its references to its parent and children are destroyed. If one of these references was the last reference to a child window, it would try to un-anchor the child window in the registry again by overwriting it with nil.

I got all of this working, and I don't think that there is a problem when that happens in a normal run of the garbage collector. (In fact, my current implementation as described above suffers from the problem that a hierarchy of windows is never garbage collected, because there is always the anchor in the registry. I'll fix this soon, and it is not related to my question.)

However, when the forced shutdown by a call to lua_close() occurs, this sequence of events can occur:
a) The __gc handler is called for a window,
b) which deletes it's C++ instance.
c) The destructor of the C++ instance removes all references to the parent and children.
d) If a reference count drops to zero during step "c)", because e.g. nobody else refers to a child, the reference will attempt to un-anchor the child from the registry, by overwriting it with nil.

I've never experienced crashes or memory corruption with this, but I still wonder if this is a valid action?

Many thanks and best regards,

Multi-Player, Multi-Platform, Real-Time 3D Action