2006-09-28 Jan Schmidt <thaytan@mad.scientist.com>
+ * gst/gst.c: (init_pre), (scan_and_update_registry),
+ (ensure_current_registry_nonforking),
+ (ensure_current_registry_forking), (ensure_current_registry),
+ (init_post), (gst_debug_help), (gst_deinit):
+ * gst/gst_private.h:
+ * gst/gstregistry.c: (gst_registry_finalize),
+ (gst_registry_remove_features_for_plugin_unlocked),
+ (gst_registry_remove_plugin), (gst_registry_scan_path_level),
+ (gst_registry_scan_path),
+ (_priv_gst_registry_remove_cache_plugins),
+ (_priv_gst_registry_cleanup):
+ * gst/gstregistry.h:
+ Re-commit the registry changes, along with an extra fix:
+ When a cached plugin is encountered at a different file path,
+ update the stored path in the registry cache so that the parent
+ process knows where it actually is now when it re-reads the registry
+ cache. Fixes the thing that broke distcheck with the previous commit.
+
+ * tests/check/Makefile.am:
+ Clean up files named 'core' too when running make clean.
+
+ * tests/examples/manual/Makefile.am:
+ Set up a registry path for running these tests, and clean it properly
+ for distcheck.
+
+2006-09-28 Jan Schmidt <thaytan@mad.scientist.com>
+
* configure.ac:
Don't pull in gmodule-2.0.pc as a dependency in our .pc files - we
want gmodule-no-export-2.0.pc instead so that we don't drag in
static gboolean _gst_enable_registry_fork = DEFAULT_FORK;
static void load_plugin_func (gpointer data, gpointer user_data);
-static gboolean init_pre (void);
-static gboolean init_post (void);
+static gboolean init_pre (GOptionContext * context, GOptionGroup * group,
+ gpointer data, GError ** error);
+static gboolean init_post (GOptionContext * context, GOptionGroup * group,
+ gpointer data, GError ** error);
static gboolean parse_goption_arg (const gchar * s_opt,
const gchar * arg, gpointer data, GError ** err);
/* we have no fail cases yet, but maybe in the future */
static gboolean
-init_pre (void)
+init_pre (GOptionContext * context, GOptionGroup * group, gpointer data,
+ GError ** error)
{
/* GStreamer was built against a GLib >= 2.8 and is therefore not doing
* the refcount hack. Check that it isn't being run against an older GLib */
*/
static gboolean
scan_and_update_registry (GstRegistry * default_registry,
- const gchar * registry_file, gboolean write_changes)
+ const gchar * registry_file, gboolean write_changes, GError ** error)
{
const gchar *plugin_path;
gboolean changed = FALSE;
g_strfreev (list);
}
+ /* Remove cached plugins so stale info is cleared. */
+ changed |= _priv_gst_registry_remove_cache_plugins (default_registry);
+
if (!changed) {
- GST_DEBUG ("registry cache has not changed");
+ GST_INFO ("Registry cache has not changed");
return TRUE;
}
if (!write_changes) {
- GST_DEBUG ("not trying to write registry cache changes to file");
+ GST_INFO ("Registry cached changed, but writing is disabled. Not writing.");
return TRUE;
}
- GST_DEBUG ("writing registry cache");
+ GST_INFO ("Registry cache changed. Writing new registry cache");
if (!gst_registry_xml_write_cache (default_registry, registry_file)) {
- g_warning ("Problem writing registry cache to %s: %s", registry_file,
- g_strerror (errno));
+ g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
+ _("Error writing registry cache to %s: %s"),
+ registry_file, g_strerror (errno));
return FALSE;
}
- GST_DEBUG ("registry cache written successfully");
+ GST_INFO ("Registry cache written successfully");
return TRUE;
}
static gboolean
ensure_current_registry_nonforking (GstRegistry * default_registry,
- const gchar * registry_file)
+ const gchar * registry_file, GError ** error)
{
/* fork() not available */
- GST_DEBUG ("updating registry cache");
- scan_and_update_registry (default_registry, registry_file, TRUE);
+ GST_DEBUG ("Updating registry cache in-process");
+ scan_and_update_registry (default_registry, registry_file, TRUE, error);
return TRUE;
}
* TRUE immediatly */
static gboolean
ensure_current_registry_forking (GstRegistry * default_registry,
- const gchar * registry_file)
+ const gchar * registry_file, GError ** error)
{
#ifdef HAVE_FORK
pid_t pid;
/* We fork here, and let the child read and possibly rebuild the registry.
* After that, the parent will re-read the freshly generated registry. */
- GST_DEBUG ("forking");
+ GST_DEBUG ("forking to update registry");
pid = fork ();
if (pid == -1) {
GST_ERROR ("Failed to fork()");
/* this is the child */
GST_DEBUG ("child reading registry cache");
- res = scan_and_update_registry (default_registry, registry_file, TRUE);
- _gst_registry_remove_cache_plugins (default_registry);
+ res =
+ scan_and_update_registry (default_registry, registry_file, TRUE, NULL);
/* need to use _exit, so that any exit handlers registered don't
* bring down the main program */
GST_DEBUG ("parent done waiting on child");
if (ret == -1) {
GST_ERROR ("error during waitpid: %s", g_strerror (errno));
+ g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
+ _("Error re-scanning registry %s: %s"),
+ ", waitpid returned error", g_strerror (errno));
return FALSE;
}
if (WIFSIGNALED (status)) {
GST_ERROR ("child did not exit normally, terminated by signal %d",
WTERMSIG (status));
+ g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
+ _("Error re-scanning registry %s: %d"),
+ ", child terminated by signal", WTERMSIG (status));
} else {
GST_ERROR ("child did not exit normally, status: %d", status);
+ g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
+ _("Error re-scanning registry %s: %d"),
+ ", child did not exit normally, status", status);
}
return FALSE;
}
GST_DEBUG ("parent reading registry cache");
gst_registry_xml_read_cache (default_registry, registry_file);
} else {
- GST_DEBUG ("parent re-scanning registry");
- scan_and_update_registry (default_registry, registry_file, FALSE);
+ GST_DEBUG ("parent re-scanning registry. Ignoring errors.");
+ scan_and_update_registry (default_registry, registry_file, FALSE, NULL);
}
}
#endif /* HAVE_FORK */
}
static gboolean
-ensure_current_registry (void)
+ensure_current_registry (GError ** error)
{
char *registry_file;
GstRegistry *default_registry;
/* now check registry with or without forking */
if (do_fork) {
GST_DEBUG ("forking for registry rebuild");
- ret = ensure_current_registry_forking (default_registry, registry_file);
+ ret = ensure_current_registry_forking (default_registry, registry_file,
+ error);
} else {
GST_DEBUG ("requested not to fork for registry rebuild");
- ret = ensure_current_registry_nonforking (default_registry, registry_file);
+ ret = ensure_current_registry_nonforking (default_registry, registry_file,
+ error);
}
g_free (registry_file);
* we might and then it's nice to be able to return that
*/
static gboolean
-init_post (void)
+init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
+ GError ** error)
{
GLogLevelFlags llf;
gst_initialized = TRUE;
#ifndef GST_DISABLE_REGISTRY
- if (!ensure_current_registry ())
+ if (!ensure_current_registry (error))
return FALSE;
#endif /* GST_DISABLE_REGISTRY */
GSList *list, *walk;
GList *list2, *g;
- if (!init_post ())
+ /* Need to ensure the registry is loaded to get debug categories */
+ if (!init_post (NULL, NULL, NULL, NULL))
exit (1);
list2 = gst_registry_plugin_filter (gst_registry_get_default (),
gst_object_unref (clock);
gst_object_unref (clock);
- _gst_registry_cleanup ();
+ _priv_gst_registry_cleanup ();
gst_initialized = FALSE;
GST_INFO ("deinitialized GStreamer");
#include <stdlib.h>
#include <string.h>
+/* Needed for GstRegistry * */
+#include "gstregistry.h"
+
G_BEGIN_DECLS
gboolean __gst_in_valgrind (void);
/* Initialize GStreamer private quark storage */
void _priv_gst_quarks_initialize (void);
+/* Private registry functions */
+gboolean _priv_gst_registry_remove_cache_plugins (GstRegistry *registry);
+void _priv_gst_registry_cleanup (void);
+
/*** debugging categories *****************************************************/
#ifndef GST_DISABLE_GST_DEBUG
if (plugin) {
GST_DEBUG_OBJECT (registry, "removing plugin %s",
gst_plugin_get_name (plugin));
- gst_registry_remove_plugin (registry, plugin);
+ gst_object_unref (plugin);
}
p = g_list_next (p);
}
GstPluginFeature *feature = f->data;
if (feature) {
- gst_registry_remove_feature (registry, feature);
+ GST_DEBUG_OBJECT (registry, "removing feature %p (%s)",
+ feature, gst_plugin_feature_get_name (feature));
+ gst_object_unref (feature);
}
f = g_list_next (f);
}
return TRUE;
}
+static void
+gst_registry_remove_features_for_plugin_unlocked (GstRegistry * registry,
+ GstPlugin * plugin)
+{
+ GList *f;
+
+ g_return_if_fail (GST_IS_REGISTRY (registry));
+ g_return_if_fail (GST_IS_PLUGIN (plugin));
+
+ /* Remove all features for this plugin */
+ f = registry->features;
+ while (f != NULL) {
+ GList *next = g_list_next (f);
+ GstPluginFeature *feature = f->data;
+
+ if (feature && !strcmp (feature->plugin_name, gst_plugin_get_name (plugin))) {
+ GST_DEBUG_OBJECT (registry, "removing feature %p (%s) for plugin %s",
+ feature, gst_plugin_feature_get_name (feature),
+ gst_plugin_get_name (plugin));
+
+ registry->features = g_list_delete_link (registry->features, f);
+ gst_object_unref (feature);
+ }
+ f = next;
+ }
+}
+
/**
* gst_registry_remove_plugin:
* @registry: the registry to remove the plugin from
g_return_if_fail (GST_IS_REGISTRY (registry));
g_return_if_fail (GST_IS_PLUGIN (plugin));
+ GST_DEBUG_OBJECT (registry, "removing plugin %p (%s)",
+ plugin, gst_plugin_get_name (plugin));
+
GST_OBJECT_LOCK (registry);
registry->plugins = g_list_remove (registry->plugins, plugin);
+ gst_registry_remove_features_for_plugin_unlocked (registry, plugin);
GST_OBJECT_UNLOCK (registry);
gst_object_unref (plugin);
}
struct stat file_status;
if (stat (filename, &file_status)) {
- /* FIXME remove from cache */
+ /* Plugin will be removed from cache after the scan completes if it
+ * is still marked 'cached' */
g_free (filename);
+ gst_object_unref (plugin);
continue;
}
if (plugin->registered) {
plugin->file_size == file_status.st_size) {
GST_DEBUG_OBJECT (registry, "file %s cached", filename);
plugin->flags &= ~GST_PLUGIN_FLAG_CACHED;
- GST_DEBUG_OBJECT (registry, "marking plugin %p as registered", plugin);
+ GST_DEBUG_OBJECT (registry, "marking plugin %p as registered as %s",
+ plugin, filename);
plugin->registered = TRUE;
+ /* Update the file path on which we've seen this cached plugin
+ * to ensure the registry cache will reflect up to date information */
+ if (strcmp (plugin->filename, filename) != 0) {
+ g_free (plugin->filename);
+ plugin->filename = g_strdup (filename);
+ changed = TRUE;
+ }
} else {
GST_INFO_OBJECT (registry, "cached info for %s is stale", filename);
GST_DEBUG_OBJECT (registry, "mtime %ld != %ld or size %"
g_dir_close (dir);
- GST_DEBUG_OBJECT (registry, "registry changed? %d", changed);
-
return changed;
}
GST_DEBUG_OBJECT (registry, "scanning path %s", path);
changed = gst_registry_scan_path_level (registry, path, 10);
- GST_DEBUG_OBJECT (registry, "registry changed? %d", changed);
+ GST_DEBUG_OBJECT (registry, "registry changed in path %s: %d", path, changed);
return changed;
}
-void
-_gst_registry_remove_cache_plugins (GstRegistry * registry)
+/* Unref all plugins marked 'cached', to clear old plugins that no
+ * longer exist. Returns TRUE if any plugins were removed */
+gboolean
+_priv_gst_registry_remove_cache_plugins (GstRegistry * registry)
{
GList *g;
GList *g_next;
GstPlugin *plugin;
+ gboolean changed = FALSE;
- g_return_if_fail (GST_IS_REGISTRY (registry));
+ g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
GST_OBJECT_LOCK (registry);
if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
GST_DEBUG_OBJECT (registry, "removing cached plugin \"%s\"",
GST_STR_NULL (plugin->filename));
- /* seems it would be sufficient just to do a delete_link for o(1) deletion
- * -- we have to traverse the whole list anyway, and dup entries (if
- * possible) should have dup refcounts */
- registry->plugins = g_list_remove (registry->plugins, plugin);
+ registry->plugins = g_list_delete_link (registry->plugins, g);
gst_object_unref (plugin);
+ changed = TRUE;
}
g = g_next;
}
GST_OBJECT_UNLOCK (registry);
+
+ return changed;
}
_gst_plugin_feature_filter_plugin_name, FALSE, (gpointer) name);
}
+/* Unref and delete the default registry */
void
-_gst_registry_cleanup ()
+_priv_gst_registry_cleanup ()
{
GstRegistry *registry;
gboolean gst_registry_xml_read_cache (GstRegistry * registry, const char *location);
gboolean gst_registry_xml_write_cache (GstRegistry * registry, const char *location);
-void _gst_registry_remove_cache_plugins (GstRegistry *registry);
-
-void _gst_registry_cleanup (void);
-
/* convinience defines for the default registry */
/**
install-pluginLTLIBRARIES:
# the core dumps of some machines have PIDs appended
-CLEANFILES = core.* test-registry.xml *.gcno *.gcda
+CLEANFILES = core core.* test-registry.xml *.gcno *.gcda
SUPPRESSIONS = $(top_srcdir)/common/gst.supp
# gnome_LDADD = $(GST_OBJ_LIBS) $(LIBGNOMEUI_LIBS)
# gnome_CFLAGS = $(GST_OBJ_CFLAGS) $(LIBGNOMEUI_CFLAGS)
+CLEANFILES = core core.* test-registry.xml *.gcno *.gcda
+
EXTRA_DIST = extract.pl
EXAMPLES = \
$(PERL_PATH) $(srcdir)/extract.pl $@ \
$(top_srcdir)/docs/manual/highlevel-xml.xml
+CHECK_REGISTRY = $(top_builddir)/tests/examples/manual/test-registry.xml
+
+REGISTRY_ENVIRONMENT = \
+ GST_REGISTRY=$(CHECK_REGISTRY)
+
+TESTS_ENVIRONMENT = \
+ $(REGISTRY_ENVIRONMENT) \
+ GST_PLUGIN_SYSTEM_PATH= \
+ GST_PLUGIN_PATH=$(top_builddir)/plugins
+
TESTS = bin \
elementcreate elementfactory elementget elementlink elementmake \
ghostpad init