mirror of
https://github.com/mpv-player/mpv
synced 2024-11-14 22:48:35 +01:00
lua: use an autofree wrapper instead of mp_lua_PITA
Advantages of this approach: - All the resources are released right after the function ends regardless if it threw an error or not, without having to wait for GC. - Simpler code. - Simpler lua setup which most likely uses less memory allocation and as a result should be quicker, though it wasn't measured. This commit adds the autofree wrapper and uses it where mp_lua_PITA was used. It's not yet enforced at the C level, there are still redundant talloc_free_children leftovers, and there are few more places which could also use autofree. The next commits will address those.
This commit is contained in:
parent
6169fba796
commit
eb5635131d
89
player/lua.c
89
player/lua.c
@ -114,36 +114,7 @@ static void mp_lua_optarg(lua_State *L, int arg)
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
static int destroy_crap(lua_State *L)
|
||||
{
|
||||
void **data = luaL_checkudata(L, 1, "ohthispain");
|
||||
talloc_free(data[0]);
|
||||
data[0] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Creates a small userdata object and pushes it to the Lua stack. The function
|
||||
// will (on the C level) return a talloc object that will be released by the
|
||||
// userdata gc routine.
|
||||
// This can be used to free temporary C data structures correctly if Lua errors
|
||||
// happen.
|
||||
// You can't free the talloc context directly; the Lua __gc handler does this.
|
||||
// In many cases, talloc_free_children(returnval) will be used to free attached
|
||||
// memory in advance when it's known not to be needed anymore (a minor
|
||||
// optimization). Freeing it completely must be left to the Lua GC.
|
||||
static void *mp_lua_PITA(lua_State *L)
|
||||
{
|
||||
void **data = lua_newuserdata(L, sizeof(void *)); // u
|
||||
if (luaL_newmetatable(L, "ohthispain")) { // u metatable
|
||||
lua_pushvalue(L, -1); // u metatable metatable
|
||||
lua_setfield(L, -2, "__index"); // u metatable
|
||||
lua_pushcfunction(L, destroy_crap); // u metatable gc
|
||||
lua_setfield(L, -2, "__gc"); // u metatable
|
||||
}
|
||||
lua_setmetatable(L, -2); // u
|
||||
*data = talloc_new(NULL);
|
||||
return *data;
|
||||
}
|
||||
static void *mp_lua_PITA(lua_State *L);
|
||||
|
||||
// Perform the equivalent of mpv_free_node_contents(node) when tmp is freed.
|
||||
static void auto_free_node(void *tmp, mpv_node *node)
|
||||
@ -1148,10 +1119,12 @@ static int script_format_json(lua_State *L)
|
||||
return 2;
|
||||
}
|
||||
|
||||
#define FN_ENTRY(name) {#name, script_ ## name}
|
||||
#define FN_ENTRY(name) {#name, script_ ## name, 0}
|
||||
#define AF_ENTRY(name) {#name, script_ ## name, 1}
|
||||
struct fn_entry {
|
||||
const char *name;
|
||||
int (*fn)(lua_State *L);
|
||||
int autofree;
|
||||
};
|
||||
|
||||
static const struct fn_entry main_fns[] = {
|
||||
@ -1165,16 +1138,16 @@ static const struct fn_entry main_fns[] = {
|
||||
FN_ENTRY(get_script_directory),
|
||||
FN_ENTRY(command),
|
||||
FN_ENTRY(commandv),
|
||||
FN_ENTRY(command_native),
|
||||
FN_ENTRY(raw_command_native_async),
|
||||
AF_ENTRY(command_native),
|
||||
AF_ENTRY(raw_command_native_async),
|
||||
FN_ENTRY(raw_abort_async_command),
|
||||
FN_ENTRY(get_property_bool),
|
||||
FN_ENTRY(get_property_number),
|
||||
FN_ENTRY(get_property_native),
|
||||
AF_ENTRY(get_property_native),
|
||||
FN_ENTRY(set_property),
|
||||
FN_ENTRY(set_property_bool),
|
||||
FN_ENTRY(set_property_number),
|
||||
FN_ENTRY(set_property_native),
|
||||
AF_ENTRY(set_property_native),
|
||||
FN_ENTRY(raw_observe_property),
|
||||
FN_ENTRY(raw_unobserve_property),
|
||||
FN_ENTRY(get_mouse_pos),
|
||||
@ -1194,17 +1167,57 @@ static const struct fn_entry utils_fns[] = {
|
||||
FN_ENTRY(split_path),
|
||||
FN_ENTRY(join_path),
|
||||
FN_ENTRY(getpid),
|
||||
FN_ENTRY(parse_json),
|
||||
FN_ENTRY(format_json),
|
||||
AF_ENTRY(parse_json),
|
||||
AF_ENTRY(format_json),
|
||||
{0}
|
||||
};
|
||||
|
||||
/* returns the talloc ctx which script_autofree_trampoline sets */
|
||||
static void *mp_lua_PITA(lua_State *L)
|
||||
{
|
||||
void **ctx = lua_touserdata(L, lua_upvalueindex(1));
|
||||
assert(ctx && *ctx);
|
||||
return *ctx;
|
||||
}
|
||||
|
||||
static int script_autofree_trampoline(lua_State *L)
|
||||
{
|
||||
lua_CFunction target = lua_touserdata(L, lua_upvalueindex(1));
|
||||
assert(target);
|
||||
|
||||
int nargs = lua_gettop(L);
|
||||
void *ctx = NULL;
|
||||
|
||||
lua_pushlightuserdata(L, &ctx);
|
||||
lua_pushcclosure(L, target, 1);
|
||||
lua_insert(L, 1);
|
||||
|
||||
ctx = talloc_new(NULL);
|
||||
int r = lua_pcall(L, nargs, LUA_MULTRET, 0);
|
||||
talloc_free(ctx);
|
||||
|
||||
if (r)
|
||||
lua_error(L);
|
||||
|
||||
return lua_gettop(L);
|
||||
}
|
||||
|
||||
static void mp_push_autofree_fn(lua_State *L, lua_CFunction fn)
|
||||
{
|
||||
lua_pushlightuserdata(L, fn);
|
||||
lua_pushcclosure(L, script_autofree_trampoline, 1);
|
||||
}
|
||||
|
||||
static void register_package_fns(lua_State *L, char *module,
|
||||
const struct fn_entry *e)
|
||||
{
|
||||
push_module_table(L, module); // modtable
|
||||
for (int n = 0; e[n].name; n++) {
|
||||
lua_pushcclosure(L, e[n].fn, 0); // modtable fn
|
||||
if (e[n].autofree) {
|
||||
mp_push_autofree_fn(L, e[n].fn); // modtable fn
|
||||
} else {
|
||||
lua_pushcclosure(L, e[n].fn, 0); // modtable fn
|
||||
}
|
||||
lua_setfield(L, -2, e[n].name); // modtable
|
||||
}
|
||||
lua_pop(L, 1); // -
|
||||
|
Loading…
Reference in New Issue
Block a user