wplua: move under modules/module-lua-scripting
It's unlikely that wplua will ever be useful outside the context of module-lua-scripting, so let's move it to keep all the code in one place
This commit is contained in:
181
modules/module-lua-scripting/wplua/closure.c
Normal file
181
modules/module-lua-scripting/wplua/closure.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "wplua.h"
|
||||
#include "private.h"
|
||||
#include <wp/wp.h>
|
||||
|
||||
/* This structure is added to a lua global and it's only referenced from there;
|
||||
When the lua_State closes, it is unrefed and its finalize function below
|
||||
invalidates all the closures so that nothing attempts to call into a lua
|
||||
function after the state is closed */
|
||||
typedef struct _WpLuaClosureStore WpLuaClosureStore;
|
||||
struct _WpLuaClosureStore
|
||||
{
|
||||
GPtrArray *closures;
|
||||
};
|
||||
|
||||
static WpLuaClosureStore *
|
||||
_wplua_closure_store_new (void)
|
||||
{
|
||||
WpLuaClosureStore *self = g_rc_box_new (WpLuaClosureStore);
|
||||
self->closures = g_ptr_array_new ();
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
_wplua_closure_store_finalize (WpLuaClosureStore * self)
|
||||
{
|
||||
for (guint i = self->closures->len; i > 0; i--) {
|
||||
GClosure *c = g_ptr_array_index (self->closures, i-1);
|
||||
g_closure_ref (c);
|
||||
g_closure_invalidate (c);
|
||||
g_ptr_array_remove_index_fast (self->closures, i-1);
|
||||
g_closure_unref (c);
|
||||
}
|
||||
g_ptr_array_unref (self->closures);
|
||||
}
|
||||
|
||||
static WpLuaClosureStore *
|
||||
_wplua_closure_store_ref (WpLuaClosureStore * self)
|
||||
{
|
||||
return g_rc_box_acquire (self);
|
||||
}
|
||||
|
||||
static void
|
||||
_wplua_closure_store_unref (WpLuaClosureStore * self)
|
||||
{
|
||||
g_rc_box_release_full (self, (GDestroyNotify) _wplua_closure_store_finalize);
|
||||
}
|
||||
|
||||
G_DEFINE_BOXED_TYPE(WpLuaClosureStore, _wplua_closure_store,
|
||||
_wplua_closure_store_ref, _wplua_closure_store_unref)
|
||||
|
||||
|
||||
typedef struct _WpLuaClosure WpLuaClosure;
|
||||
struct _WpLuaClosure
|
||||
{
|
||||
GClosure closure;
|
||||
int func_ref;
|
||||
GPtrArray *closures;
|
||||
};
|
||||
|
||||
static void
|
||||
_wplua_closure_marshal (GClosure *closure, GValue *return_value,
|
||||
guint n_param_values, const GValue *param_values,
|
||||
gpointer invocation_hint, gpointer marshal_data)
|
||||
{
|
||||
static int reentrant = 0;
|
||||
lua_State *L = closure->data;
|
||||
int func_ref = ((WpLuaClosure *) closure)->func_ref;
|
||||
|
||||
/* invalid closure, skip it */
|
||||
if (func_ref == LUA_NOREF || func_ref == LUA_REFNIL)
|
||||
return;
|
||||
|
||||
/* stop the garbage collector */
|
||||
if (reentrant == 0)
|
||||
lua_gc (L, LUA_GCSTOP, 0);
|
||||
|
||||
/* push the function */
|
||||
lua_rawgeti (L, LUA_REGISTRYINDEX, func_ref);
|
||||
|
||||
/* push arguments */
|
||||
for (guint i = 0; i < n_param_values; i++)
|
||||
wplua_gvalue_to_lua (L, ¶m_values[i]);
|
||||
|
||||
/* call in protected mode */
|
||||
reentrant++;
|
||||
int res = _wplua_pcall (L, n_param_values, return_value ? 1 : 0);
|
||||
reentrant--;
|
||||
|
||||
/* handle the result */
|
||||
if (res == LUA_OK && return_value) {
|
||||
wplua_lua_to_gvalue (L, -1, return_value);
|
||||
lua_pop (L, 1);
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
lua_gc (L, LUA_GCCOLLECT, 0);
|
||||
if (reentrant == 0)
|
||||
lua_gc (L, LUA_GCRESTART, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
_wplua_closure_invalidate (lua_State *L, WpLuaClosure *c)
|
||||
{
|
||||
wp_trace_boxed (G_TYPE_CLOSURE, c, "invalidated");
|
||||
luaL_unref (L, LUA_REGISTRYINDEX, c->func_ref);
|
||||
c->func_ref = LUA_NOREF;
|
||||
}
|
||||
|
||||
static void
|
||||
_wplua_closure_finalize (lua_State *L, WpLuaClosure *c)
|
||||
{
|
||||
g_ptr_array_remove_fast (c->closures, c);
|
||||
g_ptr_array_unref (c->closures);
|
||||
}
|
||||
|
||||
GClosure *
|
||||
wplua_checkclosure (lua_State *L, int idx)
|
||||
{
|
||||
luaL_checktype (L, idx, LUA_TFUNCTION);
|
||||
return wplua_function_to_closure (L, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* wplua_function_to_closure:
|
||||
*
|
||||
* Make a GClosure out of a Lua function at index @em idx
|
||||
*
|
||||
* Returns: (transfer floating): the new closure
|
||||
*/
|
||||
GClosure *
|
||||
wplua_function_to_closure (lua_State *L, int idx)
|
||||
{
|
||||
g_return_val_if_fail (lua_isfunction(L, idx), NULL);
|
||||
|
||||
GClosure *c = g_closure_new_simple (sizeof (WpLuaClosure), L);
|
||||
WpLuaClosure *wlc = (WpLuaClosure *) c;
|
||||
WpLuaClosureStore *store;
|
||||
|
||||
lua_pushvalue (L, idx);
|
||||
wlc->func_ref = luaL_ref (L, LUA_REGISTRYINDEX);
|
||||
|
||||
wp_trace_boxed (G_TYPE_CLOSURE, c, "created, func_ref = %d", wlc->func_ref);
|
||||
|
||||
g_closure_set_marshal (c, _wplua_closure_marshal);
|
||||
g_closure_add_invalidate_notifier (c, L,
|
||||
(GClosureNotify) _wplua_closure_invalidate);
|
||||
g_closure_add_finalize_notifier (c, L,
|
||||
(GClosureNotify) _wplua_closure_finalize);
|
||||
|
||||
/* keep a weak ref of the closure in the store's array,
|
||||
so that we can invalidate the closure when lua_State closes;
|
||||
keep a strong ref of the array in the closure so that
|
||||
_wplua_closure_finalize() works even after the state is closed */
|
||||
lua_pushliteral (L, "wplua_closures");
|
||||
lua_gettable (L, LUA_REGISTRYINDEX);
|
||||
store = wplua_toboxed (L, -1);
|
||||
lua_pop (L, 1);
|
||||
|
||||
g_ptr_array_add (store->closures, c);
|
||||
wlc->closures = g_ptr_array_ref (store->closures);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
_wplua_init_closure (lua_State *L)
|
||||
{
|
||||
lua_pushliteral (L, "wplua_closures");
|
||||
wplua_pushboxed (L,
|
||||
_wplua_closure_store_get_type (),
|
||||
_wplua_closure_store_new ());
|
||||
lua_settable (L, LUA_REGISTRYINDEX);
|
||||
}
|
Reference in New Issue
Block a user