Plugin loader phase 2
authorJan Schmidt <thaytan@noraisin.net>
Fri, 23 Jan 2009 15:47:08 +0000 (15:47 +0000)
committerJan Schmidt <thaytan@noraisin.net>
Tue, 6 Oct 2009 18:51:42 +0000 (19:51 +0100)
phase 2 - make the plugin loader receive the list of plugins to load and
send back the results asynchronously, so we don't context switch back
and forth so much.

gst/gstpluginloader.c
gst/gstpluginloader.h
gst/gstregistry.c

index 3fd29cc..8ea7959 100644 (file)
 static GstPluginLoader *plugin_loader_new (GstRegistry * registry);
 static gboolean plugin_loader_free (GstPluginLoader * loader);
 static gboolean plugin_loader_load (GstPluginLoader * loader,
-    const gchar * filename);
+    const gchar * filename, off_t file_size, time_t file_mtime);
 
 const GstPluginLoaderFuncs _priv_gst_plugin_loader_funcs = {
   plugin_loader_new, plugin_loader_free, plugin_loader_load
 };
 
+typedef struct _PendingPluginEntry
+{
+  guint32 tag;
+  gchar *filename;
+  off_t file_size;
+  time_t file_mtime;
+} PendingPluginEntry;
+
 struct _GstPluginLoader
 {
   GstRegistry *registry;
@@ -75,6 +83,11 @@ struct _GstPluginLoader
   guint8 *rx_buf;
   guint rx_buf_size;
   gboolean rx_done;
+
+  /* Head and tail of the pending plugins list. List of
+     PendingPluginEntry structs */
+  GList *pending_plugins;
+  GList *pending_plugins_tail;
 };
 
 #define PACKET_EXIT 1
@@ -118,6 +131,7 @@ plugin_loader_new (GstRegistry * registry)
 static gboolean
 plugin_loader_free (GstPluginLoader * loader)
 {
+  GList *cur;
   gboolean got_plugin_details;
 
   fsync (loader->fd_w.fd);
@@ -154,14 +168,28 @@ plugin_loader_free (GstPluginLoader * loader)
 
   got_plugin_details = loader->got_plugin_details;
 
+  /* Free any pending plugin entries */
+  cur = loader->pending_plugins;
+  while (cur) {
+    PendingPluginEntry *entry = (PendingPluginEntry *) (cur->data);
+    g_free (entry->filename);
+    g_free (entry);
+
+    cur = g_list_delete_link (cur, cur);
+  }
+
   g_free (loader);
 
   return got_plugin_details;
 }
 
 static gboolean
-plugin_loader_load (GstPluginLoader * loader, const gchar * filename)
+plugin_loader_load (GstPluginLoader * loader, const gchar * filename,
+    off_t file_size, time_t file_mtime)
 {
+  gint len;
+  PendingPluginEntry *entry;
+
   if (!loader->child_started) {
     if (!gst_plugin_loader_spawn (loader))
       return FALSE;
@@ -171,10 +199,22 @@ plugin_loader_load (GstPluginLoader * loader, const gchar * filename)
   GST_LOG_OBJECT (loader->registry,
       "Sending file %s to child. tag %u", filename, loader->next_tag);
 
-  put_packet (loader, PACKET_LOAD_PLUGIN, loader->next_tag,
-      (guint8 *) filename, strlen (filename) + 1);
+  entry = g_new (PendingPluginEntry, 1);
+  entry->tag = loader->next_tag++;
+  entry->filename = g_strdup (filename);
+  entry->file_size = file_size;
+  entry->file_mtime = file_mtime;
+  loader->pending_plugins_tail =
+      g_list_append (loader->pending_plugins_tail, entry);
+
+  if (loader->pending_plugins == NULL)
+    loader->pending_plugins = loader->pending_plugins_tail;
+  else
+    loader->pending_plugins_tail = g_list_next (loader->pending_plugins_tail);
 
-  loader->next_tag++;
+  len = strlen (filename);
+  put_packet (loader, PACKET_LOAD_PLUGIN, entry->tag,
+      (guint8 *) filename, len + 1);
 
   if (!exchange_packets (loader))
     return FALSE;
@@ -412,9 +452,35 @@ handle_rx_packet (GstPluginLoader * l,
       break;
     case PACKET_PLUGIN_DETAILS:{
       gchar *tmp = (gchar *) payload;
+      PendingPluginEntry *entry = NULL;
+      GList *cur;
 
       GST_DEBUG_OBJECT (l->registry,
-          "child loaded plugin w/ tag %u. %d bytes info", tag, payload_len);
+          "Received plugin details from child w/ tag %u. %d bytes info",
+          tag, payload_len);
+
+      /* Assume that tagged details come back in the order
+       * we requested, and delete anything before this one */
+      cur = l->pending_plugins;
+      while (cur) {
+        PendingPluginEntry *e = (PendingPluginEntry *) (cur->data);
+
+        if (e->tag > tag)
+          break;
+
+        cur = g_list_delete_link (cur, cur);
+
+        if (e->tag == tag) {
+          entry = e;
+          break;
+        } else {
+          g_free (e->filename);
+          g_free (e);
+        }
+      }
+      l->pending_plugins = cur;
+      if (cur == NULL)
+        l->pending_plugins_tail = NULL;
 
       if (payload_len > 0) {
         GstPlugin *newplugin;
@@ -428,6 +494,32 @@ handle_rx_packet (GstPluginLoader * l,
 
         /* We got a set of plugin details - remember it for later */
         l->got_plugin_details = TRUE;
+      } else if (entry != NULL) {
+        /* Create a dummy entry for this file to prevent scanning every time */
+        GstPlugin *plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
+
+        plugin->filename = g_strdup (entry->filename);
+        plugin->file_mtime = entry->file_mtime;
+        plugin->file_size = entry->file_size;
+
+        plugin->basename = g_path_get_basename (plugin->filename);
+        plugin->desc.name = g_intern_string (plugin->basename);
+        plugin->desc.description = g_strdup_printf ("Dummy plugin for file %s",
+            plugin->filename);
+        plugin->desc.version = g_intern_string ("0.0.0");
+        plugin->desc.license = g_intern_string ("DUMMY");
+        plugin->desc.source = plugin->desc.license;
+        plugin->desc.package = plugin->desc.license;
+        plugin->desc.origin = plugin->desc.license;
+
+        GST_DEBUG ("Adding dummy plugin '%s'", plugin->desc.name);
+        gst_registry_add_plugin (l->registry, plugin);
+        l->got_plugin_details = TRUE;
+      }
+
+      if (entry != NULL) {
+        g_free (entry->filename);
+        g_free (entry);
       }
 
       break;
index cae2634..b2dbabd 100644 (file)
@@ -28,7 +28,8 @@ typedef struct _GstPluginLoader GstPluginLoader;
 typedef struct _GstPluginLoaderFuncs {
   GstPluginLoader * (*create)(GstRegistry *registry);
   gboolean (*destroy)(GstPluginLoader *loader);
-  gboolean (*load)(GstPluginLoader *loader, const gchar *filename);
+  gboolean (*load)(GstPluginLoader *loader, const gchar *filename,
+      off_t file_size, time_t file_mtime);
 } GstPluginLoaderFuncs;
 
 extern const GstPluginLoaderFuncs _priv_gst_plugin_loader_funcs;
index b179fa5..591e798 100644 (file)
@@ -878,7 +878,7 @@ clear_scan_context (GstRegistryScanContext * context)
 
 static gboolean
 gst_registry_scan_plugin_file (GstRegistryScanContext * context,
-    const gchar * filename)
+    const gchar * filename, off_t file_size, time_t file_mtime)
 {
   gboolean changed = FALSE;
   GstPlugin *newplugin = NULL;
@@ -895,7 +895,8 @@ gst_registry_scan_plugin_file (GstRegistryScanContext * context,
 
   if (context->helper_state == REGISTRY_SCAN_HELPER_RUNNING) {
     GST_DEBUG ("Using scan-helper to load plugin %s", filename);
-    if (!_priv_gst_plugin_loader_funcs.load (context->helper, filename)) {
+    if (!_priv_gst_plugin_loader_funcs.load (context->helper,
+            filename, file_size, file_mtime)) {
       g_warning ("External plugin loader failed...");
       context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
     }
@@ -1027,14 +1028,16 @@ gst_registry_scan_path_level (GstRegistryScanContext * context,
             (gint64) plugin->file_size, (gint64) file_status.st_size,
             env_vars_changed, deps_changed);
         gst_registry_remove_plugin (context->registry, plugin);
-        changed |= gst_registry_scan_plugin_file (context, filename);
+        changed |= gst_registry_scan_plugin_file (context, filename,
+            file_status.st_size, file_status.st_mtime);
       }
       gst_object_unref (plugin);
 
     } else {
       GST_DEBUG_OBJECT (context->registry, "file %s not yet in registry",
           filename);
-      changed |= gst_registry_scan_plugin_file (context, filename);
+      changed |= gst_registry_scan_plugin_file (context, filename,
+          file_status.st_size, file_status.st_mtime);
     }
 
     g_free (filename);