lua-users home
lua-l archive

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


Hi,

I've a got a problem right now, and I wonder how I can fix it.
Let me expose you.

I've a type of object that we will call `ninja' (because ninjas
are cool).
Each `ninja' has a weapon: a callback function!

So basically I get a struct defined as:
typedef struct ninja_t {
    int weapon;
} ninja_t;

So far so good. Now, when I give a weapon (function) to a ninja, I do:
myninja->weapon = luaL_ref(L, LUA_REGISTRYINDEX);
That set myninja->weapon to a reference number in the registry.

Now, as you know, ninja get killed often, so I store them in a
weak-keyed table:
battles = setmetatable({}, { __mode 'k' })

In the `battles' table, I will store a `mutant' as the key, and a ninja
has the value (we all know that ninja fight mutants).

battles[mymutant] = myninja

So far, so good: as soon as `mymutant' get killed, since it's a
weak-keyed table, myninja will get unref'ed.

BUT.

Now imagine I add a weapon to myninja and then store it:

myninja.weapon = function () kick_ass_of(mymutant) end
battles[mymutant] = myninja

Now, I've something which is like an "island" and will be never garbage
collected. Why? As I understand, that's because myninja.weapon reference
`mymutant'. But, since it's a function stored in the Lua registry, Lua
has no clue that this function is used and store for `myninja'. So it
basically thinks that mymutant has a valid reference.

Schematic:

  From my programmer's point of view:

battles[mymutant] --ref--> myninja --ref--> weapon
   ^----------------ref------------------------'

 Cyclic ref, but Lua is smart so can collect.


  From real Lua point of view

REGISTRY                            battles[mymutant]
  \                                       /
   \                                     /
    \ ref                          ref  /
     \                                 /
      `-> mymutant                 myninja

 Uncollectable: mymutant is refed by the callback function (weapon)
 of the ninja in a table (registry), so no reason to kill
 battles[mymutant].

I clearly need to tell Lua: "hey buddy, I'm storing things in the
registry for `myninja', so don't think it's totally unrelated".
I am not sure I can do that.

What's the solution guys?

Cheers,
-- 
Julien Danjou
// ᐰ <julien@danjou.info>   http://julien.danjou.info
// 9A0D 5FD9 EB42 22F6 8974  C95C A462 B51E C2FE E5CD
// Don't give up.

Attachment: signature.asc
Description: Digital signature