mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-09 02:48:05 +02:00
Merge branch 'prepare-shutdown-lua-gc-race' into 'master'
lib: core: add prepare_shutdown vfunc to fix Lua GC crash on exit See merge request pipewire/wireplumber!832
This commit is contained in:
commit
bed6148e4d
6 changed files with 105 additions and 6 deletions
|
|
@ -397,7 +397,21 @@ static void
|
|||
wp_core_dispose (GObject * obj)
|
||||
{
|
||||
WpCore *self = WP_CORE (obj);
|
||||
GPtrArray *objects = self->registry.objects;
|
||||
guint i;
|
||||
|
||||
/* Notify all plugins to prepare for shutdown before the registry is cleared.
|
||||
* This allows the Lua scripting plugin to close its lua_State while all
|
||||
* GObjects are still alive, preventing use-after-free in finalizers. */
|
||||
if (objects) {
|
||||
for (i = 0; i < objects->len; i++) {
|
||||
gpointer item = objects->pdata[i];
|
||||
if (WP_IS_PLUGIN (item))
|
||||
wp_plugin_prepare_shutdown (WP_PLUGIN (item));
|
||||
}
|
||||
}
|
||||
|
||||
/* Now it is safe to clear the registry */
|
||||
wp_registry_clear (&self->registry);
|
||||
wp_object_update_features (WP_OBJECT (self), 0, WP_CORE_FEATURE_COMPONENTS);
|
||||
|
||||
|
|
|
|||
|
|
@ -213,6 +213,21 @@ wp_plugin_get_name (WpPlugin * self)
|
|||
return g_quark_to_string (priv->name_quark);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called during core shutdown before registry is cleared.
|
||||
*
|
||||
* \ingroup wpplugin
|
||||
* \param self the plugin
|
||||
* \returns void
|
||||
*/
|
||||
void
|
||||
wp_plugin_prepare_shutdown (WpPlugin * self)
|
||||
{
|
||||
g_return_if_fail (WP_IS_PLUGIN (self));
|
||||
if (WP_PLUGIN_GET_CLASS (self)->prepare_shutdown)
|
||||
WP_PLUGIN_GET_CLASS (self)->prepare_shutdown (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* \var _WpPluginClass::enable
|
||||
*
|
||||
|
|
|
|||
|
|
@ -36,9 +36,12 @@ struct _WpPluginClass
|
|||
|
||||
void (*enable) (WpPlugin * self, WpTransition * transition);
|
||||
void (*disable) (WpPlugin * self);
|
||||
/* New virtual method: called during core shutdown before registry is cleared.
|
||||
Uses one of the padding slots to preserve ABI. */
|
||||
void (*prepare_shutdown) (WpPlugin * self);
|
||||
|
||||
/*< private >*/
|
||||
WP_PADDING(6)
|
||||
WP_PADDING(5)
|
||||
};
|
||||
|
||||
WP_API
|
||||
|
|
@ -47,6 +50,9 @@ WpPlugin * wp_plugin_find (WpCore * core, const gchar * plugin_name);
|
|||
WP_API
|
||||
const gchar * wp_plugin_get_name (WpPlugin * self);
|
||||
|
||||
WP_API
|
||||
void wp_plugin_prepare_shutdown (WpPlugin * self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ struct _WpLuaScriptingPlugin
|
|||
{
|
||||
WpPlugin parent;
|
||||
lua_State *L;
|
||||
GPtrArray *scripts; /* List of all loaded WpLuaScript objects */
|
||||
gboolean is_shutting_down; /* Flag to avoid double cleanup */
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
@ -90,6 +92,8 @@ G_DEFINE_TYPE_WITH_CODE (WpLuaScriptingPlugin, wp_lua_scripting_plugin,
|
|||
static void
|
||||
wp_lua_scripting_plugin_init (WpLuaScriptingPlugin * self)
|
||||
{
|
||||
self->scripts = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
self->is_shutting_down = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -112,12 +116,49 @@ wp_lua_scripting_plugin_enable (WpPlugin * plugin, WpTransition * transition)
|
|||
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_lua_scripting_plugin_prepare_shutdown (WpPlugin *plugin)
|
||||
{
|
||||
WpLuaScriptingPlugin *self = WP_LUA_SCRIPTING_PLUGIN (plugin);
|
||||
guint i;
|
||||
|
||||
/* Avoid double execution */
|
||||
if (self->is_shutting_down)
|
||||
return;
|
||||
self->is_shutting_down = TRUE;
|
||||
|
||||
/* 1. Close the lua_State early. This will run all pending __gc finalizers
|
||||
* while all GObjects are still alive. */
|
||||
if (self->L)
|
||||
g_clear_pointer (&self->L, wplua_unref);
|
||||
|
||||
/* 2. Clear the lua_State pointer from every WpLuaScript that this plugin
|
||||
* has loaded. This prevents them from trying to close the same state
|
||||
* again in their finalize handlers during registry cleanup. */
|
||||
for (i = 0; i < self->scripts->len; i++) {
|
||||
WpLuaScript *script = g_ptr_array_index (self->scripts, i);
|
||||
if (WP_IS_LUA_SCRIPT (script))
|
||||
wp_lua_script_clear_lua_state (script);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wp_lua_scripting_plugin_disable (WpPlugin * plugin)
|
||||
{
|
||||
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
|
||||
if (self->is_shutting_down)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->L, wplua_unref);
|
||||
if (self->L)
|
||||
g_clear_pointer (&self->L, wplua_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
wp_lua_scripting_plugin_finalize (GObject *object)
|
||||
{
|
||||
WpLuaScriptingPlugin *self = WP_LUA_SCRIPTING_PLUGIN (object);
|
||||
g_clear_pointer (&self->scripts, g_ptr_array_unref);
|
||||
G_OBJECT_CLASS (wp_lua_scripting_plugin_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -187,6 +228,7 @@ wp_lua_scripting_plugin_load (WpComponentLoader * cl, WpCore * core,
|
|||
"arguments", args,
|
||||
NULL);
|
||||
|
||||
g_ptr_array_add (self->scripts, g_object_ref (script));
|
||||
g_task_return_pointer (task, g_steal_pointer (&script), g_object_unref);
|
||||
}
|
||||
|
||||
|
|
@ -204,9 +246,12 @@ static void
|
|||
wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass)
|
||||
{
|
||||
WpPluginClass *plugin_class = (WpPluginClass *) klass;
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
plugin_class->enable = wp_lua_scripting_plugin_enable;
|
||||
plugin_class->disable = wp_lua_scripting_plugin_disable;
|
||||
plugin_class->prepare_shutdown = wp_lua_scripting_plugin_prepare_shutdown;
|
||||
object_class->finalize = wp_lua_scripting_plugin_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -61,11 +61,15 @@ wp_lua_script_finalize (GObject * object)
|
|||
{
|
||||
WpLuaScript *self = WP_LUA_SCRIPT (object);
|
||||
|
||||
wp_lua_script_cleanup (self);
|
||||
g_clear_pointer (&self->L, wplua_unref);
|
||||
g_clear_pointer (&self->filename, g_free);
|
||||
g_clear_pointer (&self->args, wp_spa_json_unref);
|
||||
/* If the lua_State has already been cleared by the plugin's prepare_shutdown,
|
||||
* skip closing it again, but still free other resources. */
|
||||
if (self->L != NULL) {
|
||||
wp_lua_script_cleanup (self);
|
||||
g_clear_pointer (&self->L, wplua_unref);
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->filename, g_free);
|
||||
g_clear_pointer (&self->args, wp_spa_json_unref); /* if args exists */
|
||||
G_OBJECT_CLASS (wp_lua_script_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
|
@ -286,3 +290,12 @@ wp_lua_script_class_init (WpLuaScriptClass * klass)
|
|||
WP_TYPE_SPA_JSON,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
void
|
||||
wp_lua_script_clear_lua_state (WpLuaScript *self)
|
||||
{
|
||||
g_return_if_fail (WP_IS_LUA_SCRIPT (self));
|
||||
/* Only clear the pointer; the lua_State is owned and destroyed by the
|
||||
* WpLuaScriptingPlugin. Setting it to NULL prevents double closing. */
|
||||
self->L = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ G_BEGIN_DECLS
|
|||
#define WP_TYPE_LUA_SCRIPT (wp_lua_script_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (WpLuaScript, wp_lua_script, WP, LUA_SCRIPT, WpPlugin)
|
||||
|
||||
/* Clear the internal lua_State pointer to prevent the finalizer from
|
||||
* attempting to close the already-destroyed state. Called by the Lua
|
||||
* scripting plugin during prepare_shutdown. */
|
||||
WP_API
|
||||
void wp_lua_script_clear_lua_state (WpLuaScript *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue