lua-users home
lua-l archive

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


Maybe I just don't get it ;-)

I have a couple of CFunctions (actually C++ ;-) which create
userdata objects and return them to LUA.  some of these objects
are "containers" and some of these objects are "containees"

    con = makeContainer( )
    obj = makeObject( )

The 'obj' userdata has a tagmethod (in C++) which overrides "settable" so that
I can do this:

    obj["container"] = con

To add the object to the container. (yes, I know, I should make the container
be a table or at least look/act like a table or something, but there are 
good API reasons why I'm doing it this way ;-)

The "settable" tag method for the containee-object does this (pseudo code):

    obj = lua_touserdata(L,1);		// get ptr to object.
    index = lua_tostring(L,2);
    if (index == "container") {		// trying to change container?
	int oldCont = obj->container;	// get old container, a lua ref
	if (oldCont != LUA_NOREF) {
	    lua_unref(L,oldCont);	// release ref to container
	}
	lua_pushvalue(L,3);		// copy of 'container'
	obj->container = lua_ref(L,1);	// pop locked reference

	// now notify containers (old and new)
	if (oldCont != LUA_NOREF) {
	    lua_getref(L,oldCont);	// push ref of old container
					// and get object.
	    Container *cont = (Container*)lua_touserdata(L,-1);
	    lua_pop(L,1);		// remove container
	    cont->remObject(obj);	// tell container that 'obj' is gone
	}

	if (obj->container != LUA_NOREF) {
	    lua_getref(L,obj->container);// push ref of 'new' container
					 // and get object.
	    Container *cont = (Container*)lua_touserdata(L,-1);
	    lua_pop(L,1);		// remove container
	    cont->addObject(obj);	// tell container about 'obj'
	}

The code for addObject() looks something like this:

    Container::addObject(Object *o)
    {
	lua_pushusertag(L,o,o->getTag());	// put object on stack
	int ref = lua_ref(L,1);			// lock reference.

	// .. store 'obj' and 'ref' in associative array
	// listing contained objects
	objects[ref] = obj;
    }

Likewise, remObject() looks something like this:

    Container::remObject(Object *o)
    {
	lua_pushusertag(L,o,o->getTag());	// put object on stack
	int ref = lua_ref(L,0);			// get reference, unlocked
	// .. remove 'obj' from associative array
	// by removing element 'i'.
	objects[ref] = nil;
	lua_unref(L,ref);
    }

Now, if I execute the following Lua code:

    con = makeContainer( ... )
    obj = makeObject( ... )
    obj["container"] = con
    obj = makeObject( ... )
    obj["container"] = con
    collectgarbage()

What I should end up with is "obj->container" having a locked ref to the
container object and the container knowing that 'obj' is contained within
it and having a lock'ed reference back to the 'obj'.

Howver, in the code listed above, the first object gets garbage collected!  

I'm at a loss.  I'm using 4.1a ... 
Since lua_pushusertag() went away in 4.1a (why?).  I have redefined 
lua_pushusertag thusly:

    #define lua_pushusertag(L,o,tag) \
	{ lua_newuserdatabox(L,o); lua_settag(L,tag); }

Any help would be greatly appreciated.
--
Mike Cuddy (mcuddy@FensEnde.com, MC312), Programmer, Daddy, Human.
Fen's Ende Software, Redwood City, CA, USA, Earth, Sol System, Milky Way.

       Now I lay me down to sleep / CVS, I pray, my code to keep.  
       If disks crash before I wake: / format, newfs, cvs up, make.

       Join CAUCE: The Coalition Against Unsolicited Commercial E-mail.
                          <http://www.cauce.org/>