X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusintrospection.c;h=6d3ff93ead7224c5e4477e3a0cfc3cea1e132baa;hb=e55a953642a9e402f4363f9fa347b6061dd78990;hp=5d9b6bdd0425ce847f673a11973ca4b7dd157f84;hpb=73af5ab4cf14d33495ba098af3b53f7d7f257256;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusintrospection.c b/gio/gdbusintrospection.c index 5d9b6bd..6d3ff93 100644 --- a/gio/gdbusintrospection.c +++ b/gio/gdbusintrospection.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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. + * Public License along with this library; if not, see . * * Author: David Zeuthen */ @@ -40,7 +38,7 @@ * used when registering objects with g_dbus_connection_register_object(). * * The format of D-Bus introspection XML is specified in the - * D-Bus specification. + * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format) */ /* ---------------------------------------------------------------------------------------------------- */ @@ -583,12 +581,15 @@ g_dbus_annotation_info_generate_xml (GDBusAnnotationInfo *info, guint indent, GString *string_builder) { + gchar *tmp; guint n; - g_string_append_printf (string_builder, "%*skey, - info->value); + tmp = g_markup_printf_escaped ("%*skey, + info->value); + g_string_append (string_builder, tmp); + g_free (tmp); if (info->annotations == NULL) { @@ -773,13 +774,13 @@ g_dbus_property_info_generate_xml (GDBusPropertyInfo *info, * g_dbus_interface_info_generate_xml: * @info: A #GDBusNodeInfo * @indent: Indentation level. - * @string_builder: A #GString to to append XML data to. + * @string_builder: (out): A #GString to to append XML data to. * * Appends an XML representation of @info (and its children) to @string_builder. * * This function is typically used for generating introspection XML * documents at run-time for handling the - * org.freedesktop.DBus.Introspectable.Introspect + * `org.freedesktop.DBus.Introspectable.Introspect` * method. * * Since: 2.26 @@ -822,12 +823,12 @@ g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info, * g_dbus_node_info_generate_xml: * @info: A #GDBusNodeInfo. * @indent: Indentation level. - * @string_builder: A #GString to to append XML data to. + * @string_builder: (out): A #GString to to append XML data to. * * Appends an XML representation of @info (and its children) to @string_builder. * * This function is typically used for generating introspection XML documents at run-time for - * handling the org.freedesktop.DBus.Introspectable.Introspect method. + * handling the `org.freedesktop.DBus.Introspectable.Introspect` method. * * Since: 2.26 */ @@ -1755,6 +1756,13 @@ parser_error (GMarkupParseContext *context, * * Parses @xml_data and returns a #GDBusNodeInfo representing the data. * + * The introspection XML must contain exactly one top-level + * element. + * + * Note that this routine is using a + * [GMarkup][glib-Simple-XML-Subset-Parser.description]-based + * parser that only accepts a subset of valid XML documents. + * * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free * with g_dbus_node_info_unref(). * @@ -1782,7 +1790,7 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, data = parse_data_new (); context = g_markup_parse_context_new (parser, - 0, + G_MARKUP_IGNORE_QUALIFIED, data, (GDestroyNotify) parse_data_free); @@ -1810,11 +1818,8 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, /* clean up */ for (n = 0; n < num_nodes; n++) { - for (n = 0; n < num_nodes; n++) - { - g_dbus_node_info_unref (ughret[n]); - ughret[n] = NULL; - } + g_dbus_node_info_unref (ughret[n]); + ughret[n] = NULL; } } @@ -1822,8 +1827,7 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, g_free (ughret); out: - if (parser != NULL) - g_free (parser); + g_free (parser); if (context != NULL) g_markup_parse_context_free (context); @@ -1834,12 +1838,12 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, /** * g_dbus_annotation_info_lookup: - * @annotations: A %NULL-terminated array of annotations or %NULL. + * @annotations: (array zero-terminated=1) (allow-none): A %NULL-terminated array of annotations or %NULL. * @name: The name of the annotation to look up. * * Looks up the value of an annotation. * - * This cost of this function is O(n) in number of annotations. + * The cost of this function is O(n) in number of annotations. * * Returns: The value or %NULL if not found. Do not free, it is owned by @annotations. * @@ -1868,6 +1872,37 @@ g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations, /* ---------------------------------------------------------------------------------------------------- */ +G_LOCK_DEFINE_STATIC (info_cache_lock); + +typedef struct +{ + gint use_count; + + /* gchar* -> GDBusMethodInfo* */ + GHashTable *method_name_to_data; + + /* gchar* -> GDBusMethodInfo* */ + GHashTable *signal_name_to_data; + + /* gchar* -> GDBusMethodInfo* */ + GHashTable *property_name_to_data; +} InfoCacheEntry; + +static void +info_cache_free (InfoCacheEntry *cache) +{ + g_assert (cache->use_count == 0); + g_hash_table_unref (cache->method_name_to_data); + g_hash_table_unref (cache->signal_name_to_data); + g_hash_table_unref (cache->property_name_to_data); + g_slice_free (InfoCacheEntry, cache); +} + +/* maps from GDBusInterfaceInfo* to InfoCacheEntry* */ +static GHashTable *info_cache = NULL; + +/* ---------------------------------------------------------------------------------------------------- */ + /** * g_dbus_interface_info_lookup_method: * @info: A #GDBusInterfaceInfo. @@ -1875,9 +1910,10 @@ g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations, * * Looks up information about a method. * - * This cost of this function is O(n) in number of methods. + * The cost of this function is O(n) in number of methods unless + * g_dbus_interface_info_cache_build() has been used on @info. * - * Returns: A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info. + * Returns: (transfer none): A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info. * * Since: 2.26 */ @@ -1888,6 +1924,20 @@ g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info, guint n; GDBusMethodInfo *result; + G_LOCK (info_cache_lock); + if (G_LIKELY (info_cache != NULL)) + { + InfoCacheEntry *cache; + cache = g_hash_table_lookup (info_cache, info); + if (G_LIKELY (cache != NULL)) + { + result = g_hash_table_lookup (cache->method_name_to_data, name); + G_UNLOCK (info_cache_lock); + goto out; + } + } + G_UNLOCK (info_cache_lock); + for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++) { GDBusMethodInfo *i = info->methods[n]; @@ -1914,9 +1964,10 @@ g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info, * * Looks up information about a signal. * - * This cost of this function is O(n) in number of signals. + * The cost of this function is O(n) in number of signals unless + * g_dbus_interface_info_cache_build() has been used on @info. * - * Returns: A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info. + * Returns: (transfer none): A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info. * * Since: 2.26 */ @@ -1927,6 +1978,20 @@ g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info, guint n; GDBusSignalInfo *result; + G_LOCK (info_cache_lock); + if (G_LIKELY (info_cache != NULL)) + { + InfoCacheEntry *cache; + cache = g_hash_table_lookup (info_cache, info); + if (G_LIKELY (cache != NULL)) + { + result = g_hash_table_lookup (cache->signal_name_to_data, name); + G_UNLOCK (info_cache_lock); + goto out; + } + } + G_UNLOCK (info_cache_lock); + for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++) { GDBusSignalInfo *i = info->signals[n]; @@ -1953,9 +2018,10 @@ g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info, * * Looks up information about a property. * - * This cost of this function is O(n) in number of properties. + * The cost of this function is O(n) in number of properties unless + * g_dbus_interface_info_cache_build() has been used on @info. * - * Returns: A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info. + * Returns: (transfer none): A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info. * * Since: 2.26 */ @@ -1966,6 +2032,20 @@ g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info, guint n; GDBusPropertyInfo *result; + G_LOCK (info_cache_lock); + if (G_LIKELY (info_cache != NULL)) + { + InfoCacheEntry *cache; + cache = g_hash_table_lookup (info_cache, info); + if (G_LIKELY (cache != NULL)) + { + result = g_hash_table_lookup (cache->property_name_to_data, name); + G_UNLOCK (info_cache_lock); + goto out; + } + } + G_UNLOCK (info_cache_lock); + for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++) { GDBusPropertyInfo *i = info->properties[n]; @@ -1986,15 +2066,104 @@ g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info, /* ---------------------------------------------------------------------------------------------------- */ /** + * g_dbus_interface_info_cache_build: + * @info: A #GDBusInterfaceInfo. + * + * Builds a lookup-cache to speed up + * g_dbus_interface_info_lookup_method(), + * g_dbus_interface_info_lookup_signal() and + * g_dbus_interface_info_lookup_property(). + * + * If this has already been called with @info, the existing cache is + * used and its use count is increased. + * + * Note that @info cannot be modified until + * g_dbus_interface_info_cache_release() is called. + * + * Since: 2.30 + */ +void +g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info) +{ + InfoCacheEntry *cache; + guint n; + + G_LOCK (info_cache_lock); + if (info_cache == NULL) + info_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) info_cache_free); + cache = g_hash_table_lookup (info_cache, info); + if (cache != NULL) + { + cache->use_count += 1; + goto out; + } + cache = g_slice_new0 (InfoCacheEntry); + cache->use_count = 1; + cache->method_name_to_data = g_hash_table_new (g_str_hash, g_str_equal); + cache->signal_name_to_data = g_hash_table_new (g_str_hash, g_str_equal); + cache->property_name_to_data = g_hash_table_new (g_str_hash, g_str_equal); + for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++) + g_hash_table_insert (cache->method_name_to_data, info->methods[n]->name, info->methods[n]); + for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++) + g_hash_table_insert (cache->signal_name_to_data, info->signals[n]->name, info->signals[n]); + for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++) + g_hash_table_insert (cache->property_name_to_data, info->properties[n]->name, info->properties[n]); + g_hash_table_insert (info_cache, info, cache); + out: + G_UNLOCK (info_cache_lock); +} + +/** + * g_dbus_interface_info_cache_release: + * @info: A GDBusInterfaceInfo + * + * Decrements the usage count for the cache for @info built by + * g_dbus_interface_info_cache_build() (if any) and frees the + * resources used by the cache if the usage count drops to zero. + * + * Since: 2.30 + */ +void +g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info) +{ + InfoCacheEntry *cache; + + G_LOCK (info_cache_lock); + if (G_UNLIKELY (info_cache == NULL)) + { + g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC); + goto out; + } + + cache = g_hash_table_lookup (info_cache, info); + if (G_UNLIKELY (cache == NULL)) + { + g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC); + goto out; + } + cache->use_count -= 1; + if (cache->use_count == 0) + { + g_hash_table_remove (info_cache, info); + /* could nuke info_cache itself if empty */ + } + out: + G_UNLOCK (info_cache_lock); +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +/** * g_dbus_node_info_lookup_interface: * @info: A #GDBusNodeInfo. * @name: A D-Bus interface name. * * Looks up information about an interface. * - * This cost of this function is O(n) in number of interfaces. + * The cost of this function is O(n) in number of interfaces. * - * Returns: A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info. + * Returns: (transfer none): A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info. * * Since: 2.26 */