lua-users home
lua-l archive

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


Am 22.05.2014 01:02 schröbte Tim Hill:

On May 21, 2014, at 3:07 PM, Philipp Janda <siffiejoe@gmx.net> wrote:

It's not just two objects where one depends on the other, but N objects which depend on one other. E.g. in APR you have memory pools that do all the allocation/deallocation of APR objects (files, directories, processes, strings, sockets, etc.), and destroying the pool will destroy all APR objects created with it. The same is true for textures (chunks of memory in video RAM) and renderers in SDL: The renderer destroys all textures that belong to it when it is destroyed, so you must not finalize the renderer before its textures or you will double-free the textures (or crash trying).
I also use the finalizer ordering to make sure that `APR_terminate`/`SDL_Quit` is called after all objects from those libraries are destroyed by putting a userdata with a suitable `__gc` in the registry before I initialize the library.
Lua itself uses a similar mechanism to ensure that shared libraries are unloaded after all userdata objects using symbols from those libraries are finalized.


Completely agree that this is a messy problem. It’s just if it was me
I’d be very wary of relying on finalizer ordering to solve it, unless
the official Lua docs had very strong guarantees about that (and even
then I’d still avoid it as much as I possibly could).

They have. And of course I only use those guarantees if they simplify the lifetime management of my C objects.


As others have said, pretty much the only way you can tackle this is
using weak tables and/or having idempotent finalizers that may be
called by the GC or by other parts of the system as necessary.

I don't think that anyone has mentioned this yet, but I guess you mean something like this:
*   put B in A's uservalue table to keep it alive as long as A is alive
*   put a weak back reference to A in B's uservalue table
*   in A's finalizer free A if it hasn't been freed before by someone else
* in B's finalizer first free A if the weak back reference still exists and A hasn't been freed before, and then free B itself if it hasn't been freed before

But this (if it actually works) relies on undocumented order of clearing objects from weak tables in relation to calling finalizers of other objects in the same gc cycle. (In Lua 5.2 you can use weak values which have the necessary guarantees, and in Lua 5.1 you can probably use strong back references with some degradation of lifetime granularity.) And of course my `SDL_Quit` finalizer would store references to all SDL objects ever created, but this approach could still be an option for the OP ...

Are there other approaches using weak tables and idempotent finalizers that I've missed?


—Tim


Philipp