component-loader: make wp_core_load_component() API asynchronous
This change completely refactors the way components are loaded in wireplumber: - The module_init() function must return a GObject now. This object is either a WpPlugin or a WpSiFactory in the current modules. - When the component loader initializes a module, it automatically registers the WpPlugin or WpSiFactory with their respective methods. There is no need to register the WpPlugin or WpSiFactory in the module now. - The wp_core_load_component() API has been refactored to be asynchronows. This allows the component loader to automatically activate WpPlugin objects, and therefore allows the application to directly get the WpPlugin without having to find it. This simplifies a lot of things. - The 'ifexists' and 'nofail' component flags now work even if the respective WpPlugin could not be activated. - The code that loads components in main.c has also been simplified a lot, and the option to load dangling components has also been removed.
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#define WP_MODULE_INIT_SYMBOL "wireplumber__module_init"
|
||||
typedef gboolean (*WpModuleInitFunc) (WpCore *, GVariant *, GError **);
|
||||
typedef GObject *(*WpModuleInitFunc) (WpCore *, GVariant *, GError **);
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (WpComponentLoader, wp_component_loader, WP_TYPE_PLUGIN)
|
||||
|
||||
@@ -46,7 +46,7 @@ wp_component_loader_class_init (WpComponentLoaderClass * klass)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static GObject *
|
||||
load_module (WpCore * core, const gchar * module_name,
|
||||
GVariant * args, GError ** error)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ load_module (WpCore * core, const gchar * module_name,
|
||||
if (!gmodule) {
|
||||
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
||||
"Failed to open module %s: %s", module_path, g_module_error ());
|
||||
return FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (gmodule, WP_MODULE_INIT_SYMBOL, &module_init)) {
|
||||
@@ -72,7 +72,7 @@ load_module (WpCore * core, const gchar * module_name,
|
||||
"Failed to locate symbol " WP_MODULE_INIT_SYMBOL " in %s",
|
||||
module_path);
|
||||
g_module_close (gmodule);
|
||||
return FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ((WpModuleInitFunc) module_init) (core, args, error);
|
||||
@@ -98,13 +98,28 @@ wp_component_loader_find (WpCore * core, const gchar * type)
|
||||
return c ? WP_COMPONENT_LOADER (c) : NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
wp_component_loader_load (WpComponentLoader * self, const gchar * component,
|
||||
const gchar * type, GVariant * args, GError ** error)
|
||||
const gchar * type, GVariant * args, GAsyncReadyCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
g_return_val_if_fail (WP_IS_COMPONENT_LOADER (self), FALSE);
|
||||
return WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type,
|
||||
args, error);
|
||||
g_return_if_fail (WP_IS_COMPONENT_LOADER (self));
|
||||
WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type,
|
||||
args, callback, data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_object_loaded (WpObject *object, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
g_autoptr (GTask) task = G_TASK (data);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (!wp_object_activate_finish (object, res, &error)) {
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_pointer (task, g_object_ref (object), g_object_unref);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -121,25 +136,80 @@ wp_component_loader_load (WpComponentLoader * self, const gchar * component,
|
||||
* \param type the type of the component
|
||||
* \param args (transfer floating)(nullable): additional arguments for the component,
|
||||
* usually a dict or a string
|
||||
* \param error (out) (optional): return location for errors, or NULL to ignore
|
||||
* \returns TRUE if loaded, FALSE if there was an error
|
||||
* \param callback (scope async): the callback to call when the operation is done
|
||||
* \param data (closure): data to pass to \a callback
|
||||
*/
|
||||
gboolean
|
||||
void
|
||||
wp_core_load_component (WpCore * self, const gchar * component,
|
||||
const gchar * type, GVariant * args, GError ** error)
|
||||
const gchar * type, GVariant * args, GAsyncReadyCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
g_autoptr (GVariant) args_ref = args ? g_variant_ref_sink (args) : NULL;
|
||||
g_autoptr (GTask) task = NULL;
|
||||
g_autoptr (WpComponentLoader) c = NULL;
|
||||
|
||||
if (!g_strcmp0 (type, "module"))
|
||||
return load_module (self, component, args_ref, error);
|
||||
else {
|
||||
g_autoptr (WpComponentLoader) c = wp_component_loader_find (self, type);
|
||||
if (c)
|
||||
return wp_component_loader_load (c, component, type, args, error);
|
||||
else {
|
||||
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
|
||||
"No component loader was found for components of type '%s'", type);
|
||||
return FALSE;
|
||||
/* Special case for "module" component type */
|
||||
if (g_str_equal (type, "module")) {
|
||||
task = g_task_new (self, NULL, callback, data);
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autoptr (GObject) o = NULL;
|
||||
|
||||
/* load Module */
|
||||
o = load_module (self, component, args_ref, &error);
|
||||
if (!o) {
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
if (WP_IS_OBJECT (o)) {
|
||||
/* WpObject needs to be activated */
|
||||
if (WP_IS_PLUGIN (o))
|
||||
wp_plugin_register (WP_PLUGIN (g_object_ref (o)));
|
||||
wp_object_activate (WP_OBJECT (o), WP_OBJECT_FEATURES_ALL, NULL,
|
||||
(GAsyncReadyCallback) on_object_loaded, g_object_ref (task));
|
||||
return;
|
||||
} else if (WP_IS_SI_FACTORY (o)) {
|
||||
/* WpSiFactory doesn't need to be activated */
|
||||
wp_si_factory_register (self, WP_SI_FACTORY (g_object_ref (o)));
|
||||
g_task_return_pointer (task, g_object_ref (o), g_object_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_new_error (task, WP_DOMAIN_LIBRARY,
|
||||
WP_LIBRARY_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid module object for component %s", component);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise find a component loader for that type and load the component */
|
||||
c = wp_component_loader_find (self, type);
|
||||
if (!c) {
|
||||
task = g_task_new (self, NULL, callback, data);
|
||||
g_task_return_new_error (task, WP_DOMAIN_LIBRARY,
|
||||
WP_LIBRARY_ERROR_INVALID_ARGUMENT,
|
||||
"No component loader was found for components of type '%s'", type);
|
||||
return;
|
||||
}
|
||||
|
||||
wp_component_loader_load (c, component, type, args, callback, data);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Finishes the operation started by wp_core_load_component().
|
||||
* This is meant to be called in the callback that was passed to that method.
|
||||
*
|
||||
*
|
||||
* \ingroup wpcomponentloader
|
||||
* \param self the component loader object
|
||||
* \param res the async result
|
||||
* \param error (out) (optional): the operation's error, if it occurred
|
||||
* \returns (transfer full): The loaded component object, or NULL if an
|
||||
* error happened.
|
||||
*/
|
||||
GObject *
|
||||
wp_core_load_component_finish (WpCore * self, GAsyncResult * res,
|
||||
GError ** error)
|
||||
{
|
||||
gpointer o = g_task_propagate_pointer (G_TASK (res), error);
|
||||
return o ? g_object_ref (G_OBJECT (o)) : NULL;
|
||||
}
|
||||
|
Reference in New Issue
Block a user