From c43514eb593c82b5d57e7b1a6fa896f68e430d84 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 15 Sep 2005 23:51:24 +0000 Subject: [PATCH] check/: Add test Original commit message from CVS: * check/Makefile.am: * check/gst/gstplugin.c: Add test * gst/gstplugin.c: Fix problems noticed by testsuite * gst/gstplugin.h: * gst/gstregistry.c: * gst/gstregistry.h: --- ChangeLog | 9 +++ check/Makefile.am | 1 + check/gst/gstplugin.c | 166 ++++++++++++++++++++++++++++++++++++++++++++ gst/gstplugin.c | 22 +++++- gst/gstplugin.h | 4 +- gst/gstregistry.c | 115 ++++++++++++++++++++---------- gst/gstregistry.h | 5 +- tests/check/Makefile.am | 1 + tests/check/gst/gstplugin.c | 166 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 443 insertions(+), 46 deletions(-) create mode 100644 check/gst/gstplugin.c create mode 100644 tests/check/gst/gstplugin.c diff --git a/ChangeLog b/ChangeLog index 021a196..5d4a445 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2005-09-15 David Schleef + * check/Makefile.am: + * check/gst/gstplugin.c: Add test + * gst/gstplugin.c: Fix problems noticed by testsuite + * gst/gstplugin.h: + * gst/gstregistry.c: + * gst/gstregistry.h: + +2005-09-15 David Schleef + * gst/gstplugin.c: Implement semi-decent recounting and locking in plugins and plugin features. * gst/gstplugin.h: diff --git a/check/Makefile.am b/check/Makefile.am index 14e02f8..d8fd600 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -39,6 +39,7 @@ check_PROGRAMS = \ gst/gstobject \ gst/gstpad \ gst/gstpipeline \ + gst/gstplugin \ gst/gstsystemclock \ gst/gststructure \ gst/gsttag \ diff --git a/check/gst/gstplugin.c b/check/gst/gstplugin.c new file mode 100644 index 0000000..e2ae667 --- /dev/null +++ b/check/gst/gstplugin.c @@ -0,0 +1,166 @@ +/* GStreamer + * + * unit test for GstPlugin + * + * Copyright 2004 Thomas Vander Stichele + * Copyright 2005 David Schleef + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +static gboolean +register_check_elements (GstPlugin * plugin) +{ + return TRUE; +} + +static GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "check elements", + "check elements", + register_check_elements, + VERSION, + GST_LICENSE, + PACKAGE, + GST_PACKAGE, + GST_ORIGIN, + + GST_PADDING_INIT +}; + +GST_START_TEST (test_register_static) +{ + GstPlugin *plugin; + + _gst_plugin_register_static (&plugin_desc); + + plugin = g_object_new (GST_TYPE_PLUGIN, NULL); + + gst_object_unref (plugin); +} + +GST_END_TEST +GST_START_TEST (test_load_gstelements) +{ + GstPlugin *unloaded_plugin; + GstPlugin *loaded_plugin; + + unloaded_plugin = gst_default_registry_find_plugin ("gstelements"); + fail_if (unloaded_plugin == NULL, "Failed to find gstelements plugin"); + fail_if (unloaded_plugin->object.refcount != 2, + "Refcount of unloaded plugin in registry initially should be 2"); + + gst_object_ref (unloaded_plugin); + loaded_plugin = gst_plugin_load (unloaded_plugin); + fail_if (loaded_plugin == NULL, "Failed to load plugin"); + + fail_if (loaded_plugin->object.refcount != 2, + "Refcount of loaded plugin in registry should be 2"); + fail_if (unloaded_plugin->object.refcount != 1, + "Refcount of replaced plugin in registry should be 1"); + + gst_object_unref (unloaded_plugin); + gst_object_unref (loaded_plugin); +} + +GST_END_TEST +GST_START_TEST (test_registry_get_plugin_list) +{ + GList *list; + GstPlugin *plugin; + + plugin = gst_default_registry_find_plugin ("gstelements"); + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in registry should be 2"); + + list = gst_registry_get_plugin_list (gst_registry_get_default ()); + + fail_if (plugin->object.refcount != 3, + "Refcount of plugin in registry+list should be 3"); + + gst_plugin_list_free (list); + + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in after list free should be 2"); + + gst_object_unref (plugin); +} + +GST_END_TEST +GST_START_TEST (test_find_feature) +{ + GstPlugin *plugin; + GstPluginFeature *feature; + + plugin = gst_default_registry_find_plugin ("gstelements"); + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in registry should be 2"); + + feature = gst_registry_find_feature (gst_registry_get_default (), + "identity", GST_TYPE_ELEMENT_FACTORY); + fail_if (feature == NULL, "Failed to find identity element factory"); + fail_if (feature->plugin != plugin, + "Expected indentity to be from gstelements plugin"); + + fail_if (plugin->object.refcount != 3, + "Refcount of plugin in registry+feature should be 3"); + + gst_object_unref (feature->plugin); + + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in after list free should be 2"); + + gst_object_unref (plugin); +} +GST_END_TEST Suite * gst_plugin_suite (void) +{ + Suite *s = suite_create ("GstPlugin"); + TCase *tc_chain = tcase_create ("general"); + + /* turn off timeout */ + tcase_set_timeout (tc_chain, 60); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_register_static); + tcase_add_test (tc_chain, test_load_gstelements); + tcase_add_test (tc_chain, test_registry_get_plugin_list); + tcase_add_test (tc_chain, test_find_feature); + + return s; +} + + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = gst_plugin_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_VERBOSE); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} diff --git a/gst/gstplugin.c b/gst/gstplugin.c index adfc78a..7d10169 100644 --- a/gst/gstplugin.c +++ b/gst/gstplugin.c @@ -402,6 +402,7 @@ gst_plugin_load_file (const gchar * filename, GError ** error) _gst_plugin_fault_handler_filename = NULL; GST_INFO ("plugin \"%s\" loaded", plugin->filename); + gst_object_ref (plugin); gst_default_registry_add_plugin (plugin); g_static_mutex_unlock (&gst_plugin_loading_mutex); @@ -857,6 +858,7 @@ GstPlugin * gst_plugin_load (GstPlugin * plugin) { GError *error = NULL; + GstPlugin *newplugin; if (gst_plugin_is_loaded (plugin)) { return plugin; @@ -866,12 +868,26 @@ gst_plugin_load (GstPlugin * plugin) return plugin; } - plugin = gst_plugin_load_file (plugin->filename, &error); - if (!plugin) { + newplugin = gst_plugin_load_file (plugin->filename, &error); + if (newplugin == NULL) { GST_WARNING ("load_plugin error: %s\n", error->message); g_error_free (error); + gst_object_unref (plugin); return NULL; } - return plugin; + gst_object_unref (plugin); + + return newplugin; +} + +void +gst_plugin_list_free (GList * list) +{ + GList *g; + + for (g = list; g; g = g->next) { + gst_object_unref (GST_PLUGIN (g->data)); + } + g_list_free (list); } diff --git a/gst/gstplugin.h b/gst/gstplugin.h index bfae206..dbd1db8 100644 --- a/gst/gstplugin.h +++ b/gst/gstplugin.h @@ -150,9 +150,6 @@ typedef gboolean (*GstPluginFilter) (GstPlugin *plugin, GType gst_plugin_get_type (void); -GstPlugin * gst_plugin_new (void); -void gst_plugin_free (GstPlugin *plugin); - void _gst_plugin_initialize (void); void _gst_plugin_register_static (GstPluginDesc *desc); @@ -175,6 +172,7 @@ GList* gst_plugin_list_feature_filter (GList *list, GstPluginFeatureFilter filter, gboolean first, gpointer user_data); +void gst_plugin_list_free (GList *list); gboolean gst_plugin_name_filter (GstPlugin *plugin, const gchar *name); GList* gst_plugin_get_feature_list (GstPlugin *plugin); diff --git a/gst/gstregistry.c b/gst/gstregistry.c index b72560e..286b439 100644 --- a/gst/gstregistry.c +++ b/gst/gstregistry.c @@ -117,10 +117,12 @@ enum static void gst_registry_class_init (GstRegistryClass * klass); static void gst_registry_init (GstRegistry * registry); -static GObjectClass *parent_class = NULL; static guint gst_registry_signals[LAST_SIGNAL] = { 0 }; -G_DEFINE_TYPE (GstRegistry, gst_registry, G_TYPE_OBJECT); +static GstPlugin *gst_registry_lookup_locked (GstRegistry * registry, + const char *filename); + +G_DEFINE_TYPE (GstRegistry, gst_registry, GST_TYPE_OBJECT); static void gst_registry_class_init (GstRegistryClass * klass) @@ -129,8 +131,6 @@ gst_registry_class_init (GstRegistryClass * klass) gobject_class = (GObjectClass *) klass; - parent_class = g_type_class_ref (G_TYPE_OBJECT); - gst_registry_signals[PLUGIN_ADDED] = g_signal_new ("plugin-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRegistryClass, plugin_added), NULL, @@ -176,13 +176,16 @@ gst_registry_add_path (GstRegistry * registry, const gchar * path) return; } + GST_LOCK (registry); if (g_list_find_custom (registry->paths, path, (GCompareFunc) strcmp)) { g_warning ("path %s already added to registry", path); + GST_UNLOCK (registry); return; } GST_INFO ("Adding plugin path: \"%s\"", path); registry->paths = g_list_append (registry->paths, g_strdup (path)); + GST_UNLOCK (registry); } /** @@ -196,29 +199,20 @@ gst_registry_add_path (GstRegistry * registry, const gchar * path) GList * gst_registry_get_path_list (GstRegistry * registry) { - g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL); - - return g_list_copy (registry->paths); -} + GList *list; + g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL); -/** - * gst_registry_clear_paths: - * @registry: the registry to clear the paths of - * - * Clear the paths of the given registry - */ -void -gst_registry_clear_paths (GstRegistry * registry) -{ - g_return_if_fail (GST_IS_REGISTRY (registry)); - - g_list_foreach (registry->paths, (GFunc) g_free, NULL); - g_list_free (registry->paths); + GST_LOCK (registry); + /* We don't need to copy the strings, because they won't be deleted + * as long as the GstRegistry is around */ + list = g_list_copy (registry->paths); + GST_UNLOCK (registry); - registry->paths = NULL; + return list; } + /** * gst_registry_add_plugin: * @registry: the registry to add the plugin to @@ -235,26 +229,27 @@ gst_registry_add_plugin (GstRegistry * registry, GstPlugin * plugin) g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE); - existing_plugin = gst_registry_lookup (registry, plugin->filename); + GST_LOCK (registry); + existing_plugin = gst_registry_lookup_locked (registry, plugin->filename); if (existing_plugin) { - GST_DEBUG ("Replacing existing plugin for filename \"%s\"", - plugin->filename); + GST_DEBUG ("Replacing existing plugin %p for filename \"%s\"", + existing_plugin, plugin->filename); registry->plugins = g_list_remove (registry->plugins, existing_plugin); gst_object_unref (existing_plugin); } + GST_DEBUG ("Adding plugin %p for filename \"%s\"", plugin, plugin->filename); + registry->plugins = g_list_prepend (registry->plugins, plugin); gst_object_ref (plugin); gst_object_sink (plugin); + GST_UNLOCK (registry); GST_DEBUG ("emitting plugin-added for filename %s", plugin->filename); g_signal_emit (G_OBJECT (registry), gst_registry_signals[PLUGIN_ADDED], 0, plugin); - /* FIXME hack to fix unref later */ - gst_object_ref (plugin); - return TRUE; } @@ -270,7 +265,10 @@ gst_registry_remove_plugin (GstRegistry * registry, GstPlugin * plugin) { g_return_if_fail (GST_IS_REGISTRY (registry)); + GST_LOCK (registry); registry->plugins = g_list_remove (registry->plugins, plugin); + GST_UNLOCK (registry); + gst_object_unref (plugin); } /** @@ -284,16 +282,26 @@ gst_registry_remove_plugin (GstRegistry * registry, GstPlugin * plugin) * the results. If the first flag is set, only the first match is * returned (as a list with a single object). * - * Returns: a GList of plugins, g_list_free after use. + * Returns: a GList of plugins, gst_plugin_list_free after use. */ GList * gst_registry_plugin_filter (GstRegistry * registry, GstPluginFilter filter, gboolean first, gpointer user_data) { + GList *list; + GList *g; + g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL); - return gst_filter_run (registry->plugins, (GstFilterFunc) filter, first, + GST_LOCK (registry); + list = gst_filter_run (registry->plugins, (GstFilterFunc) filter, first, user_data); + for (g = list; g; g = g->next) { + gst_object_ref (GST_PLUGIN (g->data)); + } + GST_UNLOCK (registry); + + return list; } /** @@ -308,16 +316,22 @@ gst_registry_plugin_filter (GstRegistry * registry, * If the first flag is set, only the first match is * returned (as a list with a single object). * - * Returns: a GList of plugin features, g_list_free after use. + * Returns: a GList of plugin features, gst_plugin_feature_list_free after use. */ GList * gst_registry_feature_filter (GstRegistry * registry, GstPluginFeatureFilter filter, gboolean first, gpointer user_data) { + GList *list; + g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL); - return gst_plugin_list_feature_filter (registry->plugins, filter, first, + GST_LOCK (registry); + list = gst_plugin_list_feature_filter (registry->plugins, filter, first, user_data); + GST_UNLOCK (registry); + + return list; } /** @@ -343,7 +357,8 @@ gst_registry_find_plugin (GstRegistry * registry, const gchar * name) if (walk) result = GST_PLUGIN (walk->data); - g_list_free (walk); + gst_object_ref (result); + gst_plugin_list_free (walk); return result; } @@ -380,7 +395,8 @@ gst_registry_find_feature (GstRegistry * registry, const gchar * name, if (walk) feature = GST_PLUGIN_FEATURE (walk->data); - g_list_free (walk); + gst_object_ref (feature->plugin); + gst_plugin_feature_list_free (walk); return feature; } @@ -401,15 +417,28 @@ gst_registry_get_feature_list (GstRegistry * registry, GType type) GList * gst_registry_get_plugin_list (GstRegistry * registry) { - return g_list_copy (registry->plugins); + GList *list; + GList *g; + + GST_LOCK (registry); + list = g_list_copy (registry->plugins); + for (g = list; g; g = g->next) { + gst_object_ref (GST_PLUGIN (g->data)); + } + GST_UNLOCK (registry); + + return list; } -GstPlugin * -gst_registry_lookup (GstRegistry * registry, const char *filename) +static GstPlugin * +gst_registry_lookup_locked (GstRegistry * registry, const char *filename) { GList *g; GstPlugin *plugin; + if (filename == NULL) + return NULL; + for (g = registry->plugins; g; g = g_list_next (g)) { plugin = GST_PLUGIN (g->data); if (plugin->filename && strcmp (filename, plugin->filename) == 0) { @@ -420,6 +449,18 @@ gst_registry_lookup (GstRegistry * registry, const char *filename) return NULL; } +GstPlugin * +gst_registry_lookup (GstRegistry * registry, const char *filename) +{ + GstPlugin *plugin; + + GST_LOCK (registry); + plugin = gst_registry_lookup_locked (registry, filename); + GST_UNLOCK (registry); + + return plugin; +} + static void gst_registry_scan_path_level (GstRegistry * registry, const gchar * path, int level) diff --git a/gst/gstregistry.h b/gst/gstregistry.h index c22659d..5db5e17 100644 --- a/gst/gstregistry.h +++ b/gst/gstregistry.h @@ -39,7 +39,7 @@ typedef struct _GstRegistry GstRegistry; typedef struct _GstRegistryClass GstRegistryClass; struct _GstRegistry { - GObject object; + GstObject object; GList *plugins; @@ -52,7 +52,7 @@ struct _GstRegistry { }; struct _GstRegistryClass { - GObjectClass parent_class; + GstObjectClass parent_class; /* signals */ void (*plugin_added) (GstRegistry *registry, GstPlugin *plugin); @@ -68,7 +68,6 @@ GstRegistry * gst_registry_get_default (void); void gst_registry_scan_path (GstRegistry *registry, const gchar *path); GList* gst_registry_get_path_list (GstRegistry *registry); -void gst_registry_clear_paths (GstRegistry *registry); gboolean gst_registry_add_plugin (GstRegistry *registry, GstPlugin *plugin); void gst_registry_remove_plugin (GstRegistry *registry, GstPlugin *plugin); diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 14e02f8..d8fd600 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -39,6 +39,7 @@ check_PROGRAMS = \ gst/gstobject \ gst/gstpad \ gst/gstpipeline \ + gst/gstplugin \ gst/gstsystemclock \ gst/gststructure \ gst/gsttag \ diff --git a/tests/check/gst/gstplugin.c b/tests/check/gst/gstplugin.c new file mode 100644 index 0000000..e2ae667 --- /dev/null +++ b/tests/check/gst/gstplugin.c @@ -0,0 +1,166 @@ +/* GStreamer + * + * unit test for GstPlugin + * + * Copyright 2004 Thomas Vander Stichele + * Copyright 2005 David Schleef + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +static gboolean +register_check_elements (GstPlugin * plugin) +{ + return TRUE; +} + +static GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "check elements", + "check elements", + register_check_elements, + VERSION, + GST_LICENSE, + PACKAGE, + GST_PACKAGE, + GST_ORIGIN, + + GST_PADDING_INIT +}; + +GST_START_TEST (test_register_static) +{ + GstPlugin *plugin; + + _gst_plugin_register_static (&plugin_desc); + + plugin = g_object_new (GST_TYPE_PLUGIN, NULL); + + gst_object_unref (plugin); +} + +GST_END_TEST +GST_START_TEST (test_load_gstelements) +{ + GstPlugin *unloaded_plugin; + GstPlugin *loaded_plugin; + + unloaded_plugin = gst_default_registry_find_plugin ("gstelements"); + fail_if (unloaded_plugin == NULL, "Failed to find gstelements plugin"); + fail_if (unloaded_plugin->object.refcount != 2, + "Refcount of unloaded plugin in registry initially should be 2"); + + gst_object_ref (unloaded_plugin); + loaded_plugin = gst_plugin_load (unloaded_plugin); + fail_if (loaded_plugin == NULL, "Failed to load plugin"); + + fail_if (loaded_plugin->object.refcount != 2, + "Refcount of loaded plugin in registry should be 2"); + fail_if (unloaded_plugin->object.refcount != 1, + "Refcount of replaced plugin in registry should be 1"); + + gst_object_unref (unloaded_plugin); + gst_object_unref (loaded_plugin); +} + +GST_END_TEST +GST_START_TEST (test_registry_get_plugin_list) +{ + GList *list; + GstPlugin *plugin; + + plugin = gst_default_registry_find_plugin ("gstelements"); + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in registry should be 2"); + + list = gst_registry_get_plugin_list (gst_registry_get_default ()); + + fail_if (plugin->object.refcount != 3, + "Refcount of plugin in registry+list should be 3"); + + gst_plugin_list_free (list); + + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in after list free should be 2"); + + gst_object_unref (plugin); +} + +GST_END_TEST +GST_START_TEST (test_find_feature) +{ + GstPlugin *plugin; + GstPluginFeature *feature; + + plugin = gst_default_registry_find_plugin ("gstelements"); + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in registry should be 2"); + + feature = gst_registry_find_feature (gst_registry_get_default (), + "identity", GST_TYPE_ELEMENT_FACTORY); + fail_if (feature == NULL, "Failed to find identity element factory"); + fail_if (feature->plugin != plugin, + "Expected indentity to be from gstelements plugin"); + + fail_if (plugin->object.refcount != 3, + "Refcount of plugin in registry+feature should be 3"); + + gst_object_unref (feature->plugin); + + fail_if (plugin->object.refcount != 2, + "Refcount of plugin in after list free should be 2"); + + gst_object_unref (plugin); +} +GST_END_TEST Suite * gst_plugin_suite (void) +{ + Suite *s = suite_create ("GstPlugin"); + TCase *tc_chain = tcase_create ("general"); + + /* turn off timeout */ + tcase_set_timeout (tc_chain, 60); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_register_static); + tcase_add_test (tc_chain, test_load_gstelements); + tcase_add_test (tc_chain, test_registry_get_plugin_list); + tcase_add_test (tc_chain, test_find_feature); + + return s; +} + + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = gst_plugin_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_VERBOSE); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} -- 2.7.4