summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Halachmi (:avih) <avihpit@yahoo.com>2020-03-22 19:53:19 +0200
committeravih <avih@users.noreply.github.com>2020-03-22 23:34:19 +0200
commiteb5635131d3c16f9a670063c10f208ecdece6b7e (patch)
treea69ace42a0c8e72a68b009e5a53202ed0ad005dc
parent6169fba79679aff0c4b07fbae03ed30e9f6f7eb6 (diff)
downloadmpv-eb5635131d3c16f9a670063c10f208ecdece6b7e.tar.bz2
mpv-eb5635131d3c16f9a670063c10f208ecdece6b7e.tar.xz
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.
-rw-r--r--player/lua.c89
1 files changed, 51 insertions, 38 deletions
diff --git a/player/lua.c b/player/lua.c
index fca6791d48..f1204926eb 100644
--- a/player/lua.c
+++ b/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); // -