lua-users home
lua-l archive

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



On Jun 29, 2010, at 2:48 PM, Mailing-Listen wrote:

> On Mon, Jun 28, 2010 at 09:42:50AM -0700, Graham Wakefield wrote:
>> This might not be optimal code, but it works for me.
> 
> Thank you.
> It also works for me and it does what I wanted.
> But I must admit, I don't fully understand it.
> 
>> /*
>> 	get a callback when the value at stack index idx is collected
>> */
>> static void gc_sentinel(lua_State * L, int idx, lua_CFunction callback) {
>> 
>> 	lua_pushvalue(L, idx); // value @idx
>> 	lua_newuserdata(L, sizeof(void *)); // sentinel userdata
>> 		lua_newtable(L);	// userdata metatable with __gc = callback
>> 		lua_pushcfunction(L, callback);
>> 		lua_setfield(L, -2, "__gc");
>> 		lua_setmetatable(L, -2);
> 
> That is what was described in the previous mail.
> I understand it that far.
> 
> But what does the following code do?
> I've tried if it still works without it and it does.

The sentinel userdata above will call the cleanup code as soon as it is collected; to prevent collection until the module is destroyed, we need to add a reference that links the module to the sentinel. 
We're using the LUA_REGISTRYINDEX to store this in a way that is hidden from Lua scripts.  
We create a weak-valued table in the registry called "__gc_sentinels" (if it doesn't already exist), and use weak-referencing so that existence of the module in this table will not stop it from being collected. 
For most uses of Lua, this won't matter since modules usually only get unloaded when the lua_State is closed; but we had a situation where we needed to manually unload modules sometimes.	

> 
>> 	/* check for (weak-valued) sentinel table; create if needed */
>> 	lua_getfield(L, LUA_REGISTRYINDEX, "__gc_sentinels");
>> 	if (lua_isnoneornil(L, -1)) {
>> 		lua_pop(L, 1);
>> 		lua_newtable(L);
>> 		// make weak-keyed
>> 		lua_pushstring(L, "k");		
>> 		lua_setfield(L, -2, "__mode");
>> 		lua_pushvalue(L, -1);
>> 		lua_setfield(L, -2, "__index");
>> 		lua_pushvalue(L, -1);
>> 		lua_setmetatable(L, -2);
>> 		lua_pushvalue(L, -1);
>> 		lua_setfield(L, LUA_REGISTRYINDEX, "__gc_sentinels");
>> 	}
>> 
>> 	lua_insert(L, -3);
>> 	lua_insert(L, -2);
>> 	lua_settable(L, -3); // __gc_sentinels[object] = sentinel
>> 	lua_pop(L, 1); //  __gc_sentinels
>> }
> 
> May I use your code in a GPLv3+ licensed project?
> How would you like to be referred to in the Copyright notice?
> Full name with e-mail address?

The code in question is taken from the LuaAV project (http://lua-av.mat.ucsb.edu/about.html)
LuaAV is covered by the UC Regents license, which is similar in nature to the BSD or MIT license - so feel free!
See http://lua-av.mat.ucsb.edu/source.html