lua-users home
lua-l archive

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


Short version: 
I feel like this should be possible, but would like to know for sure. Is it possible to re-reference a userdata during the __gc handler, to prevent the memory being reclaimed immediately?

Long version:
I want Lua to manage the memory for my userdata, but I cannot free the memory immediately because I have to wait for a signal from another (OS) thread to let me know it isn't using it either. Normally I'd do this with boxed pointers, but I wondered if the following scheme would work. The reasons to avoid boxed pointers are 1) avoiding extra pointer indirection on frequently used objects and 2) letting Lua's GC know how much memory is really in use. 

int userdata_gc(lua_State * L) {
	void * ptr =  lua_touserdata(L, 1);
	// remove metatable first to prevent further use or __gc calls:
	lua_pushnil(L);
	lua_setmetatable(L, 1);
	// add a temporary reference back to userdatum to prevent Lua reclaiming the memory immediately:
	lua_pushlightuserdata(L, ptr);
	lua_pushvalue(L, 1);
	lua_settable(L, LUA_REGISTRYINDEX);
	// now send a message to secondary OS thread to say 'tell me when you've done with ptr':
	notify_dead(notify_dead_callback, L, ptr);
	return 0;
}

// callback triggered when secondary OS thread is done with ptr:
void notify_dead_callback(lua_State * L, void * ptr) {
	// remove temporary reference to userdatum to allow Lua to reclaim the memory now:
	lua_pushlightuserdata(L, ptr);
	lua_pushnil(L, 1);
	lua_settable(L, LUA_REGISTRYINDEX);
}

At least one possible pitfall is that the lua_State itself is no longer valid. I can avoid that if I ensure that L in the callback is the 'root' lua_State, and to cancel all pending callbacks when this lua_State is closed.