From 646787a6bcdcdb4070742f86a66111d0d26d20fb Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Tue, 29 Jan 2013 17:26:42 -0500 Subject: [PATCH] Fix parent removal FIXME in dbus/dbus-object-tree.c Modify _dbus_object_tree_unregister_and_unlock to free newly-childless unregistered nodes. Add unregister_function and user_data arguments to find_subtree_recurse. Use them to store the node-to-unregister's unregister function and user data. Also add free_path argument and remove_subtree helper function. On the recursive return path, call remove_subtree until the current node is registered or has children, at which point set free_path to FALSE to stop attempting further removals. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=60176 --- dbus/dbus-object-tree.c | 611 +++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 540 insertions(+), 71 deletions(-) diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 172c9d9..7ecc116 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -154,17 +154,54 @@ _dbus_object_tree_unref (DBusObjectTree *tree) } } +static dbus_bool_t +remove_subtree (DBusObjectSubtree *subtree, + int index_in_parent) +{ + _dbus_assert (subtree != NULL); + _dbus_assert (subtree->parent != NULL); + _dbus_assert (index_in_parent >= 0); + _dbus_assert (subtree->parent->subtrees[index_in_parent] == subtree); + + /* If subtree is childless and is not a registered path, remove it from the + tree then free it */ + if (subtree->n_subtrees == 0 && subtree->message_function == NULL) + { + /* Assumes a 0-byte memmove is OK */ + memmove (&subtree->parent->subtrees[index_in_parent], + &subtree->parent->subtrees[index_in_parent + 1], + (subtree->parent->n_subtrees - index_in_parent - 1) * + sizeof (subtree->parent->subtrees[0])); + subtree->parent->n_subtrees -= 1; + + subtree->parent = NULL; + + _dbus_object_subtree_unref (subtree); + + /* Continue attempting to remove subtree's ancestors in case they have + become childless */ + return TRUE; + } + else + /* subtree was not removed from the tree so do not attempt to remove any of + its ancestors */ + return FALSE; +} + /** Set to 1 to get a bunch of debug spew about finding the * subtree nodes */ #define VERBOSE_FIND 0 static DBusObjectSubtree* -find_subtree_recurse (DBusObjectSubtree *subtree, - const char **path, - dbus_bool_t create_if_not_found, - int *index_in_parent, - dbus_bool_t *exact_match) +find_subtree_recurse (DBusObjectSubtree *subtree, + const char **path, + dbus_bool_t create_if_not_found, + int *index_in_parent, + dbus_bool_t *exact_match, + dbus_bool_t *free_path, + DBusObjectPathUnregisterFunction *unregister_function, + void **user_data) { int i, j; dbus_bool_t return_deepest_match; @@ -172,6 +209,12 @@ find_subtree_recurse (DBusObjectSubtree *subtree, return_deepest_match = exact_match != NULL; _dbus_assert (!(return_deepest_match && create_if_not_found)); + _dbus_assert (!(free_path != NULL && !*free_path)); + _dbus_assert (!(free_path != NULL && create_if_not_found)); + _dbus_assert (!(free_path != NULL && index_in_parent != NULL)); + _dbus_assert (!(free_path != NULL && exact_match != NULL)); + _dbus_assert (!(free_path != NULL && unregister_function == NULL)); + _dbus_assert (!(free_path != NULL && user_data == NULL)); if (path[0] == NULL) { @@ -181,6 +224,33 @@ find_subtree_recurse (DBusObjectSubtree *subtree, #endif if (exact_match != NULL) *exact_match = TRUE; + if (free_path != NULL) + { + /* Confirm this subtree is registered */ + if (subtree->message_function != NULL) + { + subtree->message_function = NULL; + + *unregister_function = subtree->unregister_function; + *user_data = subtree->user_data; + + subtree->unregister_function = NULL; + subtree->user_data = NULL; + + return NULL; + } + else + { +#ifndef DBUS_DISABLE_CHECKS + /* Do not warn about root tree */ + if (subtree->parent && subtree->n_subtrees == 0) + _dbus_warn ("Failed to free unregistered childless subtree %s," + " which should not exist\n", subtree->name); +#else + _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0); +#endif + } + } return subtree; } @@ -206,6 +276,8 @@ find_subtree_recurse (DBusObjectSubtree *subtree, if (v == 0) { + DBusObjectSubtree *next; + if (index_in_parent) { #if VERBOSE_FIND @@ -216,11 +288,11 @@ find_subtree_recurse (DBusObjectSubtree *subtree, if (return_deepest_match) { - DBusObjectSubtree *next; - next = find_subtree_recurse (subtree->subtrees[k], &path[1], create_if_not_found, - index_in_parent, exact_match); + index_in_parent, exact_match, + free_path, unregister_function, + user_data); if (next == NULL && subtree->invoke_as_fallback) { @@ -232,13 +304,18 @@ find_subtree_recurse (DBusObjectSubtree *subtree, *exact_match = FALSE; return subtree; } - else - return next; } else - return find_subtree_recurse (subtree->subtrees[k], - &path[1], create_if_not_found, - index_in_parent, exact_match); + { + next = find_subtree_recurse (subtree->subtrees[k], + &path[1], create_if_not_found, + index_in_parent, exact_match, + free_path, unregister_function, + user_data); + if (free_path != NULL && next == NULL && *free_path) + *free_path = remove_subtree (subtree->subtrees[k], k); + } + return next; } else if (v < 0) { @@ -309,43 +386,28 @@ find_subtree_recurse (DBusObjectSubtree *subtree, return find_subtree_recurse (child, &path[1], create_if_not_found, - index_in_parent, exact_match); + index_in_parent, exact_match, + free_path, unregister_function, + user_data); } else { if (exact_match != NULL) *exact_match = FALSE; - return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; + return ((return_deepest_match && subtree->invoke_as_fallback) + || free_path != NULL) ? subtree : NULL; } } static DBusObjectSubtree* -find_subtree (DBusObjectTree *tree, - const char **path, - int *index_in_parent) -{ - DBusObjectSubtree *subtree; - -#if VERBOSE_FIND - _dbus_verbose ("Looking for exact registered subtree\n"); -#endif - - subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL); - - if (subtree && subtree->message_function == NULL) - return NULL; - else - return subtree; -} - -static DBusObjectSubtree* lookup_subtree (DBusObjectTree *tree, const char **path) { #if VERBOSE_FIND _dbus_verbose ("Looking for subtree\n"); #endif - return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); + return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL, + NULL, NULL, NULL); } static DBusObjectSubtree* @@ -360,7 +422,8 @@ find_handler (DBusObjectTree *tree, *exact_match = FALSE; /* ensure always initialized */ - return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match); + return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match, + NULL, NULL, NULL); } static DBusObjectSubtree* @@ -370,7 +433,8 @@ ensure_subtree (DBusObjectTree *tree, #if VERBOSE_FIND _dbus_verbose ("Ensuring subtree\n"); #endif - return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL); + return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL, + NULL, NULL, NULL); } static char *flatten_path (const char **path); @@ -444,21 +508,27 @@ void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, const char **path) { - int i; DBusObjectSubtree *subtree; + dbus_bool_t free_path; DBusObjectPathUnregisterFunction unregister_function; void *user_data; DBusConnection *connection; _dbus_assert (path != NULL); + _dbus_assert (tree != NULL && tree->root != NULL); + free_path = TRUE; unregister_function = NULL; user_data = NULL; - subtree = find_subtree (tree, path, &i); + /* When free_path is set, find_subtree_recurse returns NULL on success and + the deepest-match subtree on failure */ + subtree = find_subtree_recurse (tree->root, path, FALSE, + NULL, NULL, &free_path, + &unregister_function, &user_data); #ifndef DBUS_DISABLE_CHECKS - if (subtree == NULL) + if (subtree != NULL) { _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", path[0] ? path[0] : "null", @@ -466,39 +536,9 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, goto unlock; } #else - _dbus_assert (subtree != NULL); + _dbus_assert (subtree == NULL); #endif - _dbus_assert (subtree->parent == NULL || - (i >= 0 && subtree->parent->subtrees[i] == subtree)); - - subtree->message_function = NULL; - - unregister_function = subtree->unregister_function; - user_data = subtree->user_data; - - subtree->unregister_function = NULL; - subtree->user_data = NULL; - - /* If we have no subtrees of our own, remove from - * our parent (FIXME could also be more aggressive - * and remove our parent if it becomes empty) - */ - if (subtree->parent && subtree->n_subtrees == 0) - { - /* assumes a 0-byte memmove is OK */ - memmove (&subtree->parent->subtrees[i], - &subtree->parent->subtrees[i+1], - (subtree->parent->n_subtrees - i - 1) * - sizeof (subtree->parent->subtrees[0])); - subtree->parent->n_subtrees -= 1; - - subtree->parent = NULL; - - _dbus_object_subtree_unref (subtree); - } - subtree = NULL; - unlock: connection = tree->connection; @@ -1507,6 +1547,39 @@ run_decompose_tests (void) return TRUE; } +static DBusObjectSubtree* +find_subtree (DBusObjectTree *tree, + const char **path, + int *index_in_parent) +{ + DBusObjectSubtree *subtree; + +#if VERBOSE_FIND + _dbus_verbose ("Looking for exact registered subtree\n"); +#endif + + subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL, + NULL, NULL, NULL); + + if (subtree && subtree->message_function == NULL) + return NULL; + else + return subtree; +} + +static DBusObjectSubtree* +find_subtree_unregistered (DBusObjectTree *tree, + const char **path, + int *index_in_parent) +{ +#if VERBOSE_FIND + _dbus_verbose ("Looking for exact subtree, registered or unregistered\n"); +#endif + + return find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL, + NULL, NULL, NULL); +} + static dbus_bool_t object_tree_test_iteration (void *data) { @@ -1519,8 +1592,19 @@ object_tree_test_iteration (void *data) const char *path6[] = { "blah", "boof", NULL }; const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; const char *path8[] = { "childless", NULL }; + const char *path9[] = { "blah", "a", NULL }; + const char *path10[] = { "blah", "b", NULL }; + const char *path11[] = { "blah", "c", NULL }; + const char *path12[] = { "blah", "a", "d", NULL }; + const char *path13[] = { "blah", "b", "d", NULL }; + const char *path14[] = { "blah", "c", "d", NULL }; DBusObjectTree *tree; TreeTestData tree_test_data[9]; + DBusObjectPathVTable test_vtable = { NULL, test_message_function, NULL }; +#if 0 + DBusObjectSubtree *subtree; +#endif + int i; dbus_bool_t exact_match; @@ -1889,6 +1973,391 @@ object_tree_test_iteration (void *data) ++i; } + /* Test that empty parents are freed */ + if (!do_register (tree, path2, TRUE, 2, tree_test_data)) + goto out; + + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + /* Test that unregistered parents cannot be freed out from under their + children */ + if (!do_register (tree, path2, TRUE, 2, tree_test_data)) + goto out; + + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + +#if 0 + /* This triggers the "Attempted to unregister path ..." warning message */ + _dbus_object_tree_unregister_and_unlock (tree, path1); +#endif + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + /* Test that registered parents cannot be freed out from under their + children, and that if they are unregistered before their children, they + are still freed when their children are unregistered */ + if (!do_register (tree, path1, TRUE, 1, tree_test_data)) + goto out; + if (!do_register (tree, path2, TRUE, 2, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path1); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + /* Test with NULL unregister_function and user_data */ + if (!_dbus_object_tree_register (tree, TRUE, path2, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + /* Test freeing a long path */ + if (!do_register (tree, path3, TRUE, 3, tree_test_data)) + goto out; + + _dbus_object_tree_unregister_and_unlock (tree, path3); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + /* Test freeing multiple children from the same path */ + if (!do_register (tree, path3, TRUE, 3, tree_test_data)) + goto out; + if (!do_register (tree, path4, TRUE, 4, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path3); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path4, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path4); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + + /* Test subtree removal */ + if (!_dbus_object_tree_register (tree, TRUE, path12, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path12, NULL)); + + if (!_dbus_object_tree_register (tree, TRUE, path13, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path13, NULL)); + + if (!_dbus_object_tree_register (tree, TRUE, path14, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path14, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path12); + + _dbus_assert (!find_subtree_unregistered (tree, path12, NULL)); + _dbus_assert (find_subtree (tree, path13, NULL)); + _dbus_assert (find_subtree (tree, path14, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path9, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + if (!_dbus_object_tree_register (tree, TRUE, path12, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path12, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path13); + + _dbus_assert (find_subtree (tree, path12, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path13, NULL)); + _dbus_assert (find_subtree (tree, path14, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path10, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + if (!_dbus_object_tree_register (tree, TRUE, path13, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path13, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path14); + + _dbus_assert (find_subtree (tree, path12, NULL)); + _dbus_assert (find_subtree (tree, path13, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path14, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path11, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path12); + + _dbus_assert (!find_subtree_unregistered (tree, path12, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path9, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path13); + + _dbus_assert (!find_subtree_unregistered (tree, path13, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path10, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path5, NULL)); + + /* Repeat free testing with non-fallback paths */ + + if (!do_register (tree, path2, FALSE, 2, tree_test_data)) + goto out; + + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + if (!do_register (tree, path2, FALSE, 2, tree_test_data)) + goto out; + + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + +#if 0 + /* This triggers the "Attempted to unregister path ..." warning message */ + _dbus_object_tree_unregister_and_unlock (tree, path1); +#endif + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + if (!do_register (tree, path1, FALSE, 1, tree_test_data)) + goto out; + if (!do_register (tree, path2, FALSE, 2, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path1); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + if (!_dbus_object_tree_register (tree, FALSE, path2, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + if (!do_register (tree, path3, FALSE, 3, tree_test_data)) + goto out; + + _dbus_object_tree_unregister_and_unlock (tree, path3); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path0, NULL)); + + if (!do_register (tree, path3, FALSE, 3, tree_test_data)) + goto out; + if (!do_register (tree, path4, FALSE, 4, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path3); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path4, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path4); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path3, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path2, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); + + if (!_dbus_object_tree_register (tree, FALSE, path12, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path12, NULL)); + + if (!_dbus_object_tree_register (tree, FALSE, path13, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path13, NULL)); + + if (!_dbus_object_tree_register (tree, FALSE, path14, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path14, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path12); + + _dbus_assert (!find_subtree_unregistered (tree, path12, NULL)); + _dbus_assert (find_subtree (tree, path13, NULL)); + _dbus_assert (find_subtree (tree, path14, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path9, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + if (!_dbus_object_tree_register (tree, FALSE, path12, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path12, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path13); + + _dbus_assert (find_subtree (tree, path12, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path13, NULL)); + _dbus_assert (find_subtree (tree, path14, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path10, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + if (!_dbus_object_tree_register (tree, FALSE, path13, + &test_vtable, + NULL, + NULL)) + goto out; + + _dbus_assert (find_subtree (tree, path13, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path14); + + _dbus_assert (find_subtree (tree, path12, NULL)); + _dbus_assert (find_subtree (tree, path13, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path14, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path11, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path12); + + _dbus_assert (!find_subtree_unregistered (tree, path12, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path9, NULL)); + _dbus_assert (find_subtree_unregistered (tree, path5, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path13); + + _dbus_assert (!find_subtree_unregistered (tree, path13, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path10, NULL)); + _dbus_assert (!find_subtree_unregistered (tree, path5, NULL)); + +#if 0 + /* Trigger unregistered childless subtree warning message */ + if (!ensure_subtree (tree, path1)) + goto out; + + _dbus_assert (find_subtree_unregistered (tree, path1, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path1); + subtree = find_subtree_unregistered (tree, path1, &i); + _dbus_assert (subtree); + _dbus_assert (i == 0); + remove_subtree (subtree, i); + _dbus_assert (!find_subtree_unregistered (tree, path1, NULL)); +#endif + +#if 0 + /* Test attempting to unregister non-existent paths. These trigger + "Attempted to unregister path ..." warning messages */ + _dbus_object_tree_unregister_and_unlock (tree, path0); + _dbus_object_tree_unregister_and_unlock (tree, path1); + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_object_tree_unregister_and_unlock (tree, path3); + _dbus_object_tree_unregister_and_unlock (tree, path4); +#endif + /* Register it all again, and test dispatch */ if (!do_register (tree, path0, TRUE, 0, tree_test_data)) -- 1.6.0.6