diff options
-rw-r--r-- | src/lilv_internal.h | 1 | ||||
-rw-r--r-- | src/world.c | 64 | ||||
-rw-r--r-- | test/lilv_test.c | 8 |
3 files changed, 58 insertions, 15 deletions
diff --git a/src/lilv_internal.h b/src/lilv_internal.h index 89ae629..bdb88ed 100644 --- a/src/lilv_internal.h +++ b/src/lilv_internal.h @@ -156,6 +156,7 @@ struct LilvWorldImpl { LilvPluginClasses* plugin_classes; LilvSpec* specs; LilvPlugins* plugins; + LilvPlugins* zombies; LilvNodes* loaded_files; ZixTree* libs; struct { diff --git a/src/world.c b/src/world.c index 70a79d6..0710899 100644 --- a/src/world.c +++ b/src/world.c @@ -39,6 +39,7 @@ lilv_world_new(void) world->specs = NULL; world->plugin_classes = lilv_plugin_classes_new(); world->plugins = lilv_plugins_new(); + world->zombies = lilv_plugins_new(); world->loaded_files = zix_tree_new( false, lilv_resource_node_cmp, NULL, (ZixDestroyFunc)lilv_node_free); @@ -133,6 +134,13 @@ lilv_world_free(LilvWorld* world) zix_tree_free((ZixTree*)world->plugins); world->plugins = NULL; + LILV_FOREACH(plugins, i, world->zombies) { + const LilvPlugin* p = lilv_plugins_get(world->zombies, i); + lilv_plugin_free((LilvPlugin*)p); + } + zix_tree_free((ZixTree*)world->zombies); + world->zombies = NULL; + zix_tree_free((ZixTree*)world->loaded_files); world->loaded_files = NULL; @@ -322,23 +330,27 @@ lilv_lib_compare(const void* a, const void* b, void* user_data) } /** Get an element of a collection of any object with an LilvHeader by URI. */ -struct LilvHeader* -lilv_collection_get_by_uri(const ZixTree* const_seq, - const LilvNode* uri) +static ZixTreeIter* +lilv_collection_find_by_uri(const ZixTree* seq, const LilvNode* uri) { if (!lilv_node_is_uri(uri)) { return NULL; } - ZixTree* seq = (ZixTree*)const_seq; struct LilvHeader key = { NULL, (LilvNode*)uri }; ZixTreeIter* i = NULL; - ZixStatus st = zix_tree_find(seq, &key, &i); - if (!st) { - return (struct LilvHeader*)zix_tree_get(i); - } + const ZixStatus st = zix_tree_find(seq, &key, &i); - return NULL; + return st ? NULL : i; +} + +/** Get an element of a collection of any object with an LilvHeader by URI. */ +struct LilvHeader* +lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri) +{ + ZixTreeIter* const i = lilv_collection_find_by_uri(seq, uri); + + return i ? (struct LilvHeader*)zix_tree_get(i) : NULL; } static void @@ -377,8 +389,9 @@ lilv_world_add_plugin(LilvWorld* world, void* dynmanifest, const SordNode* bundle) { - LilvNode* plugin_uri = lilv_node_new_from_node(world, plugin_node); - LilvPlugin* plugin = (LilvPlugin*)lilv_plugins_get_by_uri( + LilvNode* plugin_uri = lilv_node_new_from_node(world, plugin_node); + ZixTreeIter* z = NULL; + LilvPlugin* plugin = (LilvPlugin*)lilv_plugins_get_by_uri( world->plugins, plugin_uri); if (plugin) { @@ -397,6 +410,13 @@ lilv_world_add_plugin(LilvWorld* world, lilv_node_free(plugin_uri); return; } + } else if ((z = lilv_collection_find_by_uri(world->zombies, plugin_uri))) { + // Plugin bundle has been re-loaded, move from zombies to plugins + plugin = zix_tree_get(z); + zix_tree_remove(world->zombies, z); + zix_tree_insert((ZixTree*)world->plugins, plugin, NULL); + lilv_node_free(plugin_uri); + plugin->loaded = false; } else { // Add new plugin to the world plugin = lilv_plugin_new( @@ -682,7 +702,7 @@ lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri) return 0; } - // Unload any files, including manifest.ttl + // Find all loaded files that are inside the bundle LilvNodes* files = lilv_nodes_new(); LILV_FOREACH(nodes, i, world->loaded_files) { const LilvNode* file = lilv_nodes_get(world->loaded_files, i); @@ -695,6 +715,7 @@ lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri) } } + // Unload all loaded files in the bundle LILV_FOREACH(nodes, i, files) { const LilvNode* file = lilv_nodes_get(world->plugins, i); lilv_world_unload_file(world, file); @@ -702,6 +723,25 @@ lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri) lilv_nodes_free(files); + /* Remove any plugins in the bundle from the plugin list. Since the + application may still have a pointer to the LilvPlugin, it can not be + destroyed here. Instead, we move it to the zombie plugin list, so it + will not be in the list returned by lilv_world_get_all_plugins() but can + still be used. + */ + ZixTreeIter* i = zix_tree_begin(world->plugins); + while (i != zix_tree_end(world->plugins)) { + LilvPlugin* p = (LilvPlugin*)zix_tree_get(i); + ZixTreeIter* next = zix_tree_iter_next(i); + + if (lilv_node_equals(lilv_plugin_get_bundle_uri(p), bundle_uri)) { + zix_tree_remove(world->plugins, i); + zix_tree_insert(world->zombies, p, NULL); + } + + i = next; + } + // Drop everything in bundle graph return lilv_world_drop_graph(world, bundle_uri); } diff --git a/test/lilv_test.c b/test/lilv_test.c index 7b6d14a..64021f8 100644 --- a/test/lilv_test.c +++ b/test/lilv_test.c @@ -1982,14 +1982,16 @@ test_reload_bundle(void) ":plug a lv2:Plugin ; " PLUGIN_NAME("Second name") " ."); + // Check that plugin is no longer in the world's plugin list + TEST_ASSERT(lilv_plugins_size(plugins) == 0); + // Load new bundle lilv_world_load_bundle(world, bundle_uri); - // TODO: Mechanism to actually remove plugin from world list - - // Check that plugin is present again + // Check that plugin is present again and is the same LilvPlugin const LilvPlugin* plug2 = lilv_plugins_get_by_uri(plugins, plugin_uri_value); TEST_ASSERT(plug2); + TEST_ASSERT(plug2 == plug); // Check that plugin now has new name LilvNode* name2 = lilv_plugin_get_name(plug2); |