X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-object-tree.c;h=953aa3bd7a182de4fb716dbc49b007423c8eaaa7;hb=e113a70b567eb413ce43ca79f2be56b08c41516f;hp=ae28cc1c9fe818ce889886154852a4f7e2a53241;hpb=df0c6408805341f1ac673430ce6e92f352a473e6;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index ae28cc1..953aa3b 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -1,7 +1,7 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) * - * Copyright (C) 2003 Red Hat Inc. + * Copyright (C) 2003, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * @@ -74,7 +74,7 @@ struct DBusObjectSubtree void *user_data; /**< Data for functions */ DBusObjectSubtree **subtrees; /**< Child nodes */ int n_subtrees; /**< Number of child nodes */ - unsigned int subtrees_sorted : 1; /**< Whether children are sorted */ + int max_subtrees; /**< Number of allocated entries in subtrees */ unsigned int invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */ char name[1]; /**< Allocated as large as necessary */ }; @@ -152,36 +152,6 @@ _dbus_object_tree_unref (DBusObjectTree *tree) } } -static int -subtree_cmp (DBusObjectSubtree *subtree_a, - DBusObjectSubtree *subtree_b) -{ - return strcmp (subtree_a->name, subtree_b->name); -} - -static int -subtree_qsort_cmp (const void *a, - const void *b) -{ - DBusObjectSubtree **subtree_a_p = (void*) a; - DBusObjectSubtree **subtree_b_p = (void*) b; - - return subtree_cmp (*subtree_a_p, *subtree_b_p); -} - -static void -ensure_sorted (DBusObjectSubtree *subtree) -{ - if (subtree->subtrees && !subtree->subtrees_sorted) - { - qsort (subtree->subtrees, - subtree->n_subtrees, - sizeof (DBusObjectSubtree*), - subtree_qsort_cmp); - subtree->subtrees_sorted = TRUE; - } -} - /** Set to 1 to get a bunch of debug spew about finding the * subtree nodes */ @@ -194,7 +164,7 @@ find_subtree_recurse (DBusObjectSubtree *subtree, int *index_in_parent, dbus_bool_t *exact_match) { - int i; + int i, j; dbus_bool_t return_deepest_match; return_deepest_match = exact_match != NULL; @@ -217,22 +187,18 @@ find_subtree_recurse (DBusObjectSubtree *subtree, subtree->name, path[0]); #endif - ensure_sorted (subtree); - - /* FIXME we should do a binary search here instead - * of O(n) - */ - i = 0; - while (i < subtree->n_subtrees) + j = subtree->n_subtrees; + while (i < j) { - int v; + int k, v; - v = strcmp (path[0], subtree->subtrees[i]->name); + k = (i + j) / 2; + v = strcmp (path[0], subtree->subtrees[k]->name); #if VERBOSE_FIND _dbus_verbose (" %s cmp %s = %d\n", - path[0], subtree->subtrees[i]->name, + path[0], subtree->subtrees[k]->name, v); #endif @@ -241,16 +207,16 @@ find_subtree_recurse (DBusObjectSubtree *subtree, if (index_in_parent) { #if VERBOSE_FIND - _dbus_verbose (" storing parent index %d\n", i); + _dbus_verbose (" storing parent index %d\n", k); #endif - *index_in_parent = i; + *index_in_parent = k; } if (return_deepest_match) { DBusObjectSubtree *next; - next = find_subtree_recurse (subtree->subtrees[i], + next = find_subtree_recurse (subtree->subtrees[k], &path[1], create_if_not_found, index_in_parent, exact_match); if (next == NULL && @@ -268,19 +234,20 @@ find_subtree_recurse (DBusObjectSubtree *subtree, return next; } else - return find_subtree_recurse (subtree->subtrees[i], + return find_subtree_recurse (subtree->subtrees[k], &path[1], create_if_not_found, index_in_parent, exact_match); } else if (v < 0) { - goto not_found; + j = k; + } + else + { + i = k + 1; } - - ++i; } - not_found: #if VERBOSE_FIND _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n", subtree->name, create_if_not_found); @@ -289,8 +256,7 @@ find_subtree_recurse (DBusObjectSubtree *subtree, if (create_if_not_found) { DBusObjectSubtree* child; - DBusObjectSubtree **new_subtrees; - int new_n_subtrees; + int child_pos, new_n_subtrees; #if VERBOSE_FIND _dbus_verbose (" creating subtree %s\n", @@ -302,25 +268,41 @@ find_subtree_recurse (DBusObjectSubtree *subtree, if (child == NULL) return NULL; - /* FIXME we should do the "double alloc each time" standard thing */ new_n_subtrees = subtree->n_subtrees + 1; - new_subtrees = dbus_realloc (subtree->subtrees, - new_n_subtrees * sizeof (DBusObjectSubtree*)); - if (new_subtrees == NULL) + if (new_n_subtrees > subtree->max_subtrees) { - child->unregister_function = NULL; - child->message_function = NULL; - _dbus_object_subtree_unref (child); - return NULL; + int new_max_subtrees; + DBusObjectSubtree **new_subtrees; + + new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees; + new_subtrees = dbus_realloc (subtree->subtrees, + new_max_subtrees * sizeof (DBusObjectSubtree*)); + if (new_subtrees == NULL) + { + _dbus_object_subtree_unref (child); + return NULL; + } + subtree->subtrees = new_subtrees; + subtree->max_subtrees = new_max_subtrees; } - new_subtrees[subtree->n_subtrees] = child; + /* The binary search failed, so i == j points to the + place the child should be inserted. */ + child_pos = i; + _dbus_assert (child_pos < new_n_subtrees && + new_n_subtrees <= subtree->max_subtrees); + if (child_pos + 1 < new_n_subtrees) + { + memmove (&subtree->subtrees[child_pos+1], + &subtree->subtrees[child_pos], + (new_n_subtrees - child_pos - 1) * + sizeof subtree->subtrees[0]); + } + subtree->subtrees[child_pos] = child; + if (index_in_parent) - *index_in_parent = subtree->n_subtrees; - subtree->subtrees_sorted = FALSE; + *index_in_parent = child_pos; subtree->n_subtrees = new_n_subtrees; - subtree->subtrees = new_subtrees; - child->parent = subtree; return find_subtree_recurse (child, @@ -373,6 +355,9 @@ find_handler (DBusObjectTree *tree, _dbus_verbose ("Looking for deepest handler\n"); #endif _dbus_assert (exact_match != NULL); + + *exact_match = FALSE; /* ensure always initialized */ + return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match); } @@ -386,6 +371,8 @@ ensure_subtree (DBusObjectTree *tree, return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL); } +static char *flatten_path (const char **path); + /** * Registers a new subtree in the global object tree. * @@ -394,14 +381,17 @@ ensure_subtree (DBusObjectTree *tree, * @param path NULL-terminated array of path elements giving path to subtree * @param vtable the vtable used to traverse this subtree * @param user_data user data to pass to methods in the vtable - * @returns #FALSE if not enough memory + * @param error address where an error can be returned + * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported */ dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, dbus_bool_t fallback, const char **path, const DBusObjectPathVTable *vtable, - void *user_data) + void *user_data, + DBusError *error) { DBusObjectSubtree *subtree; @@ -411,24 +401,33 @@ _dbus_object_tree_register (DBusObjectTree *tree, subtree = ensure_subtree (tree, path); if (subtree == NULL) - return FALSE; + { + _DBUS_SET_OOM (error); + return FALSE; + } -#ifndef DBUS_DISABLE_CHECKS if (subtree->message_function != NULL) { - _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n", - path[0] ? path[0] : "null"); + if (error != NULL) + { + char *complete_path = flatten_path (path); + + dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE, + "A handler is already registered for %s", + complete_path ? complete_path + : "(cannot represent path: out of memory!)"); + + dbus_free (complete_path); + } + return FALSE; } -#else - _dbus_assert (subtree->message_function == NULL); -#endif subtree->message_function = vtable->message_function; subtree->unregister_function = vtable->unregister_function; subtree->user_data = user_data; subtree->invoke_as_fallback = fallback != FALSE; - + return TRUE; } @@ -451,6 +450,9 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, _dbus_assert (path != NULL); + unregister_function = NULL; + user_data = NULL; + subtree = find_subtree (tree, path, &i); #ifndef DBUS_DISABLE_CHECKS @@ -459,7 +461,7 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", path[0] ? path[0] : "null", path[1] ? path[1] : "null"); - return; + goto unlock; } #else _dbus_assert (subtree != NULL); @@ -495,6 +497,7 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, } subtree = NULL; +unlock: connection = tree->connection; /* Unlock and call application code */ @@ -503,6 +506,7 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, #endif { _dbus_connection_ref_unlocked (connection); + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); _dbus_connection_unlock (connection); } @@ -629,13 +633,16 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, reply = NULL; if (!dbus_message_is_method_call (message, - DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE, + DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) { #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -647,7 +654,10 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } return DBUS_HANDLER_RESULT_NEED_MEMORY; } @@ -690,6 +700,8 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, if (tree->connection) #endif { + already_unlocked = TRUE; + if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL)) goto out; } @@ -702,7 +714,10 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, #endif { if (!already_unlocked) - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } } _dbus_string_free (&xml); @@ -747,7 +762,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } _dbus_verbose ("No memory to get decomposed path\n"); @@ -759,7 +777,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } _dbus_verbose ("No path field in message\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -822,7 +843,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } /* FIXME you could unregister the subtree in another thread * before we invoke the callback, and I can't figure out a @@ -859,7 +883,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } } while (list != NULL) @@ -875,6 +902,37 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, } /** + * Looks up the data passed to _dbus_object_tree_register() for a + * handler at the given path. + * + * @param tree the global object tree + * @param path NULL-terminated array of path elements giving path to subtree + * @returns the object's user_data or #NULL if none found + */ +void* +_dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, + const char **path) +{ + dbus_bool_t exact_match; + DBusObjectSubtree *subtree; + + _dbus_assert (tree != NULL); + _dbus_assert (path != NULL); + + /* Find the deepest path that covers the path in the message */ + subtree = find_handler (tree, (const char**) path, &exact_match); + + if ((subtree == NULL) || !exact_match) + { + _dbus_verbose ("%s: No object at specified path found\n", + _DBUS_FUNCTION_NAME); + return NULL; + } + + return subtree->user_data; +} + +/** * Allocates a subtree object. * * @param name name to duplicate. @@ -891,7 +949,7 @@ allocate_subtree_object (const char *name) len = strlen (name); - subtree = dbus_malloc (front_padding + (len + 1)); + subtree = dbus_malloc (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree))); if (subtree == NULL) return NULL; @@ -931,17 +989,12 @@ _dbus_object_subtree_new (const char *name, subtree->refcount.value = 1; subtree->subtrees = NULL; subtree->n_subtrees = 0; - subtree->subtrees_sorted = TRUE; + subtree->max_subtrees = 0; subtree->invoke_as_fallback = FALSE; return subtree; oom: - if (subtree) - { - dbus_free (subtree); - } - return NULL; } @@ -993,7 +1046,10 @@ _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } return result; } @@ -1098,10 +1154,6 @@ _dbus_decompose_path (const char* data, /** @} */ -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include - static char* flatten_path (const char **path) { @@ -1146,6 +1198,13 @@ flatten_path (const char **path) } +#ifdef DBUS_BUILD_TESTS + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include "dbus-test.h" +#include + typedef enum { STR_EQUAL, @@ -1168,9 +1227,9 @@ path_contains (const char **container, if (container[i] == NULL) return STR_PREFIX; /* container ran out, child continues; - * thus the container is a parent of the - * child. - */ + * thus the container is a parent of the + * child. + */ _dbus_assert (container[i] != NULL); _dbus_assert (child[i] != NULL); @@ -1179,8 +1238,8 @@ path_contains (const char **container, if (v != 0) return STR_DIFFERENT; /* they overlap until here and then are different, - * not overlapping - */ + * not overlapping + */ ++i; } @@ -1269,7 +1328,7 @@ do_register (DBusObjectTree *tree, { DBusObjectPathVTable vtable = { test_unregister_function, test_message_function, NULL }; - + tree_test_data[i].message_handled = FALSE; tree_test_data[i].handler_unregistered = FALSE; tree_test_data[i].handler_fallback = fallback; @@ -1277,9 +1336,13 @@ do_register (DBusObjectTree *tree, if (!_dbus_object_tree_register (tree, fallback, path, &vtable, - &tree_test_data[i])) + &tree_test_data[i], + NULL)) return FALSE; + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == + &tree_test_data[i]); + return TRUE; } @@ -1686,6 +1749,7 @@ object_tree_test_iteration (void *data) goto out; _dbus_object_tree_unregister_and_unlock (tree, path0); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (find_subtree (tree, path1, NULL)); @@ -1698,6 +1762,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path1); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1710,6 +1775,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1722,6 +1788,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path3); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1734,6 +1801,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path4); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1746,6 +1814,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path5); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1758,6 +1827,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path6); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1770,6 +1840,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path7); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1782,6 +1853,7 @@ object_tree_test_iteration (void *data) _dbus_assert (find_subtree (tree, path8, NULL)); _dbus_object_tree_unregister_and_unlock (tree, path8); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL); _dbus_assert (!find_subtree (tree, path0, NULL)); _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1872,4 +1944,6 @@ _dbus_object_tree_test (void) return TRUE; } +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + #endif /* DBUS_BUILD_TESTS */