Lua (LuaJit) and object lifetime in C

I am using LuaJit to extend a simple C application (using the Lua C API). The host application does manage memory for a lot of objects, which I wrote wrappers for Lua on.

Now, I would like to be able to remove objects from the lua function, i.e. implement the delete function. I would like to illustrate this problem with the following outline of the problem.

Basically my custom lua data structure looks something like this.

struct my_lua_container { size_t obj_db_index; }; 

where obj_db_index is the index for the database of local objects. With the Lua C API, I created the lua function query_object(...) , which extracts the lua metatable based on this user data and offers an API to manage the db object.

Now I plan to introduce the my_db_object:delete() method into the metatable API. :delete() can invalidate my_db_object by overwriting the variable with 0 or setting another member variable. However, the problem is that all references to the remote object must be invalid. Consider this lua code:

 local p = query_object("1") local q = query_object("1") p:delete() q:do_something() -- <=== q still contains a obj_db_index 

Now I am wondering how to resolve this potential conflict. Two main problems:

  • Invalid obj_db_index may be an invalid index. In fact, it probably already caught the code, so it's not very, but good

  • after deletion, the index can be reused, and this can lead to subtle errors when other links still use the old index.

What are the strategies to solve this problem?

My idea may be a little time consuming, but that would be fine if removed:

  • Is there some kind of Introspection that I can perform on user data objects? Like iterating over all user data objects of the same type, to invalidate my_db_index when the deletion starts
+4
source share
1 answer

Maybe a little late, but ... The solution is to put new objects in a weak table and never create objects that are already stored there.

 -- this should be really C, but for readability, we write it in Lua pseudocode registry.my_cache = setmetatable({ }, { __mode = "v" }) function push_object(db_id) local object = registry.my_cache[db_id] if object == nil then object = lua_newuserdata(db_id) registry.my_cache[db_id] = object end end assert(push_object(1) == push_object(1)) 

Now, only the unique db_id passes from the C side to the Lua side, the problem has almost disappeared.

But there is one more detail that needs to be taken care of. Garbage collection of user data consists of two stages: finalization and removal from weak tables. There are times when user data ends, but is still present in a weak table, so the above code can return the final user data to the user. An additional check must be performed, and if ud is completed, it must first be manually removed from the table.

 function push_object(db_id) local object = registry.my_cache[db_id] -- check vitality first if is_finalized(object) then registry.my_cache[db_id] = nil object = nil end if object == nil then object = lua_newuserdata(db_id) registry.my_cache[db_id] = object end end 

As you know if user information has been finalized, it depends on your implementation of the finalization method (metatable .__ gc).

+1
source

All Articles