[glib/wip/resources2: 2/2] Allow resources to work with unloadable GTypeModules



commit 3fabc2d5def16638cd9c9bde8ac13aa507810dab
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Jan 10 16:40:45 2012 +0100

    Allow resources to work with unloadable GTypeModules

 gio/gio.symbols            |    1 +
 gio/gresource.c            |   58 ++++++++++++++++++++++++++++++++++++++++----
 gio/gresource.h            |    2 +
 gio/tests/resourceplugin.c |    4 ++-
 gio/tests/resources.c      |   18 +++++++++++++-
 5 files changed, 76 insertions(+), 7 deletions(-)
---
diff --git a/gio/gio.symbols b/gio/gio.symbols
index dcf9ec7..22a8af0 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1685,6 +1685,7 @@ g_resource_lookup_flags_get_type
 g_resource_new_from_data
 g_resource_open_stream
 g_resource_ref
+g_resource_set_module
 g_resource_unref
 g_resources_enumerate_children
 g_resources_get_info
diff --git a/gio/gresource.c b/gio/gresource.c
index d659df0..be377fd 100644
--- a/gio/gresource.c
+++ b/gio/gresource.c
@@ -36,6 +36,7 @@ struct _GResource
   int ref_count;
 
   GvdbTable *table;
+  GTypeModule *module;
 };
 
 G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
@@ -115,8 +116,10 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
  *
  * Note that resource data can point directly into the data segment of e.g. a library, so if you are unloading libraries
  * during runtime you need to be very careful with keeping around pointers to data from a resource, as this goes away
- * when the library is unloaded. However, in practice this is not generally a problem, since most resource accesses
- * is for your own resources, and resource data is often used once, during parsing, and then released.
+ * when the library is unloaded. For modules using #GTypeModule we support disallowing unload while resources are
+ * outstanding by using g_resource_set_module(), but not all libraries might use this. However, in practice this is
+ * not generally a problem, since most resource accesses is for your own resources, and resource data is often
+ * used once, during parsing, and then released.
  *
  * Since: 2.32
  */
@@ -176,6 +179,51 @@ g_resource_unref (GResource *resource)
 }
 
 /**
+ * g_resource_set_module:
+ * @resource: A #GResource.
+ * @type_module: (allow-none): A #GTypeModule, or %NULL.
+ *
+ * Allows setting a #GTypeModule to be associated with the
+ * resource. As long as any reference to data from the
+ * resource is outstanding the GTypeModule is used, and
+ * thus will not be unloaded.
+ *
+ * This is useful if you link a resource into a module
+ * and want to ensure that its not unloaded while there
+ * is outstanding pointers into the linked in data.
+ *
+ * Since: 2.32
+ **/
+void
+g_resource_set_module (GResource *resource,
+		       GTypeModule *type_module)
+{
+  if (resource->module)
+    g_object_unref (resource->module);
+
+  resource->module = type_module;
+
+  if (resource->module)
+    g_object_ref (resource->module);
+}
+
+static GResource *
+g_resource_use (GResource *resource)
+{
+  if (resource->module)
+    g_type_module_use (resource->module);
+  return g_resource_ref (resource);
+}
+
+static void
+g_resource_unuse (GResource *resource)
+{
+  if (resource->module)
+    g_type_module_unuse (resource->module);
+  g_resource_unref (resource);
+}
+
+/**
  * g_resource_new_from_data:
  * @data: A #GBytes.
  * @error: return location for a #GError, or %NULL.
@@ -367,8 +415,8 @@ g_resource_open_stream (GResource *resource,
 
   stream = g_memory_input_stream_new_from_data (data, data_size, NULL);
   g_object_set_data_full (G_OBJECT (stream), "g-resource",
-			  g_resource_ref (resource),
-			  (GDestroyNotify)g_resource_unref);
+			  g_resource_use (resource),
+			  (GDestroyNotify)g_resource_unuse);
 
   if (flags & G_RESOURCE_FLAGS_COMPRESSED)
     {
@@ -474,7 +522,7 @@ g_resource_lookup_data (GResource *resource,
       return g_bytes_new_take (uncompressed, size);
     }
   else
-    return g_bytes_new_with_free_func (data, data_size, (GDestroyNotify)g_resource_unref, g_resource_ref (resource));
+    return g_bytes_new_with_free_func (data, data_size, (GDestroyNotify)g_resource_unuse, g_resource_use (resource));
 }
 
 /**
diff --git a/gio/gresource.h b/gio/gresource.h
index f1a8c8e..4691057 100644
--- a/gio/gresource.h
+++ b/gio/gresource.h
@@ -74,6 +74,8 @@ gboolean      g_resource_get_info            (GResource             *resource,
 					      gsize                 *size,
 					      guint32               *flags,
 					      GError               **error);
+void          g_resource_set_module          (GResource             *resource,
+					      GTypeModule           *type_module);
 
 void          g_resources_register           (GResource             *resource);
 void          g_resources_unregister         (GResource             *resource);
diff --git a/gio/tests/resourceplugin.c b/gio/tests/resourceplugin.c
index b66d541..c1626ec 100644
--- a/gio/tests/resourceplugin.c
+++ b/gio/tests/resourceplugin.c
@@ -1,8 +1,11 @@
 #include <gio/gio.h>
 
+extern GResource *_g_plugin_resource;
+
 void
 g_io_module_load (GIOModule *module)
 {
+  g_resource_set_module (_g_plugin_resource, G_TYPE_MODULE (module));
 }
 
 void
@@ -15,4 +18,3 @@ g_io_module_query (void)
 {
   return NULL;
 }
-
diff --git a/gio/tests/resources.c b/gio/tests/resources.c
index ed6a249..bf3bd9f 100644
--- a/gio/tests/resources.c
+++ b/gio/tests/resources.c
@@ -411,6 +411,8 @@ test_resource_module (void)
 
       error = NULL;
 
+      /* Module is not loaded yet */
+
       found = g_resources_get_info ("/resourceplugin/test1.txt",
 				    G_RESOURCE_LOOKUP_FLAGS_NONE,
 				    &size, &flags, &error);
@@ -418,6 +420,8 @@ test_resource_module (void)
       g_assert_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND);
       g_clear_error (&error);
 
+      /* Load the module */
+
       g_type_module_use (G_TYPE_MODULE (module));
 
       found = g_resources_get_info ("/resourceplugin/test1.txt",
@@ -436,13 +440,25 @@ test_resource_module (void)
       size = g_bytes_get_size (data);
       g_assert (size == 6);
       g_assert_cmpstr (g_bytes_get_data (data, NULL), ==, "test1\n");
-      g_bytes_unref (data);
 
+      /* Don't unref data, should keep the module in use */
+
+      /* Unuse the module */
       g_type_module_unuse (G_TYPE_MODULE (module));
 
       found = g_resources_get_info ("/resourceplugin/test1.txt",
 				    G_RESOURCE_LOOKUP_FLAGS_NONE,
 				    &size, &flags, &error);
+      g_assert (found);
+      g_assert_no_error (error);
+
+
+      /* Unref the data, should unload the module */
+      g_bytes_unref (data);
+
+      found = g_resources_get_info ("/resourceplugin/test1.txt",
+				    G_RESOURCE_LOOKUP_FLAGS_NONE,
+				    &size, &flags, &error);
       g_assert (!found);
       g_assert_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND);
       g_clear_error (&error);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]