You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pe...@apache.org on 2023/06/02 15:04:01 UTC

[celix] branch feature/556-osgi-uninstall updated (2e24b1f6 -> fc851349)

This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a change to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git


    from 2e24b1f6 Avoid unnecessary disk write with an extra disk read.
     new 98f187b9 Fix race condition introduced by celix_framework_installBundleInternal.
     new 063593cd Use read-write-lock to protect bundle state transition.
     new 73dac42f Implement OSGi uninstall, and make install/uninstall thread-safe.
     new 6008b3d7 Add support for bundle unload.
     new 27383f6c Update all bundle activator to use async service registration.
     new ea6a979c Add useActiveBundles.
     new cccf30aa Add full support of bundle update.
     add 53cf5860 Merge pull request #564 from apache/feature/556-osgi-uninstall
     add 12a8f42b Correct build errors on OSX, issue #567
     add 2efed0a8 Merge pull request #568 from schorg/master
     new fc851349 Merge branch 'master' into feature/556-osgi-uninstall-2

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 bundles/deployment_admin/src/ioapi.c               |   3 +-
 bundles/deployment_admin/src/miniunz.c             |  15 +-
 bundles/http_admin/gtest/src/sut_activator.c       |   8 +-
 bundles/http_admin/http_admin/src/http_admin.c     |   2 +-
 .../pubsub/integration/gtest/loopback_activator.c  |   2 +-
 bundles/pubsub/integration/gtest/tst_activator.c   |   6 +-
 .../integration/gtest/tst_endpoint_activator.c     |   4 +-
 .../pubsub/pubsub_admin_tcp/src/psa_activator.c    |  12 +-
 .../pubsub/pubsub_admin_udp_mc/src/psa_activator.c |   4 +-
 .../pubsub_admin_websocket/src/psa_activator.c     |   4 +-
 .../src/pubsub_websocket_topic_receiver.c          |   4 +-
 .../src/pubsub_websocket_topic_sender.c            |   4 +-
 .../pubsub/pubsub_admin_zmq/src/psa_activator.c    |   4 +-
 .../pubsub/pubsub_discovery/src/psd_activator.c    |   4 +-
 .../src/ps_wire_protocol_activator.c               |   2 +-
 .../src/ps_wire_v2_protocol_activator.c            |   2 +-
 .../src/ps_avrobin_serializer_activator.c          |   2 +-
 .../src/ps_json_serializer_activator.c             |   2 +-
 .../pubsub_topology_manager/src/pstm_activator.c   |   4 +-
 .../src/pubsub_topology_manager.c                  |   2 +-
 .../calculator_service/src/calculator_activator.c  |   2 +-
 .../src/calculator_shell_activator.c               |   6 +-
 .../src/remote_example_activator.c                 |   2 +-
 .../src/remote_example_impl.c                      |   2 +-
 .../gtest/src/tst_activator.c                      |   2 +-
 .../src/remote_service_admin_activator.c           |   2 +-
 bundles/shell/shell/CMakeLists.txt                 |   1 +
 bundles/shell/shell/gtest/src/ShellTestSuite.cc    |   3 +
 bundles/shell/shell/src/query_command.c            |   3 +-
 bundles/shell/shell/src/std_commands.c             |   9 +-
 bundles/shell/shell/src/std_commands.h             |   2 +
 .../shell/shell/src/unload_command.c               |  17 +-
 .../shell_wui/src/shell_wui_bundle_activator.c     |   2 +-
 documents/building/README.md                       |   2 +-
 .../src/http_example_bundle_activator.c            |   2 +-
 .../src/simple_provider_example.c                  |   2 +-
 .../track_tracker_example/src/activator.c          |   2 +-
 libs/framework/gtest/src/BundleArchiveTestSuite.cc |  27 +-
 .../BundleArchiveWithErrorInjectionTestSuite.cc    |  42 +--
 .../src/CelixBundleContextBundlesTestSuite.cc      | 143 +++++++-
 .../framework/gtest/src/CelixFrameworkTestSuite.cc |  27 +-
 libs/framework/include/celix_bundle.h              |   2 +
 libs/framework/include/celix_bundle_context.h      |  30 +-
 libs/framework/include/celix_framework.h           |  95 ++++-
 libs/framework/src/bundle.c                        |  30 +-
 libs/framework/src/bundle_archive.c                |  39 +--
 libs/framework/src/bundle_context.c                |  12 +-
 libs/framework/src/bundle_revision.c               |  27 +-
 libs/framework/src/dm_dependency_manager_impl.c    |  27 +-
 libs/framework/src/framework.c                     | 382 +++++++++++----------
 .../src/framework_bundle_lifecycle_handler.c       |  20 +-
 libs/framework/src/framework_private.h             |  18 +-
 52 files changed, 637 insertions(+), 435 deletions(-)
 copy libs/error_injector/unistd/include/unistd_ei.h => bundles/shell/shell/src/unload_command.c (75%)


[celix] 06/08: Add useActiveBundles.

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit ea6a979c451b19d2b4ac8d123c7dedf79f725847
Author: PengZheng <ho...@gmail.com>
AuthorDate: Fri Jun 2 14:31:18 2023 +0800

    Add useActiveBundles.
    
    It fixes thread-safety issue in dependency manager (see #561), a null string logging issue in pubsub's topology manager, and a potential crash in query_command.c.
---
 .../src/pubsub_topology_manager.c                  |  2 +-
 bundles/shell/shell/src/query_command.c            |  3 +-
 libs/framework/include/celix_bundle.h              |  2 ++
 libs/framework/include/celix_framework.h           | 41 +++++++++++++++++++---
 libs/framework/src/dm_dependency_manager_impl.c    | 27 ++++++--------
 libs/framework/src/framework.c                     | 22 +++++++++---
 6 files changed, 69 insertions(+), 28 deletions(-)

diff --git a/bundles/pubsub/pubsub_topology_manager/src/pubsub_topology_manager.c b/bundles/pubsub/pubsub_topology_manager/src/pubsub_topology_manager.c
index a204668b..c73cc587 100644
--- a/bundles/pubsub/pubsub_topology_manager/src/pubsub_topology_manager.c
+++ b/bundles/pubsub/pubsub_topology_manager/src/pubsub_topology_manager.c
@@ -1344,7 +1344,7 @@ static celix_status_t pubsub_topologyManager_metrics(pubsub_topology_manager_t *
                 if (sm->msgMetrics[j].nrOfMessagesSend == 0 && sm->msgMetrics[j].nrOfMessagesSendFailed == 0 && sm->msgMetrics[j].nrOfSerializationErrors == 0) {
                     continue;
                 }
-                const char *bndName = NULL;
+                const char *bndName = "inactive";
                 celix_bundleContext_useBundle(manager->context, sm->msgMetrics->bndId, &bndName, fetchBundleName);
                 fprintf(os, "   |- Message '%s' from bundle '%s' (%li):\n", sm->msgMetrics[j].typeFqn, bndName, sm->msgMetrics->bndId);
                 fprintf(os, "      |- msg type = 0x%X\n", sm->msgMetrics[j].typeId);
diff --git a/bundles/shell/shell/src/query_command.c b/bundles/shell/shell/src/query_command.c
index ff7f7a8a..490513b9 100644
--- a/bundles/shell/shell/src/query_command.c
+++ b/bundles/shell/shell/src/query_command.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include "celix_framework.h"
 #include "celix_shell_constants.h"
 #include "celix_bundle_context.h"
 #include "std_commands.h"
@@ -129,7 +130,7 @@ static void queryCommand_callback(void *handle, const celix_bundle_t *bnd) {
 
 
 static void queryCommand_listServicesForBundle(celix_bundle_context_t *ctx, long bndId, struct bundle_callback_data *data, const struct query_options *opts, FILE *sout, FILE *serr) {
-    bool called = celix_bundleContext_useBundle(ctx, bndId, data, queryCommand_callback);
+    bool called = celix_framework_useBundle(celix_bundleContext_getFramework(ctx), true, bndId, data, queryCommand_callback);
     if (!called) {
         fprintf(serr, "Bundle %li not installed!", bndId);
     }
diff --git a/libs/framework/include/celix_bundle.h b/libs/framework/include/celix_bundle.h
index 63121eda..fb348709 100644
--- a/libs/framework/include/celix_bundle.h
+++ b/libs/framework/include/celix_bundle.h
@@ -177,6 +177,8 @@ typedef struct celix_bundle_service_tracker_list_entry {
 /**
  * Returns a array list of service tracker info entries for this bundle.
  *
+ * @warning It requires a valid bundle context. Calling it for an inactive bundle will lead to crash.
+ *
  * @param ctx       The bundle context
  * @param bndId     The bundle id for which the services should be listed
  * @return          A celix array list with celix_bundle_service_tracker_list_entry_t*. Caller is owner of the celix array.
diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h
index 2bfbd114..5f3d338a 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -74,22 +74,51 @@ CELIX_FRAMEWORK_EXPORT celix_bundle_context_t* celix_framework_getFrameworkConte
 CELIX_FRAMEWORK_EXPORT celix_bundle_t* celix_framework_getFrameworkBundle(const celix_framework_t *fw);
 
 /**
- * @brief * @brief Use the currently installed bundles.
+ * @brief Use the currently installed bundles.
  * The provided callback will be called for all the currently installed bundles.
  *
- * @param ctx                       The bundle context.
+ * @warning It is dangerous to use the provided bundle's context from the callback, since it may be invalid for an inactive bundle.
+ *
+ * @param fw                        The framework.
  * @param includeFrameworkBundle    If true the callback will also be triggered for the framework bundle.
  * @param callbackHandle            The data pointer, which will be used in the callbacks
  * @param use                       The callback which will be called for the currently installed bundles.
  *                                  The bundle pointers are only guaranteed to be valid during the callback.
  * @return                          The number of times the use callback is called.
  */
-CELIX_FRAMEWORK_EXPORT size_t celix_framework_useBundles(celix_framework_t *fw, bool includeFrameworkBundle, void *callbackHandle, void(*use)(void *handle, const celix_bundle_t *bnd));
+CELIX_FRAMEWORK_EXPORT size_t celix_framework_useBundles(celix_framework_t* fw,
+                                                         bool includeFrameworkBundle,
+                                                         void* callbackHandle,
+                                                         void (*use)(void* handle, const celix_bundle_t* bnd));
+
+/**
+ * @brief Use the currently active bundles.
+ * The provided callback will be called for all the currently active bundles.
+ *
+ * @warning Calling synchronous bundle-state changing functions (e.g. celix_bundleContext_stopBundle) from the callback
+ * will lead to deadlocks.
+ *
+ * @param fw                        The framework.
+ * @param includeFrameworkBundle    If true the callback will also be triggered for the framework bundle.
+ * @param callbackHandle            The data pointer, which will be used in the callbacks
+ * @param use                       The callback which will be called for the currently active bundles.
+ *                                  The bundle state is guaranteed to be active during the callback.
+ * @return                          The number of times the use callback is called.
+ */
+CELIX_FRAMEWORK_EXPORT size_t celix_framework_useActiveBundles(celix_framework_t* fw,
+                                                               bool includeFrameworkBundle,
+                                                               void* callbackHandle,
+                                                               void (*use)(void* handle, const celix_bundle_t* bnd));
 
 /**
  * @brief Use the bundle with the provided bundle id
  * The provided callback will be called if the bundle is found.
  *
+ * @warning Calling synchronous bundle-state changing functions (e.g. celix_bundleContext_stopBundle) with onlyActive=true
+ * from the callback will lead to deadlocks. Using a bundle's context, e.g. calling celix_bundle_listServiceTrackers,
+ * with onlyActive=false from the callback is generally dangerous. However, in some cases, the target bundle's context is guaranteed to be valid,
+ * e.g. the bundle is providing a service protected by a service tracker.
+ *
  * @param fw                The framework.
  * @param onlyActive        If true only starting and active bundles will trigger the callback.
  * @param bundleId          The bundle id.
@@ -98,7 +127,11 @@ CELIX_FRAMEWORK_EXPORT size_t celix_framework_useBundles(celix_framework_t *fw,
  *                          The bundle pointers are only guaranteed to be valid during the callback.
  * @return                  Returns true if the bundle is found and the callback is called.
  */
-CELIX_FRAMEWORK_EXPORT bool celix_framework_useBundle(celix_framework_t *fw, bool onlyActive, long bndId, void *callbackHandle, void(*use)(void *handle, const celix_bundle_t *bnd));
+CELIX_FRAMEWORK_EXPORT bool celix_framework_useBundle(celix_framework_t* fw,
+                                                      bool onlyActive,
+                                                      long bndId,
+                                                      void* callbackHandle,
+                                                      void (*use)(void* handle, const celix_bundle_t* bnd));
 
 /**
  * @brief Check whether a bundle is installed.
diff --git a/libs/framework/src/dm_dependency_manager_impl.c b/libs/framework/src/dm_dependency_manager_impl.c
index 21a77d45..006f97d2 100644
--- a/libs/framework/src/dm_dependency_manager_impl.c
+++ b/libs/framework/src/dm_dependency_manager_impl.c
@@ -182,10 +182,6 @@ celix_status_t celix_dependencyManager_removeAllComponentsAsync(celix_dependency
 static void celix_dm_getInfoCallback(void *handle, const celix_bundle_t *bnd) {
     celix_dependency_manager_info_t **out = handle;
 
-    if (celix_bundle_getState(bnd) != CELIX_BUNDLE_STATE_ACTIVE) {
-        return;
-    }
-
     celix_bundle_context_t *context = NULL;
     bundle_getContext((celix_bundle_t*)bnd, &context);
     celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(context);
@@ -211,18 +207,15 @@ static void celix_dm_getInfoCallback(void *handle, const celix_bundle_t *bnd) {
 }
 
 celix_dependency_manager_info_t* celix_dependencyManager_createInfo(celix_dependency_manager_t *manager, long bndId) {
-	celix_dependency_manager_info_t *info = NULL;
-	celix_bundleContext_useBundle(manager->ctx, bndId, &info, celix_dm_getInfoCallback);
-	return info;
+    celix_dependency_manager_info_t* info = NULL;
+    celix_framework_useBundle(
+        celix_bundleContext_getFramework(manager->ctx), true /*onlyActive*/, bndId, &info, celix_dm_getInfoCallback);
+    return info;
 }
 
 static void celix_dm_getInfosCallback(void* handle, const celix_bundle_t* bnd) {
     celix_array_list_t* infos = handle;
 
-    if (celix_bundle_getState(bnd) != CELIX_BUNDLE_STATE_ACTIVE) {
-        return;
-    }
-
     celix_bundle_context_t* context = NULL;
     bundle_getContext((celix_bundle_t*)bnd, &context);
     celix_dependency_manager_t* mng = celix_bundleContext_getDependencyManager(context);
@@ -253,14 +246,14 @@ static void celix_dependencyManager_destroyInfoCallback(void *data, celix_array_
 }
 
 celix_array_list_t * celix_dependencyManager_createInfos(celix_dependency_manager_t* manager) {
-	celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
-	opts.removedCallbackData = manager;
-	opts.removedCallback = celix_dependencyManager_destroyInfoCallback;
+    celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
+    opts.removedCallbackData = manager;
+    opts.removedCallback = celix_dependencyManager_destroyInfoCallback;
     celix_array_list_t* infos = celix_arrayList_createWithOptions(&opts);
 
-	celix_framework_t* fw = celix_bundleContext_getFramework(manager->ctx);
-	celix_framework_useBundles(fw, true, infos, celix_dm_getInfosCallback);
-	return infos;
+    celix_framework_t* fw = celix_bundleContext_getFramework(manager->ctx);
+    celix_framework_useActiveBundles(fw, true, infos, celix_dm_getInfosCallback);
+    return infos;
 }
 
 static void celix_dm_allComponentsActiveCallback(void *handle, const celix_bundle_t *bnd) {
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 8671abac..0c6c31b8 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -1513,8 +1513,7 @@ static celix_status_t frameworkActivator_destroy(void * userData, bundle_context
  **********************************************************************************************************************
  **********************************************************************************************************************/
 
-
-size_t celix_framework_useBundles(framework_t *fw, bool includeFrameworkBundle, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)) {
+static size_t celix_framework_useBundlesInternal(framework_t *fw, bool includeFrameworkBundle, bool onlyActive, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)) {
     size_t count = 0;
     celix_array_list_t *bundleIds = celix_arrayList_create();
 
@@ -1534,7 +1533,7 @@ size_t celix_framework_useBundles(framework_t *fw, bool includeFrameworkBundle,
     size = celix_arrayList_size(bundleIds);
     for (int i = 0; i < size; ++i) {
         long bndId = celix_arrayList_getLong(bundleIds, i);
-        bool called = celix_framework_useBundle(fw, false, bndId, callbackHandle, use);
+        bool called = celix_framework_useBundle(fw, onlyActive, bndId, callbackHandle, use);
         if (called) {
             ++count;
         }
@@ -1542,6 +1541,15 @@ size_t celix_framework_useBundles(framework_t *fw, bool includeFrameworkBundle,
 
     celix_arrayList_destroy(bundleIds);
     return count;
+
+}
+
+size_t celix_framework_useBundles(framework_t *fw, bool includeFrameworkBundle, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)) {
+    return celix_framework_useBundlesInternal(fw, includeFrameworkBundle, false, callbackHandle, use);
+}
+
+size_t celix_framework_useActiveBundles(framework_t *fw, bool includeFrameworkBundle, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)) {
+    return celix_framework_useBundlesInternal(fw, includeFrameworkBundle, true, callbackHandle, use);
 }
 
 bool celix_framework_useBundle(framework_t *fw, bool onlyActive, long bundleId, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)) {
@@ -1551,7 +1559,9 @@ bool celix_framework_useBundle(framework_t *fw, bool onlyActive, long bundleId,
                                                                                                               bundleId);
 
         if (entry != NULL) {
-            celixThreadRwlock_readLock(&entry->fsmMutex);
+            if (onlyActive) {
+                celixThreadRwlock_readLock(&entry->fsmMutex);
+            }
             celix_bundle_state_e bndState = celix_bundle_getState(entry->bnd);
             if (onlyActive && (bndState == CELIX_BUNDLE_STATE_ACTIVE || bndState == CELIX_BUNDLE_STATE_STARTING)) {
                 use(callbackHandle, entry->bnd);
@@ -1560,7 +1570,9 @@ bool celix_framework_useBundle(framework_t *fw, bool onlyActive, long bundleId,
                 use(callbackHandle, entry->bnd);
                 called = true;
             }
-            celixThreadRwlock_unlock(&entry->fsmMutex);
+            if (onlyActive) {
+                celixThreadRwlock_unlock(&entry->fsmMutex);
+            }
             celix_framework_bundleEntry_decreaseUseCount(entry);
         } else {
             framework_logIfError(fw->logger, CELIX_FRAMEWORK_EXCEPTION, NULL, "Bundle with id %li is not installed", bundleId);


[celix] 03/08: Implement OSGi uninstall, and make install/uninstall thread-safe.

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 73dac42f05e86d8e5974d14c2a66d5d8b6865c7c
Author: PengZheng <ho...@gmail.com>
AuthorDate: Thu Jun 1 19:16:21 2023 +0800

    Implement OSGi uninstall, and make install/uninstall thread-safe.
---
 libs/framework/gtest/src/BundleArchiveTestSuite.cc | 27 +++++++++++++--
 .../src/CelixBundleContextBundlesTestSuite.cc      | 40 +++++++++++++++++++---
 libs/framework/src/framework.c                     | 21 +++++++++---
 .../src/framework_bundle_lifecycle_handler.c       |  4 +--
 libs/framework/src/framework_private.h             |  4 ++-
 5 files changed, 81 insertions(+), 15 deletions(-)

diff --git a/libs/framework/gtest/src/BundleArchiveTestSuite.cc b/libs/framework/gtest/src/BundleArchiveTestSuite.cc
index 98b376a8..59cc1c1c 100644
--- a/libs/framework/gtest/src/BundleArchiveTestSuite.cc
+++ b/libs/framework/gtest/src/BundleArchiveTestSuite.cc
@@ -74,8 +74,18 @@ TEST_F(CxxBundleArchiveTestSuite, BundleArchiveReusedTest) {
     auto firstBundleRevisionTime = installTime;
     lock.unlock();
 
-    //uninstall and reinstall
-    ctx->uninstallBundle(bndId1);
+    tracker.reset();
+    fw = celix::createFramework({
+                                        {"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"},
+                                        {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "false"}
+                                });
+    ctx = fw->getFrameworkBundleContext();
+    tracker = ctx->trackBundles()
+            .addOnInstallCallback([&](const celix::Bundle& b) {
+                std::lock_guard<std::mutex> lock{m};
+                auto *archive = celix_bundle_getArchive(b.getCBundle());
+                EXPECT_EQ(CELIX_SUCCESS, celix_bundleArchive_getLastModified(archive, &installTime));
+            }).build();
     std::this_thread::sleep_for(std::chrono::milliseconds{100}); //wait so that the zip <-> archive dir modification time is different
     long bndId2 = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION);
     EXPECT_GT(bndId2, -1);
@@ -89,7 +99,18 @@ TEST_F(CxxBundleArchiveTestSuite, BundleArchiveReusedTest) {
 
 
     auto secondBundleRevisionTime = installTime;
-    ctx->uninstallBundle(bndId1);
+    tracker.reset();
+    fw = celix::createFramework({
+                                        {"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"},
+                                        {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "false"}
+                                });
+    ctx = fw->getFrameworkBundleContext();
+    tracker = ctx->trackBundles()
+            .addOnInstallCallback([&](const celix::Bundle& b) {
+                std::lock_guard<std::mutex> lock{m};
+                auto *archive = celix_bundle_getArchive(b.getCBundle());
+                EXPECT_EQ(CELIX_SUCCESS, celix_bundleArchive_getLastModified(archive, &installTime));
+            }).build();
     std::this_thread::sleep_for(std::chrono::milliseconds{100}); //wait so that the zip <-> archive dir modification time is different
     celix_utils_touch(SIMPLE_TEST_BUNDLE1_LOCATION); //touch the bundle zip file to force an update
     long bndId3 = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION);
diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
index cf9c08bf..e6213766 100644
--- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
@@ -28,6 +28,7 @@
 #include <celix_log_utils.h>
 
 #include "celix_api.h"
+#include "celix_file_utils.h"
 
 class CelixBundleContextBundlesTestSuite : public ::testing::Test {
 public:
@@ -46,7 +47,7 @@ public:
     CelixBundleContextBundlesTestSuite() {
         properties = properties_create();
         properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
-        properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
+        properties_set(properties, "org.osgi.framework.storage.clean", "true");
         properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
 
         fw = celix_frameworkFactory_createFramework(properties);
@@ -152,6 +153,29 @@ TEST_F(CelixBundleContextBundlesTestSuite, InstallAndUninstallBundlesTest) {
     ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2)); //not auto started
     ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId3));
 
+    char *bndRoot1 = nullptr;
+    ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId1, &bndRoot1, [](void* handle, const celix_bundle_t* bnd) {
+        char **root = static_cast<char **>(handle);
+        *root = celix_bundle_getEntry(bnd, "/");
+    }));
+    ASSERT_TRUE(bndRoot1 != nullptr);
+    char* bndRoot2 = nullptr;
+    ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId2, &bndRoot2, [](void* handle, const celix_bundle_t* bnd) {
+        char **root = static_cast<char **>(handle);
+        *root = celix_bundle_getEntry(bnd, "/");
+    }));
+    ASSERT_TRUE(bndRoot2 != nullptr);
+    char* bndRoot3 = nullptr;
+    ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId3, &bndRoot3, [](void* handle, const celix_bundle_t* bnd) {
+        char **root = static_cast<char **>(handle);
+        *root = celix_bundle_getEntry(bnd, "/");
+    }));
+    ASSERT_TRUE(bndRoot3 != nullptr);
+
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot1));
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot2));
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot3));
+
     //uninstall bundles
     ASSERT_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId1));
     ASSERT_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId2));
@@ -165,17 +189,25 @@ TEST_F(CelixBundleContextBundlesTestSuite, InstallAndUninstallBundlesTest) {
     ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2));
     ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId3));
 
+    ASSERT_FALSE(celix_utils_directoryExists(bndRoot1));
+    ASSERT_FALSE(celix_utils_directoryExists(bndRoot2));
+    ASSERT_FALSE(celix_utils_directoryExists(bndRoot3));
+
+    free(bndRoot1);
+    free(bndRoot2);
+    free(bndRoot3);
+
     //reinstall bundles
     long bndId4 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
     long bndId5 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false);
     long bndId6 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
 
     ASSERT_TRUE(bndId4 >= 0L);
-    ASSERT_TRUE(bndId1 == bndId4); //bundle cache -> reuse of bundle id.
+    ASSERT_FALSE(bndId1 == bndId4); //bundle cache -> reuse of bundle id.
     ASSERT_TRUE(bndId5 >= 0L);
-    ASSERT_TRUE(bndId2 == bndId5); //bundle cache -> reuse of bundle id.
+    ASSERT_FALSE(bndId2 == bndId5); //bundle cache -> reuse of bundle id.
     ASSERT_TRUE(bndId6 >= 0L);
-    ASSERT_TRUE(bndId3 == bndId6); //bundle cache -> reuse of bundle id.
+    ASSERT_FALSE(bndId3 == bndId6); //bundle cache -> reuse of bundle id.
 }
 
 TEST_F(CelixBundleContextBundlesTestSuite, StartBundleWithException) {
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 93138d13..823d3d19 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -239,6 +239,7 @@ celix_status_t framework_create(framework_pt *out, celix_properties_t* config) {
     celixThreadMutex_create(&framework->dispatcher.mutex, NULL);
     celixThreadMutex_create(&framework->frameworkListenersLock, NULL);
     celixThreadMutex_create(&framework->bundleListenerLock, NULL);
+    celixThreadMutex_create(&framework->installLock, NULL);
     celixThreadMutex_create(&framework->installedBundles.mutex, NULL);
     celixThreadCondition_init(&framework->dispatcher.cond, NULL);
     framework->dispatcher.active = true;
@@ -359,6 +360,7 @@ celix_status_t framework_destroy(framework_pt framework) {
     celixThreadMutex_unlock(&framework->installedBundles.mutex);
     celix_arrayList_destroy(framework->installedBundles.entries);
     celixThreadMutex_destroy(&framework->installedBundles.mutex);
+    celixThreadMutex_destroy(&framework->installLock);
 
     //teardown framework bundle lifecycle handling
     assert(celix_arrayList_size(framework->bundleLifecycleHandling.bundleLifecycleHandlers) == 0);
@@ -646,11 +648,13 @@ celix_framework_installBundleInternal(celix_framework_t* framework, const char*
         }
     }
 
+    celixThreadMutex_lock(&framework->installLock);
     if (status == CELIX_SUCCESS) {
         id = framework_getBundle(framework, bndLoc);
         if (id != -1L) {
             celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry);
             *bundleOut = id;
+            celixThreadMutex_unlock(&framework->installLock);
             return CELIX_SUCCESS;
         }
 
@@ -677,7 +681,7 @@ celix_framework_installBundleInternal(celix_framework_t* framework, const char*
     }
 
     celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry);
-
+    celixThreadMutex_unlock(&framework->installLock);
     return status;
 }
 
@@ -1177,7 +1181,7 @@ static void* framework_shutdown(void *framework) {
     }
     for (int i = size-1; i >= 0; --i) { //note loop in reverse order -> uninstall later installed bundle first
         celix_framework_bundle_entry_t *entry = celix_arrayList_get(stopEntries, i);
-        celix_framework_uninstallBundleEntry(fw, entry);
+        celix_framework_uninstallBundleEntry(fw, entry, false);
     }
     celix_arrayList_destroy(stopEntries);
 
@@ -1888,10 +1892,11 @@ void celix_framework_uninstallBundleAsync(celix_framework_t *fw, long bndId) {
     celix_framework_uninstallBundleInternal(fw, bndId, true);
 }
 
-celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) {
+celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry, bool permanent) {
     assert(!celix_framework_isCurrentThreadTheEventLoop(framework));
-    celixThreadRwlock_writeLock(&bndEntry->fsmMutex);
 
+    celixThreadMutex_lock(&framework->installLock);
+    celixThreadRwlock_writeLock(&bndEntry->fsmMutex);
     celix_bundle_state_e bndState = celix_bundle_getState(bndEntry->bnd);
     if (bndState == CELIX_BUNDLE_STATE_ACTIVE) {
         celix_framework_stopBundleEntryInternal(framework, bndEntry);
@@ -1900,6 +1905,7 @@ celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework
     if (!fw_bundleEntry_removeBundleEntry(framework, bndEntry)) {
         celixThreadRwlock_unlock(&bndEntry->fsmMutex);
         celix_framework_bundleEntry_decreaseUseCount(bndEntry);
+        celixThreadMutex_unlock(&framework->installLock);
         return CELIX_ILLEGAL_STATE;
     }
 
@@ -1932,8 +1938,13 @@ celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework
         celix_framework_waitForEmptyEventQueue(framework); //to ensure that the uninstall event is triggered and handled
         (void)bundle_closeModules(bnd);
         (void)bundle_destroy(bnd);
-        (void)bundleArchive_destroy(archive);
+        if(permanent) {
+            (void)celix_bundleCache_destroyArchive(framework->cache, archive);
+        } else {
+            (void)bundleArchive_destroy(archive);
+        }
     }
+    celixThreadMutex_unlock(&framework->installLock);
     framework_logIfError(framework->logger, status, "", "Cannot uninstall bundle");
     return status;
 }
diff --git a/libs/framework/src/framework_bundle_lifecycle_handler.c b/libs/framework/src/framework_bundle_lifecycle_handler.c
index c0851943..669778d8 100644
--- a/libs/framework/src/framework_bundle_lifecycle_handler.c
+++ b/libs/framework/src/framework_bundle_lifecycle_handler.c
@@ -47,7 +47,7 @@ static void* celix_framework_BundleLifecycleHandlingThread(void *data) {
             break;
         case CELIX_BUNDLE_LIFECYCLE_UNINSTALL:
             celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
-            celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry);
+            celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, true);
             break;
         default: //update
             celix_framework_updateBundleEntry(handler->framework, handler->bndEntry, handler->updatedBundleUrl);
@@ -143,7 +143,7 @@ celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_frame
         celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_UNINSTALL, NULL);
         return CELIX_SUCCESS;
     } else {
-        return celix_framework_uninstallBundleEntry(fw, bndEntry);
+        return celix_framework_uninstallBundleEntry(fw, bndEntry, true);
     }
 }
 
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index 3d98c3d8..f2944cac 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -40,6 +40,7 @@
 
 #include "celix_threads.h"
 #include "service_registry.h"
+#include <stdbool.h>
 
 #ifndef CELIX_FRAMEWORK_DEFAULT_STATIC_EVENT_QUEUE_SIZE
 #define CELIX_FRAMEWORK_DEFAULT_STATIC_EVENT_QUEUE_SIZE 1024
@@ -147,6 +148,7 @@ struct celix_framework {
         celix_thread_t thread;
     } shutdown;
 
+    celix_thread_mutex_t installLock; // serialize install/uninstall
     struct {
         celix_array_list_t *entries; //value = celix_framework_bundle_entry_t*. Note ordered by installed bundle time
                                      //i.e. later installed bundle are last
@@ -426,7 +428,7 @@ celix_status_t celix_framework_stopBundleEntry(celix_framework_t* fw, celix_fram
 /**
  * Uninstall a bundle. Cannot be called on the Celix event thread.
  */
-celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry);
+celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool permanent);
 
 /**
  * Uninstall a bundle. Cannot be called on the Celix event thread.


[celix] 07/08: Add full support of bundle update.

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit cccf30aac326a919727f0e164a474004921b9756
Author: PengZheng <ho...@gmail.com>
AuthorDate: Fri Jun 2 23:00:57 2023 +0800

    Add full support of bundle update.
    
    It fixes #563 and #557.
---
 .../BundleArchiveWithErrorInjectionTestSuite.cc    |  42 +-----
 .../src/CelixBundleContextBundlesTestSuite.cc      |  33 +++++
 .../framework/gtest/src/CelixFrameworkTestSuite.cc |  18 ++-
 libs/framework/include/celix_bundle_context.h      |  14 +-
 libs/framework/include/celix_framework.h           |  32 +++--
 libs/framework/src/bundle.c                        |  26 +---
 libs/framework/src/bundle_archive.c                |  39 +----
 libs/framework/src/bundle_revision.c               |  27 ++--
 libs/framework/src/framework.c                     | 157 ++++++++++-----------
 .../src/framework_bundle_lifecycle_handler.c       |   6 +-
 libs/framework/src/framework_private.h             |   4 +-
 11 files changed, 168 insertions(+), 230 deletions(-)

diff --git a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc
index 6fc2118f..d0363d02 100644
--- a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc
+++ b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc
@@ -229,44 +229,4 @@ TEST_F(CelixBundleArchiveErrorInjectionTestSuite, ArchiveCreateErrorTest) {
     teardownErrorInjectors();
 
     EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_destroy(cache));
-}
-
-TEST_F(CelixBundleArchiveErrorInjectionTestSuite, ArchiveReviseErrorTest) {
-    celix_bundle_cache_t* cache = nullptr;
-    createCache(&cache);
-    bundle_archive_t* archive = nullptr;
-
-    // revision creation failure
-    EXPECT_EQ(CELIX_SUCCESS,
-              celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 1, SIMPLE_TEST_BUNDLE1_LOCATION, &archive));
-    EXPECT_NE(nullptr, archive);
-    celix_ei_expect_calloc((void*)celix_bundleRevision_create, 0, nullptr);
-    EXPECT_EQ(CELIX_ENOMEM, bundleArchive_revise(archive, SIMPLE_TEST_BUNDLE1_LOCATION, nullptr));
-    EXPECT_EQ(CELIX_SUCCESS, bundleArchive_destroy(archive));
-    EXPECT_EQ(CELIX_SUCCESS, celix_utils_deleteDirectory(TEST_ARCHIVE_ROOT, nullptr));
-    teardownErrorInjectors();
-
-    // manifest clone failure
-    EXPECT_EQ(CELIX_SUCCESS,
-              celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 1, SIMPLE_TEST_BUNDLE1_LOCATION, &archive));
-    EXPECT_NE(nullptr, archive);
-    celix_ei_expect_malloc((void*)manifest_clone, 1, nullptr);
-    EXPECT_EQ(CELIX_ENOMEM, bundleArchive_revise(archive, SIMPLE_TEST_BUNDLE1_LOCATION, nullptr));
-    EXPECT_EQ(CELIX_SUCCESS, bundleArchive_destroy(archive));
-    EXPECT_EQ(CELIX_SUCCESS, celix_utils_deleteDirectory(TEST_ARCHIVE_ROOT, nullptr));
-    teardownErrorInjectors();
-
-    // extract zip data failure
-    EXPECT_EQ(CELIX_SUCCESS,
-              celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 1, SIMPLE_TEST_BUNDLE1_LOCATION, &archive));
-    EXPECT_NE(nullptr, archive);
-    celix_ei_expect_celix_utils_extractZipFile((void*)celix_framework_utils_extractBundle, 1, CELIX_FILE_IO_EXCEPTION);
-    usleep(10000); // sleep to ensure that the last modified time is different (otherwise the revision is not updated
-    celix_utils_touch(SIMPLE_TEST_BUNDLE1_LOCATION);
-    EXPECT_EQ(CELIX_FILE_IO_EXCEPTION, bundleArchive_revise(archive, SIMPLE_TEST_BUNDLE1_LOCATION, nullptr));
-    EXPECT_EQ(CELIX_SUCCESS, bundleArchive_destroy(archive));
-    EXPECT_EQ(CELIX_SUCCESS, celix_utils_deleteDirectory(TEST_ARCHIVE_ROOT, nullptr));
-    teardownErrorInjectors();
-
-    EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_destroy(cache));
-}
+}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
index f7672087..0d222bb7 100644
--- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
@@ -286,6 +286,39 @@ TEST_F(CelixBundleContextBundlesTestSuite, InstallAndUnloadBundlesTest) {
     ASSERT_TRUE(bndId3 == bndId6); //bundle cache -> reuse of bundle id.
 }
 
+TEST_F(CelixBundleContextBundlesTestSuite, UpdateBundlesTest) {
+    long bndId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
+    ASSERT_TRUE(bndId1 >= 0L);
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId1));
+
+    ASSERT_TRUE(celix_bundleContext_updateBundle(ctx, bndId1, NULL));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId1));
+
+    ASSERT_TRUE(celix_bundleContext_stopBundle(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_updateBundle(ctx, bndId1, NULL));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId1));
+
+    long bndId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false);
+    ASSERT_TRUE(bndId2 >= 0L);
+    ASSERT_FALSE(celix_bundleContext_updateBundle(ctx, bndId1, TEST_BND2_LOC));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_EQ(bndId2, celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false));
+    ASSERT_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId2));
+
+    auto sn1 = celix_bundleContext_getBundleSymbolicName(ctx, bndId1);
+    ASSERT_TRUE(celix_bundleContext_updateBundle(ctx, bndId1, TEST_BND2_LOC));
+    auto sn2 = celix_bundleContext_getBundleSymbolicName(ctx, bndId1);
+    ASSERT_STRNE(sn1, sn2);
+    free(sn2);
+    free(sn1);
+
+    ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId1));
+    ASSERT_FALSE(celix_bundleContext_updateBundle(ctx, bndId1, NULL));
+}
+
 TEST_F(CelixBundleContextBundlesTestSuite, StartBundleWithException) {
     long bndId = celix_bundleContext_installBundle(ctx, TEST_BND_WITH_EXCEPTION_LOC, true);
     ASSERT_TRUE(bndId > 0); //bundle is installed, but not started
diff --git a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc
index 89c20f61..95e7d434 100644
--- a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc
+++ b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc
@@ -79,17 +79,29 @@ TEST_F(CelixFrameworkTestSuite, EventQueueTest) {
     EXPECT_EQ(4, count);
 }
 
-TEST_F(CelixFrameworkTestSuite, AsyncInstallStartStopAndUninstallBundleTest) {
+TEST_F(CelixFrameworkTestSuite, AsyncInstallStartStopUpdateAndUninstallBundleTest) {
     long bndId = celix_framework_installBundleAsync(framework.get(), SIMPLE_TEST_BUNDLE1_LOCATION, false);
     EXPECT_GE(bndId, 0);
     EXPECT_TRUE(celix_framework_isBundleInstalled(framework.get(), bndId));
     EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId));
 
-    celix_framework_startBundle(framework.get(), bndId);
+    celix_framework_updateBundleAsync(framework.get(), bndId, NULL);
+    std::this_thread::sleep_for(std::chrono::milliseconds{100});
+    EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId));
+
+    celix_framework_startBundleAsync(framework.get(), bndId);
     std::this_thread::sleep_for(std::chrono::milliseconds{100});
     EXPECT_TRUE(celix_framework_isBundleActive(framework.get(), bndId));
 
-    celix_framework_stopBundle(framework.get(), bndId);
+    celix_framework_updateBundleAsync(framework.get(), bndId, NULL);
+    std::this_thread::sleep_for(std::chrono::milliseconds{100});
+    EXPECT_TRUE(celix_framework_isBundleActive(framework.get(), bndId));
+
+    celix_framework_stopBundleAsync(framework.get(), bndId);
+    std::this_thread::sleep_for(std::chrono::milliseconds{100});
+    EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId));
+
+    celix_framework_updateBundleAsync(framework.get(), bndId, NULL);
     std::this_thread::sleep_for(std::chrono::milliseconds{100});
     EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId));
 
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index fc73b180..3d3d71e1 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -952,22 +952,23 @@ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_stopBundle(celix_bundle_context_
 CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_startBundle(celix_bundle_context_t *ctx, long bndId);
 
 /**
- * @brief Update the bundle with the provided bundle id async.
+ * @brief Update the bundle with the provided bundle id.
  *
  * This will do the following:
- *  - stop the bundle (if needed);
- *  - update the bundle revision if a newer bundle zip if found;
- *  - start the bundle, if it was started before the update.
+ *  - uninstall the bundle with the specified bundle id;
+ *  - reinstall the bundle from the specified location with the specified bundle id;
+ *  - start the bundle, if it was previously active.
  *
  * Will silently ignore bundle ids < 0.
  *
+ * Note if specified bundle location already exists in the bundle cache but with a different bundle id, the bundle
+ * will NOT be reinstalled, and the update is cancelled.
+ *
  * If this function is called on the Celix event thread, the actual updating of the bundle will be done async and
  * on a separate thread.
  * If this function is called from a different thread than the Celix event thread, then the function will
  * return after the bundle update is completed.
  *
- * @warning Update bundle is not yet fully supported. Use at your own risk.
- *
  * @param ctx The bundle context
  * @param bndId The bundle id to update.
  * @param updatedBundleUrl The optional updated bundle url to the bundle zip file. If NULL, the existing bundle url
@@ -986,7 +987,6 @@ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_updateBundle(celix_bundle_contex
  */
 CELIX_FRAMEWORK_EXPORT char* celix_bundleContext_getBundleSymbolicName(celix_bundle_context_t *ctx, long bndId);
 
-
 /**
  * @brief Track bundles.
  *
diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h
index 5f3d338a..ad833ce5 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -186,18 +186,19 @@ CELIX_FRAMEWORK_EXPORT bool celix_framework_unloadBundle(celix_framework_t *fw,
  * @brief Update the bundle with the provided bundle id.
  *
  * This will do the following:
- *  - stop the bundle (if needed);
- *  - update the bundle revision if a newer bundle zip if found;
- *  - start the bundle, if it was started.
+ *  - uninstall the bundle with the specified bundle id;
+ *  - reinstall the bundle from the specified location with the specified bundle id;
+ *  - start the bundle, if it was previously active.
  *
  *  Will silently ignore bundle ids < 0.
  *
- * @warning Update bundle is not yet fully supported. Use at your own risk.
+ *  Note if specified bundle location already exists in the bundle cache but with a different bundle id, the bundle
+ *  will NOT be reinstalled, and the update is cancelled.
  *
- * @param fw The Celix framework
- * @parma bndId the bundle id to update.
- * @param updatedBundleUrl The optional updated bundle url to the bundle zip file. If NULL, the existing bundle url
- *                         from the bundle cache will be used.
+ * @param [in] fw The Celix framework
+ * @param [in] bndId the bundle id to update.
+ * @param [in] updatedBundleUrl The optional updated bundle url to the bundle zip file.
+ * If NULL, the existing bundle url from the bundle cache will be used.
  * @return true if the bundle is correctly updated. False if not.
  */
 CELIX_FRAMEWORK_EXPORT bool celix_framework_updateBundle(celix_framework_t *fw, long bndId, const char* updatedBundleUrl);
@@ -239,17 +240,18 @@ CELIX_FRAMEWORK_EXPORT long celix_framework_installBundleAsync(celix_framework_t
  * @brief Update the bundle with the provided bundle id async.
  *
  * This will do the following:
- *  - stop the bundle (if needed);
- *  - update the bundle revision if a newer bundle zip if found;
- *  - start the bundle, if it was started.
+ *  - uninstall the bundle with the specified bundle id;
+ *  - reinstall the bundle from the specified location with the specified bundle id;
+ *  - start the bundle, if it was previously active.
  *
  *  Will silently ignore bundle ids < 0.
  *
- *  @warning Update bundle is not yet fully supported. Use at your own risk.
+ *  Note if specified bundle location already exists in the bundle cache but with a different bundle id, the bundle
+ *  will NOT be reinstalled, and the update is cancelled.
  *
- *  @param fw The Celix framework
- *  @parma bndId the bundle id to update.
- *  @param updatedBundleUrl The optional updated bundle url to the bundle zip file. If NULL, the existing bundle url
+ * @param [in] fw The Celix framework
+ * @param [in] bndId the bundle id to update.
+ * @param [in] updatedBundleUrl The optional updated bundle url to the bundle zip file. If NULL, the existing bundle url
  *                         from the bundle cache will be used.
  */
 CELIX_FRAMEWORK_EXPORT void celix_framework_updateBundleAsync(celix_framework_t *fw, long bndId, const char* updatedBundleUrl);
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c
index 64eaa241..083a6944 100644
--- a/libs/framework/src/bundle.c
+++ b/libs/framework/src/bundle.c
@@ -280,30 +280,8 @@ celix_status_t bundle_setPersistentStateUninstalled(bundle_pt bundle) {
 }
 
 celix_status_t bundle_revise(bundle_pt bundle, const char * location, const char *inputFile) {
-	celix_status_t status;
-
-	bundle_archive_pt archive = NULL;
-	status = bundle_getArchive(bundle, &archive);
-	if (status == CELIX_SUCCESS) {
-		status = bundleArchive_revise(archive, location, inputFile);
-		if (status == CELIX_SUCCESS) {
-			module_pt module;
-			status = bundle_createModule(bundle, &module);
-			if (status == CELIX_SUCCESS) {
-				status = bundle_addModule(bundle, module);
-			} else {
-				bool rolledback;
-				status = bundleArchive_rollbackRevise(archive, &rolledback);
-				if (status == CELIX_SUCCESS) {
-					status = CELIX_BUNDLE_EXCEPTION;
-				}
-			}
-		}
-	}
-
-	framework_logIfError(bundle->framework->logger, status, NULL, "Failed to revise bundle");
-
-	return status;
+    fw_log(bundle->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Usage of bundle_revise is deprecated and no longer needed. Called for bundle %s", bundle->symbolicName);
+    return CELIX_SUCCESS;
 }
 
 celix_status_t bundle_addModule(bundle_pt bundle, module_pt module) {
diff --git a/libs/framework/src/bundle_archive.c b/libs/framework/src/bundle_archive.c
index aec52ce4..818d03a6 100644
--- a/libs/framework/src/bundle_archive.c
+++ b/libs/framework/src/bundle_archive.c
@@ -433,46 +433,11 @@ celix_status_t bundleArchive_setLastModified(bundle_archive_pt archive __attribu
     celix_utils_freeStringIfNotEqual(manifestPathBuffer, manifestPath);
     return status;
 }
-//LCOV_EXCL_STOP
 
 celix_status_t bundleArchive_revise(bundle_archive_pt archive, const char * location __attribute__((unused)), const char *updatedBundleUrl) {
-    celixThreadMutex_lock(&archive->lock);
-
-    const char* updateUrl = archive->location;
-    if (updatedBundleUrl != NULL && strcmp(updateUrl, updatedBundleUrl) != 0) {
-        fw_log(archive->fw->logger, CELIX_LOG_LEVEL_INFO, "Updating bundle archive bundle url location to %s", updatedBundleUrl);
-        updateUrl = updatedBundleUrl;
-    }
-
-    const char* reason = NULL;
-    celix_status_t status = celix_bundleArchive_extractBundle(archive, updateUrl);
-    if (status == CELIX_SUCCESS) {
-        bundle_revision_t* current = archive->revision;
-        bundle_revision_t* revised = bundleRevision_revise(current, updateUrl);
-        if (revised != NULL) {
-            archive->revision = revised;
-            bundleRevision_destroy(current);
-        } else {
-            status = CELIX_ENOMEM;
-            reason = "bundle revision creation";
-        }
-    } else {
-        reason = "bundle extraction";
-    }
-    if (status != CELIX_SUCCESS) {
-        goto revise_finished;
-    }
-    if (archive->location != updateUrl) {
-        free(archive->location);
-        archive->location = celix_utils_strdup(updateUrl);
-    }
-revise_finished:
-    celixThreadMutex_unlock(&archive->lock);
-    framework_logIfError(archive->fw->logger, status, reason, "Cannot update bundle archive %s", updateUrl);
-    return status;
+    fw_log(archive->fw->logger, CELIX_LOG_LEVEL_ERROR, "Revise not supported.");
+    return CELIX_BUNDLE_EXCEPTION;
 }
-
-//LCOV_EXCL_START
 celix_status_t bundleArchive_rollbackRevise(bundle_archive_pt archive, bool* rolledback) {
     *rolledback = true;
     fw_log(archive->fw->logger, CELIX_LOG_LEVEL_ERROR, "Revise rollback not supported.");
diff --git a/libs/framework/src/bundle_revision.c b/libs/framework/src/bundle_revision.c
index b0bdbbde..8b0a68b7 100644
--- a/libs/framework/src/bundle_revision.c
+++ b/libs/framework/src/bundle_revision.c
@@ -52,15 +52,6 @@ celix_status_t celix_bundleRevision_create(celix_framework_t* fw, const char *ro
     return status;
 }
 
-bundle_revision_t* bundleRevision_revise(const bundle_revision_t* rev, const char* updatedBundleUrl) {
-    bundle_revision_pt newRev = NULL;
-    manifest_pt clonedManifest = manifest_clone(rev->manifest);
-    if (clonedManifest) {
-        celix_bundleRevision_create(rev->fw, rev->root, updatedBundleUrl, clonedManifest, &newRev);
-    }
-    return newRev;
-}
-
 celix_status_t bundleRevision_destroy(bundle_revision_pt revision) {
     if (revision != NULL) {
         manifest_destroy(revision->manifest);
@@ -71,6 +62,18 @@ celix_status_t bundleRevision_destroy(bundle_revision_pt revision) {
     return CELIX_SUCCESS;
 }
 
+celix_status_t bundleRevision_getManifest(const bundle_revision_t* revision, manifest_pt* manifest) {
+    *manifest = revision->manifest;
+    return CELIX_SUCCESS;
+}
+
+//LCOV_EXCL_START
+bundle_revision_t* bundleRevision_revise(const bundle_revision_t* rev, const char* updatedBundleUrl) {
+    fw_log(rev->fw->logger, CELIX_LOG_LEVEL_ERROR, "Revision revise unsupported.");
+    return NULL;
+}
+
+
 celix_status_t bundleRevision_getNumber(const bundle_revision_t* revision, long *revisionNr) {
     *revisionNr = 1; //note revision nr is deprecated
     return CELIX_SUCCESS;
@@ -86,11 +89,6 @@ celix_status_t bundleRevision_getRoot(const bundle_revision_t* revision, const c
     return CELIX_SUCCESS;
 }
 
-celix_status_t bundleRevision_getManifest(const bundle_revision_t* revision, manifest_pt* manifest) {
-    *manifest = revision->manifest;
-    return CELIX_SUCCESS;
-}
-
 celix_status_t bundleRevision_getHandles(const bundle_revision_t* revision __attribute__((unused)), celix_array_list_t** handles) {
     //nop, usage deprecated
     if (handles) {
@@ -98,4 +96,5 @@ celix_status_t bundleRevision_getHandles(const bundle_revision_t* revision __att
     }
     return CELIX_SUCCESS;
 }
+//LCOV_EXCL_STOP
 
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 0c6c31b8..e730133c 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -239,7 +239,11 @@ celix_status_t framework_create(framework_pt *out, celix_properties_t* config) {
     celixThreadMutex_create(&framework->dispatcher.mutex, NULL);
     celixThreadMutex_create(&framework->frameworkListenersLock, NULL);
     celixThreadMutex_create(&framework->bundleListenerLock, NULL);
-    celixThreadMutex_create(&framework->installLock, NULL);
+    celix_thread_mutexattr_t muAttr;
+    celixThreadMutexAttr_create(&muAttr);
+    celixThreadMutexAttr_settype(&muAttr, CELIX_THREAD_MUTEX_RECURSIVE);
+    celixThreadMutex_create(&framework->installLock, &muAttr);
+    celixThreadMutexAttr_destroy(&muAttr);
     celixThreadMutex_create(&framework->installedBundles.mutex, NULL);
     celixThreadCondition_init(&framework->dispatcher.cond, NULL);
     framework->dispatcher.active = true;
@@ -625,7 +629,7 @@ bool celix_framework_getConfigPropertyAsBool(celix_framework_t* framework, const
 }
 
 celix_status_t
-celix_framework_installBundleInternal(celix_framework_t* framework, const char* bndLoc, long* bundleOut) {
+celix_framework_installBundleInternal(celix_framework_t* framework, const char* bndLoc, long* bndId) {
     celix_status_t status = CELIX_SUCCESS;
     celix_bundle_t* bundle = NULL;
     long id = -1L;
@@ -650,16 +654,19 @@ celix_framework_installBundleInternal(celix_framework_t* framework, const char*
 
     celixThreadMutex_lock(&framework->installLock);
     if (status == CELIX_SUCCESS) {
-        id = framework_getBundle(framework, bndLoc);
-        if (id != -1L) {
-            celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry);
-            *bundleOut = id;
-            celixThreadMutex_unlock(&framework->installLock);
-            return CELIX_SUCCESS;
+        if (*bndId == -1L) {
+            id = framework_getBundle(framework, bndLoc);
+            if (id != -1L) {
+                celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry);
+                celixThreadMutex_unlock(&framework->installLock);
+                *bndId = id;
+                return CELIX_SUCCESS;
+            }
+            long alreadyExistingBndId = celix_bundleCache_findBundleIdForLocation(framework->cache, bndLoc);
+            id = alreadyExistingBndId == -1 ? framework_getNextBundleId(framework) : alreadyExistingBndId;
+        } else {
+            id = *bndId;
         }
-
-        long alreadyExistingBndId = celix_bundleCache_findBundleIdForLocation(framework->cache, bndLoc);
-        id = alreadyExistingBndId == -1 ? framework_getNextBundleId(framework) : alreadyExistingBndId;
         bundle_archive_t* archive = NULL;
         status = CELIX_DO_IF(status, celix_bundleCache_createArchive(framework->cache, id, bndLoc, &archive));
         status = CELIX_DO_IF(status, celix_bundle_createFromArchive(framework, archive, &bundle));
@@ -675,7 +682,7 @@ celix_framework_installBundleInternal(celix_framework_t* framework, const char*
     }
 
     if (status == CELIX_SUCCESS) {
-        *bundleOut = id;
+        *bndId = id;
     } else {
         fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not install bundle");
     }
@@ -2267,89 +2274,71 @@ static bool celix_framework_updateBundleInternal(celix_framework_t *fw, long bnd
         fw_log(fw->logger, CELIX_LOG_LEVEL_INFO, "Cannot update framework bundle. Ignore update cmd.");
         return true;
     }
-
-    fw_log(fw->logger, CELIX_LOG_LEVEL_WARNING, "Update bundle is not yet fully supported. Use at your own risk.");
-
     bool updated = false;
     celix_framework_bundle_entry_t *bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId);
     if (bndEntry != NULL) {
         celix_status_t rc = celix_framework_updateBundleOnANonCelixEventThread(fw, bndEntry, updatedBundleUrl, forcedAsync);
+        //note not decreasing bndEntry, because this entry should now be deleted (uninstalled)
         updated = rc == CELIX_SUCCESS;
-        celix_framework_bundleEntry_decreaseUseCount(bndEntry);
         celix_framework_waitForBundleEvents(fw, bndId);
     }
     return updated;
 }
 
-
-celix_status_t celix_framework_bundleEntry_refreshBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t *entry, const char* updatedBundleUrl) {
+celix_status_t celix_framework_updateBundleEntry(celix_framework_t* framework,
+                                                 celix_framework_bundle_entry_t* bndEntry,
+                                                 const char* updatedBundleUrl) {
     celix_status_t status = CELIX_SUCCESS;
-    celix_bundle_state_e state = celix_bundle_getState(entry->bnd);
-    if (state != CELIX_BUNDLE_STATE_RESOLVED) {
-        fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot refresh bundle %s (id=%li), bundle is not in the resolved state",
-               celix_bundle_getSymbolicName(entry->bnd),
-               entry->bndId);
-        return CELIX_ILLEGAL_STATE;
-    }
-
-    bundle_archive_t* archive = NULL;
-    celix_module_t* module = NULL;
-    status = CELIX_DO_IF(status, bundle_getArchive(entry->bnd, &archive));
-    status = CELIX_DO_IF(status, bundle_getCurrentModule(entry->bnd, &module));
-
-    if (!archive || !module) {
-        fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot refresh bundle %s (id=%li), bundle has no archive or module",
-               celix_bundle_getSymbolicName(entry->bnd),
-               entry->bndId);
-        return status;
-    }
-
-    status = celix_module_closeLibraries(module);
-    if (status != CELIX_SUCCESS) {
-        fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot refresh bundle %s (id=%li), cannot close libraries",
-               celix_bundle_getSymbolicName(entry->bnd),
-               entry->bndId);
-        return status;
-    }
-
-    status = bundleArchive_revise(archive, NULL, updatedBundleUrl);
-    if (status != CELIX_SUCCESS) {
-        fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot refresh bundle %s (id=%li), bundle archive revision failed",
-               celix_bundle_getSymbolicName(entry->bnd),
-               entry->bndId);
-        return status;
-    }
-
-    status = celix_module_loadLibraries(module);
-    if (status != CELIX_SUCCESS) {
-        fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot refresh bundle %s (id=%li), cannot load libraries",
-               celix_bundle_getSymbolicName(entry->bnd),
-               entry->bndId);
-        return status;
-    }
-
-    return status;
-}
-
-celix_status_t celix_framework_updateBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry, const char* updatedBundleUrl) {
-    celix_status_t status = celix_framework_stopBundleEntry(framework, bndEntry);
-    if (status != CELIX_SUCCESS) {
-        fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not stop bundle for update");
-        return status;
-    }
-
-    status = celix_framework_bundleEntry_refreshBundleEntry(framework, bndEntry, updatedBundleUrl);
-    if (status != CELIX_SUCCESS) {
-        fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not refresh bundle for update");
-        return status;
-    }
-
-    status = celix_framework_startBundleEntry(framework, bndEntry);
-    if (status != CELIX_SUCCESS) {
-        fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not start bundle after update");
-    }
-
-    fw_log(framework->logger, CELIX_LOG_LEVEL_DEBUG, "Update bundle %s done", celix_bundle_getSymbolicName(bndEntry->bnd));
+    long bundleId = bndEntry->bndId;
+    const char* errMsg;
+    fw_log(framework->logger, CELIX_LOG_LEVEL_DEBUG, "Updating bundle %s", celix_bundle_getSymbolicName(bndEntry->bnd));
+    celix_bundle_state_e bndState = celix_bundle_getState(bndEntry->bnd);
+    char *location = celix_bundle_getLocation(bndEntry->bnd);
+    do {
+        // lock to reuse the bundle id
+        celixThreadMutex_lock(&framework->installLock);
+        if (updatedBundleUrl == NULL) {
+            updatedBundleUrl = location;
+        } else if (strcmp(location, updatedBundleUrl) != 0) {
+            long alreadyExistingBndId = celix_bundleCache_findBundleIdForLocation(framework->cache, updatedBundleUrl);
+            if (alreadyExistingBndId != -1 && alreadyExistingBndId != bundleId) {
+                errMsg = "specified bundle location exists in cache with a different id";
+                celix_framework_bundleEntry_decreaseUseCount(bndEntry);
+                celixThreadMutex_unlock(&framework->installLock);
+                status = CELIX_ILLEGAL_STATE;
+                break;
+            }
+        }
+        status = celix_framework_uninstallBundleEntry(framework, bndEntry, true);
+        if (status != CELIX_SUCCESS) {
+            errMsg = "uninstall failure";
+            celixThreadMutex_unlock(&framework->installLock);
+            break;
+        }
+        // bndEntry is now invalid
+        status = celix_framework_installBundleInternal(framework, updatedBundleUrl, &bundleId);
+        if (status != CELIX_SUCCESS) {
+            errMsg = "reinstall failure";
+            celixThreadMutex_unlock(&framework->installLock);
+            break;
+        }
+        if (bndState != CELIX_BUNDLE_STATE_STARTING && bndState != CELIX_BUNDLE_STATE_ACTIVE) {
+            // no need to restart the updated bundle
+            celixThreadMutex_unlock(&framework->installLock);
+            break;
+        }
+        celix_framework_bundle_entry_t* entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, bundleId);
+        celixThreadMutex_unlock(&framework->installLock);
+        // assert(entry != NULL);
+        status = celix_framework_startBundleEntry(framework, entry);
+        celix_framework_bundleEntry_decreaseUseCount(entry);
+        if (status != CELIX_SUCCESS) {
+            errMsg = "restart failure";
+            break;
+        }
+    } while(0);
+    framework_logIfError(framework->logger, status, errMsg, "Could not update bundle from %s", updatedBundleUrl);
+    free(location);
     return status;
 }
 
diff --git a/libs/framework/src/framework_bundle_lifecycle_handler.c b/libs/framework/src/framework_bundle_lifecycle_handler.c
index 6ffa9bb3..40caeb28 100644
--- a/libs/framework/src/framework_bundle_lifecycle_handler.c
+++ b/libs/framework/src/framework_bundle_lifecycle_handler.c
@@ -41,9 +41,11 @@ static void* celix_framework_BundleLifecycleHandlingThread(void *data) {
     switch (handler->command) {
         case CELIX_BUNDLE_LIFECYCLE_START:
             celix_framework_startBundleEntry(handler->framework, handler->bndEntry);
+            celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
             break;
         case CELIX_BUNDLE_LIFECYCLE_STOP:
             celix_framework_stopBundleEntry(handler->framework, handler->bndEntry);
+            celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
             break;
         case CELIX_BUNDLE_LIFECYCLE_UNINSTALL:
             celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
@@ -54,12 +56,10 @@ static void* celix_framework_BundleLifecycleHandlingThread(void *data) {
             celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, false);
             break;
         default: //update
+            celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
             celix_framework_updateBundleEntry(handler->framework, handler->bndEntry, handler->updatedBundleUrl);
             break;
     }
-    if (handler->command != CELIX_BUNDLE_LIFECYCLE_UNINSTALL && handler->command != CELIX_BUNDLE_LIFECYCLE_UNLOAD) {
-        celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
-    }
     celix_framework_cleanupBundleLifecycleHandler(handler->framework, handler);
     return NULL;
 }
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index c506e94b..d2a36cfc 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -253,7 +253,7 @@ double celix_framework_getConfigPropertyAsDouble(celix_framework_t* framework, c
  */
 bool celix_framework_getConfigPropertyAsBool(celix_framework_t* framework, const char* name, bool defaultValue, bool* found);
 
-celix_status_t celix_framework_installBundleInternal(celix_framework_t* framework, const char* bndLoc, long* bundleOut);
+celix_status_t celix_framework_installBundleInternal(celix_framework_t* framework, const char* bndLoc, long* bndId);
 
 celix_status_t fw_registerService(framework_pt framework, service_registration_pt * registration, long bundleId, const char* serviceName, const void* svcObj, properties_pt properties);
 celix_status_t fw_registerServiceFactory(framework_pt framework, service_registration_pt * registration, long bundleId, const char* serviceName, service_factory_pt factory, properties_pt properties);
@@ -433,7 +433,7 @@ celix_status_t celix_framework_stopBundleEntry(celix_framework_t* fw, celix_fram
 celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool permanent);
 
 /**
- * Uninstall a bundle. Cannot be called on the Celix event thread.
+ * Update a bundle. Cannot be called on the Celix event thread.
  */
 celix_status_t celix_framework_updateBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, const char* updatedBundleUrl);
 


[celix] 01/08: Fix race condition introduced by celix_framework_installBundleInternal.

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 98f187b9e40a3f774b1767f68e117dbf8f786464
Author: PengZheng <ho...@gmail.com>
AuthorDate: Wed May 31 16:55:34 2023 +0800

    Fix race condition introduced by celix_framework_installBundleInternal.
---
 libs/framework/src/bundle_context.c    |  8 +++++-
 libs/framework/src/framework.c         | 46 +++++++++++++++++-----------------
 libs/framework/src/framework_private.h |  5 ++--
 3 files changed, 32 insertions(+), 27 deletions(-)

diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index d5bb0540..8a802b7c 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -141,10 +141,16 @@ celix_status_t bundleContext_installBundle(bundle_context_pt context, const char
 }
 
 celix_status_t bundleContext_installBundle2(bundle_context_pt context, const char *location, const char *inputFile, bundle_pt *bundle) {
+    celix_status_t status = CELIX_SUCCESS;
+    long id = -1L;
     if (context == NULL || location == NULL || bundle == NULL) {
         return CELIX_ILLEGAL_ARGUMENT;
     }
-    return celix_framework_installBundleInternal(context->framework, location, bundle);
+    status = celix_framework_installBundleInternal(context->framework, location, &id);
+    if (status == CELIX_SUCCESS) {
+        *bundle = framework_getBundleById(context->framework, id);
+    }
+    return status;
 }
 
 celix_status_t bundleContext_registerService(bundle_context_pt context, const char * serviceName, const void * svcObj,
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index f87c3432..ca6cc4e1 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -525,10 +525,10 @@ static void framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw,
         char *location = strtok_r(autoStart, delims, &save_ptr);
         while (location != NULL) {
             //first install
-            bundle_t *bnd = NULL;
-            if (celix_framework_installBundleInternal(fw, location, &bnd) == CELIX_SUCCESS) {
+            long id = -1L;
+            if (celix_framework_installBundleInternal(fw, location, &id) == CELIX_SUCCESS) {
                 if (installedBundles) {
-                    celix_arrayList_add(installedBundles, bnd);
+                    celix_arrayList_addLong(installedBundles, id);
                 }
             } else {
                 fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not install bundle from location '%s'.", location);
@@ -544,8 +544,8 @@ static void framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw,
 static void framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const celix_array_list_t *installedBundles) {
     assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
     for (int i = 0; i < celix_arrayList_size(installedBundles); ++i) {
-        bundle_t *bnd = celix_arrayList_get(installedBundles, i);
-        long bndId = celix_bundle_getId(bnd);
+        long bndId = celix_arrayList_getLong(installedBundles, i);
+        bundle_t* bnd = framework_getBundleById(fw, bndId);
         if (celix_bundle_getState(bnd) != OSGI_FRAMEWORK_BUNDLE_ACTIVE) {
             bool started = celix_framework_startBundle(fw, bndId);
             if (!started) {
@@ -620,9 +620,11 @@ bool celix_framework_getConfigPropertyAsBool(celix_framework_t* framework, const
     return result;
 }
 
-celix_status_t celix_framework_installBundleInternal(celix_framework_t *framework, const char *bndLoc, celix_bundle_t **bundleOut) {
+celix_status_t
+celix_framework_installBundleInternal(celix_framework_t* framework, const char* bndLoc, long* bundleOut) {
     celix_status_t status = CELIX_SUCCESS;
     celix_bundle_t* bundle = NULL;
+    long id = -1L;
 
     bundle_state_e state = CELIX_BUNDLE_STATE_UNKNOWN;
 
@@ -634,24 +636,24 @@ celix_status_t celix_framework_installBundleInternal(celix_framework_t *framewor
     //increase use count of framework bundle to prevent a stop.
     celix_framework_bundle_entry_t *fwBundleEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework,
                                                                                                           framework->bundleId);
-  	status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
-  	if (status == CELIX_SUCCESS) {
+    status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
+    if (status == CELIX_SUCCESS) {
         if (state == CELIX_BUNDLE_STATE_STOPPING || state == CELIX_BUNDLE_STATE_UNINSTALLED) {
             fw_log(framework->logger, CELIX_LOG_LEVEL_INFO,  "The framework is being shutdown");
             status = CELIX_FRAMEWORK_SHUTDOWN;
         }
-  	}
+    }
 
     if (status == CELIX_SUCCESS) {
-        bundle = framework_getBundle(framework, bndLoc);
-        if (bundle != NULL) {
+        id = framework_getBundle(framework, bndLoc);
+        if (id != -1L) {
             celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry);
-            *bundleOut = bundle;
+            *bundleOut = id;
             return CELIX_SUCCESS;
         }
 
         long alreadyExistingBndId = celix_bundleCache_findBundleIdForLocation(framework->cache, bndLoc);
-        long id = alreadyExistingBndId == -1 ? framework_getNextBundleId(framework) : alreadyExistingBndId;
+        id = alreadyExistingBndId == -1 ? framework_getNextBundleId(framework) : alreadyExistingBndId;
         bundle_archive_t* archive = NULL;
         status = CELIX_DO_IF(status, celix_bundleCache_createArchive(framework->cache, id, bndLoc, &archive));
         status = CELIX_DO_IF(status, celix_bundle_createFromArchive(framework, archive, &bundle));
@@ -667,14 +669,14 @@ celix_status_t celix_framework_installBundleInternal(celix_framework_t *framewor
     }
 
     if (status == CELIX_SUCCESS) {
-        *bundleOut = bundle;
+        *bundleOut = id;
     } else {
         fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not install bundle");
     }
 
     celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry);
 
-  	return status;
+    return status;
 }
 
 bool celix_framework_isBundleAlreadyInstalled(celix_framework_t* fw, const char* bundleSymbolicName) {
@@ -1112,8 +1114,8 @@ array_list_pt framework_getBundles(framework_pt framework) {
     return bundles;
 }
 
-bundle_pt framework_getBundle(framework_pt framework, const char* location) {
-    bundle_t *bnd = NULL;
+long framework_getBundle(framework_pt framework, const char* location) {
+    long id = -1L;
 
     celixThreadMutex_lock(&framework->installedBundles.mutex);
     int size = celix_arrayList_size(framework->installedBundles.entries);
@@ -1122,13 +1124,13 @@ bundle_pt framework_getBundle(framework_pt framework, const char* location) {
         const char *loc = NULL;
         bundle_getBundleLocation(entry->bnd, &loc);
         if (loc != NULL && location != NULL && strncmp(loc, location, strlen(loc)) == 0) {
-            bnd = entry->bnd;
+            id = entry->bndId;
             break;
         }
     }
     celixThreadMutex_unlock(&framework->installedBundles.mutex);
 
-    return bnd;
+    return id;
 }
 
 celix_status_t framework_waitForStop(framework_pt framework) {
@@ -1833,12 +1835,10 @@ static void celix_framework_waitForBundleEvents(celix_framework_t *fw, long bndI
 
 static long celix_framework_installAndStartBundleInternal(celix_framework_t *fw, const char *bundleLoc, bool autoStart, bool forcedAsync) {
     long bundleId = -1;
-    bundle_t *bnd = NULL;
     celix_status_t status = CELIX_SUCCESS;
 
-    if (celix_framework_installBundleInternal(fw, bundleLoc, &bnd) == CELIX_SUCCESS) {
-        status = bundle_getBundleId(bnd, &bundleId);
-        if (status == CELIX_SUCCESS && autoStart) {
+    if (celix_framework_installBundleInternal(fw, bundleLoc, &bundleId) == CELIX_SUCCESS) {
+        if (autoStart) {
             celix_framework_bundle_entry_t* bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw,
                                                                                                                      bundleId);
             if (bndEntry != NULL) {
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index 47b22c8b..e1da3589 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -249,8 +249,7 @@ double celix_framework_getConfigPropertyAsDouble(celix_framework_t* framework, c
  */
 bool celix_framework_getConfigPropertyAsBool(celix_framework_t* framework, const char* name, bool defaultValue, bool* found);
 
-
-celix_status_t celix_framework_installBundleInternal(celix_framework_t *framework, const char *bndLoc, celix_bundle_t **bundleOut);
+celix_status_t celix_framework_installBundleInternal(celix_framework_t* framework, const char* bndLoc, long* bundleOut);
 
 celix_status_t fw_registerService(framework_pt framework, service_registration_pt * registration, long bundleId, const char* serviceName, const void* svcObj, properties_pt properties);
 celix_status_t fw_registerServiceFactory(framework_pt framework, service_registration_pt * registration, long bundleId, const char* serviceName, service_factory_pt factory, properties_pt properties);
@@ -271,7 +270,7 @@ celix_status_t fw_removeFrameworkListener(framework_pt framework, bundle_pt bund
 celix_status_t framework_markResolvedModules(framework_pt framework, linked_list_pt wires);
 
 array_list_pt framework_getBundles(framework_pt framework) __attribute__((deprecated("not thread safe, use celix_framework_useBundles instead")));
-bundle_pt framework_getBundle(framework_pt framework, const char* location);
+long framework_getBundle(framework_pt framework, const char* location);
 bundle_pt framework_getBundleById(framework_pt framework, long id);
 
 


[celix] 02/08: Use read-write-lock to protect bundle state transition.

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 063593cd81e9e79f411f86bd00e62fa8b0fec3c2
Author: PengZheng <ho...@gmail.com>
AuthorDate: Thu Jun 1 16:13:25 2023 +0800

    Use read-write-lock to protect bundle state transition.
    
    It fixes #561, an ABBA deadlock in test, and a potential double-free.
---
 bundles/pubsub/integration/gtest/tst_activator.c |   6 +-
 libs/framework/src/framework.c                   | 144 ++++++++++++-----------
 libs/framework/src/framework_private.h           |   1 +
 3 files changed, 81 insertions(+), 70 deletions(-)

diff --git a/bundles/pubsub/integration/gtest/tst_activator.c b/bundles/pubsub/integration/gtest/tst_activator.c
index 4084d5f0..c5d2c190 100644
--- a/bundles/pubsub/integration/gtest/tst_activator.c
+++ b/bundles/pubsub/integration/gtest/tst_activator.c
@@ -55,7 +55,7 @@ celix_status_t bnd_start(struct activator *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, PUBSUB_SUBSCRIBER_TOPIC, "ping");
         act->subSvc1.handle = act;
         act->subSvc1.receive = tst_receive;
-        act->subSvcId1 = celix_bundleContext_registerService(ctx, &act->subSvc1, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
+        act->subSvcId1 = celix_bundleContext_registerServiceAsync(ctx, &act->subSvc1, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
     }
 
     {
@@ -63,13 +63,13 @@ celix_status_t bnd_start(struct activator *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, PUBSUB_SUBSCRIBER_TOPIC, "ping");
         act->subSvc2.handle = act;
         act->subSvc2.receive = tst_receive2;
-        act->subSvcId2 = celix_bundleContext_registerService(ctx, &act->subSvc2, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
+        act->subSvcId2 = celix_bundleContext_registerServiceAsync(ctx, &act->subSvc2, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
     }
 
     {
         act->countSvc.handle = act;
         act->countSvc.receiveCount = tst_count;
-        act->countSvcId = celix_bundleContext_registerService(ctx, &act->countSvc, CELIX_RECEIVE_COUNT_SERVICE_NAME, NULL);
+        act->countSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->countSvc, CELIX_RECEIVE_COUNT_SERVICE_NAME, NULL);
     }
 
     return CELIX_SUCCESS;
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index ca6cc4e1..93138d13 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -54,10 +54,12 @@ struct celix_bundle_activator {
     celix_bundle_activator_destroy_fp destroy;
 };
 
+static celix_status_t celix_framework_stopBundleEntryInternal(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry);
+
 static inline celix_framework_bundle_entry_t* fw_bundleEntry_create(celix_bundle_t *bnd) {
     celix_framework_bundle_entry_t *entry = calloc(1, sizeof(*entry));
     entry->bnd = bnd;
-
+    celixThreadRwlock_create(&entry->fsmMutex, NULL);
     entry->bndId = celix_bundle_getId(bnd);
     entry->useCount = 0;
     celixThreadMutex_create(&entry->useMutex, NULL);
@@ -92,6 +94,7 @@ static inline void fw_bundleEntry_destroy(celix_framework_bundle_entry_t *entry,
     //destroy
     celixThreadMutex_destroy(&entry->useMutex);
     celixThreadCondition_destroy(&entry->useCond);
+    celixThreadRwlock_destroy(&entry->fsmMutex);
     free(entry);
 }
 
@@ -139,14 +142,13 @@ bool celix_framework_isBundleIdAlreadyUsed(celix_framework_t *fw, long bndId) {
     return found;
 }
 
-static inline celix_framework_bundle_entry_t* fw_bundleEntry_removeBundleEntryAndIncreaseUseCount(celix_framework_t *fw, long bndId) {
-    celix_framework_bundle_entry_t* found = NULL;
+static inline bool fw_bundleEntry_removeBundleEntry(celix_framework_t *fw, celix_framework_bundle_entry_t* bndEntry) {
+    bool found = false;
     celixThreadMutex_lock(&fw->installedBundles.mutex);
     for (int i = 0; i < celix_arrayList_size(fw->installedBundles.entries); ++i) {
         celix_framework_bundle_entry_t *entry = celix_arrayList_get(fw->installedBundles.entries, i);
-        if (entry->bndId == bndId) {
-            found = entry;
-            celix_framework_bundleEntry_increaseUseCount(entry);
+        if (entry == bndEntry) {
+            found = true;
             celix_arrayList_removeAt(fw->installedBundles.entries, i);
             break;
         }
@@ -1545,6 +1547,7 @@ bool celix_framework_useBundle(framework_t *fw, bool onlyActive, long bundleId,
                                                                                                               bundleId);
 
         if (entry != NULL) {
+            celixThreadRwlock_readLock(&entry->fsmMutex);
             celix_bundle_state_e bndState = celix_bundle_getState(entry->bnd);
             if (onlyActive && (bndState == CELIX_BUNDLE_STATE_ACTIVE || bndState == CELIX_BUNDLE_STATE_STARTING)) {
                 use(callbackHandle, entry->bnd);
@@ -1553,6 +1556,7 @@ bool celix_framework_useBundle(framework_t *fw, bool onlyActive, long bundleId,
                 use(callbackHandle, entry->bnd);
                 called = true;
             }
+            celixThreadRwlock_unlock(&entry->fsmMutex);
             celix_framework_bundleEntry_decreaseUseCount(entry);
         } else {
             framework_logIfError(fw->logger, CELIX_FRAMEWORK_EXCEPTION, NULL, "Bundle with id %li is not installed", bundleId);
@@ -1886,53 +1890,52 @@ void celix_framework_uninstallBundleAsync(celix_framework_t *fw, long bndId) {
 
 celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) {
     assert(!celix_framework_isCurrentThreadTheEventLoop(framework));
+    celixThreadRwlock_writeLock(&bndEntry->fsmMutex);
+
     celix_bundle_state_e bndState = celix_bundle_getState(bndEntry->bnd);
     if (bndState == CELIX_BUNDLE_STATE_ACTIVE) {
-        celix_framework_stopBundleEntry(framework, bndEntry);
+        celix_framework_stopBundleEntryInternal(framework, bndEntry);
     }
 
-    celix_framework_bundle_entry_t* removedEntry = fw_bundleEntry_removeBundleEntryAndIncreaseUseCount(framework, bndEntry->bndId);
+    if (!fw_bundleEntry_removeBundleEntry(framework, bndEntry)) {
+        celixThreadRwlock_unlock(&bndEntry->fsmMutex);
+        celix_framework_bundleEntry_decreaseUseCount(bndEntry);
+        return CELIX_ILLEGAL_STATE;
+    }
 
-    celix_framework_bundleEntry_decreaseUseCount(bndEntry);
-    if (removedEntry != NULL) {
-        celix_status_t status = CELIX_SUCCESS;
-        celix_bundle_t *bnd = removedEntry->bnd;
+    celix_status_t status = CELIX_SUCCESS;
+    celix_bundle_t *bnd = bndEntry->bnd;
+    bundle_archive_t *archive = NULL;
+    bundle_revision_t *revision = NULL;
+    celix_module_t* module = NULL;
+    status = CELIX_DO_IF(status, bundle_getArchive(bnd, &archive));
+    status = CELIX_DO_IF(status, bundleArchive_getCurrentRevision(archive, &revision));
+    status = CELIX_DO_IF(status, bundle_getCurrentModule(bnd, &module));
 
-        if (status == CELIX_SUCCESS) {
-            bundle_archive_t *archive = NULL;
-            bundle_revision_t *revision = NULL;
-            celix_module_t* module = NULL;
-            status = CELIX_DO_IF(status, bundle_getArchive(bnd, &archive));
-            status = CELIX_DO_IF(status, bundleArchive_getCurrentRevision(archive, &revision));
-            status = CELIX_DO_IF(status, bundle_getCurrentModule(bnd, &module));
-
-            if (module) {
-                celix_module_closeLibraries(module);
-            }
+    if (module) {
+        celix_module_closeLibraries(module);
+    }
 
-            CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, removedEntry));
+    CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, bndEntry));
 
-            status = CELIX_DO_IF(status, bundle_setState(bnd, CELIX_BUNDLE_STATE_UNINSTALLED));
+    status = CELIX_DO_IF(status, bundle_setState(bnd, CELIX_BUNDLE_STATE_UNINSTALLED));
 
-            CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED, removedEntry));
+    CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED, bndEntry));
 
-            //NOTE wait outside installedBundles.mutex
-            celix_framework_bundleEntry_decreaseUseCount(removedEntry);
-            fw_bundleEntry_destroy(removedEntry , true); //wait till use count is 0 -> e.g. not used
+    celixThreadRwlock_unlock(&bndEntry->fsmMutex);
 
-            if (status == CELIX_SUCCESS) {
-                celix_framework_waitForEmptyEventQueue(framework); //to ensure that the uninstall event is triggered and handled
-                bundleArchive_destroy(archive);
-                status = CELIX_DO_IF(status, bundle_closeModules(bnd));
-                status = CELIX_DO_IF(status, bundle_destroy(bnd));
-            }
-        }
-        framework_logIfError(framework->logger, status, "", "Cannot uninstall bundle");
-        return status;
+    //NOTE wait outside installedBundles.mutex
+    celix_framework_bundleEntry_decreaseUseCount(bndEntry);
+    fw_bundleEntry_destroy(bndEntry, true); //wait till use count is 0 -> e.g. not used
 
-    } else {
-        return CELIX_ILLEGAL_STATE;
+    if (status == CELIX_SUCCESS) {
+        celix_framework_waitForEmptyEventQueue(framework); //to ensure that the uninstall event is triggered and handled
+        (void)bundle_closeModules(bnd);
+        (void)bundle_destroy(bnd);
+        (void)bundleArchive_destroy(archive);
     }
+    framework_logIfError(framework->logger, status, "", "Cannot uninstall bundle");
+    return status;
 }
 
 static bool celix_framework_stopBundleInternal(celix_framework_t* fw, long bndId, bool forcedAsync) {
@@ -1962,9 +1965,7 @@ void celix_framework_stopBundleAsync(celix_framework_t* fw, long bndId) {
     celix_framework_stopBundleInternal(fw, bndId, true);
 }
 
-celix_status_t celix_framework_stopBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) {
-    assert(!celix_framework_isCurrentThreadTheEventLoop(framework));
-
+static celix_status_t celix_framework_stopBundleEntryInternal(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) {
     celix_bundle_activator_t *activator = NULL;
     bundle_context_t *context = NULL;
     bool wasActive = false;
@@ -1973,28 +1974,28 @@ celix_status_t celix_framework_stopBundleEntry(celix_framework_t* framework, cel
     celix_status_t status = CELIX_SUCCESS;
     celix_bundle_state_e state = celix_bundle_getState(bndEntry->bnd);
     switch (state) {
-        case CELIX_BUNDLE_STATE_UNKNOWN:
-            status = CELIX_ILLEGAL_STATE;
-            error = "state is unknown";
-            break;
-        case CELIX_BUNDLE_STATE_UNINSTALLED:
-            status = CELIX_ILLEGAL_STATE;
-            error = "bundle is uninstalled";
-            break;
-        case CELIX_BUNDLE_STATE_STARTING:
-            status = CELIX_BUNDLE_EXCEPTION;
-            error = "bundle is starting";
-            break;
-        case CELIX_BUNDLE_STATE_STOPPING:
-            status = CELIX_BUNDLE_EXCEPTION;
-            error = "bundle is stopping";
-            break;
-        case CELIX_BUNDLE_STATE_INSTALLED:
-        case CELIX_BUNDLE_STATE_RESOLVED:
-            break;
-        case CELIX_BUNDLE_STATE_ACTIVE:
-            wasActive = true;
-            break;
+    case CELIX_BUNDLE_STATE_UNKNOWN:
+        status = CELIX_ILLEGAL_STATE;
+        error = "state is unknown";
+        break;
+    case CELIX_BUNDLE_STATE_UNINSTALLED:
+        status = CELIX_ILLEGAL_STATE;
+        error = "bundle is uninstalled";
+        break;
+    case CELIX_BUNDLE_STATE_STARTING:
+        status = CELIX_BUNDLE_EXCEPTION;
+        error = "bundle is starting";
+        break;
+    case CELIX_BUNDLE_STATE_STOPPING:
+        status = CELIX_BUNDLE_EXCEPTION;
+        error = "bundle is stopping";
+        break;
+    case CELIX_BUNDLE_STATE_INSTALLED:
+    case CELIX_BUNDLE_STATE_RESOLVED:
+        break;
+    case CELIX_BUNDLE_STATE_ACTIVE:
+        wasActive = true;
+        break;
     }
 
 
@@ -2069,7 +2070,15 @@ celix_status_t celix_framework_stopBundleEntry(celix_framework_t* framework, cel
     } else {
         fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED, bndEntry);
     }
+    return status;
+}
 
+celix_status_t celix_framework_stopBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) {
+    celix_status_t status = CELIX_SUCCESS;
+    assert(!celix_framework_isCurrentThreadTheEventLoop(framework));
+    celixThreadRwlock_writeLock(&bndEntry->fsmMutex);
+    status = celix_framework_stopBundleEntryInternal(framework, bndEntry);
+    celixThreadRwlock_unlock(&bndEntry->fsmMutex);
     return status;
 }
 
@@ -2106,6 +2115,7 @@ celix_status_t celix_framework_startBundleEntry(celix_framework_t* framework, ce
     celix_bundle_context_t* context = NULL;
     celix_bundle_activator_t* activator = NULL;
 
+    celixThreadRwlock_writeLock(&bndEntry->fsmMutex);
     celix_bundle_state_e state = celix_bundle_getState(bndEntry->bnd);
 
     switch (state) {
@@ -2133,7 +2143,7 @@ celix_status_t celix_framework_startBundleEntry(celix_framework_t* framework, ce
             if (!module_isResolved(module)) {
                 wires = resolver_resolve(module);
                 if (wires == NULL) {
-                    celix_framework_bundleEntry_decreaseUseCount(bndEntry);
+                    celixThreadRwlock_unlock(&bndEntry->fsmMutex);
                     return CELIX_BUNDLE_EXCEPTION;
                 }
                 status = framework_markResolvedModules(framework, wires);
@@ -2217,7 +2227,7 @@ celix_status_t celix_framework_startBundleEntry(celix_framework_t* framework, ce
             fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not start bundle: %s [%ld]", symbolicName, id);
         }
     }
-
+    celixThreadRwlock_unlock(&bndEntry->fsmMutex);
     return status;
 }
 
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index e1da3589..3d98c3d8 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -51,6 +51,7 @@
 
 typedef struct celix_framework_bundle_entry {
     celix_bundle_t *bnd;
+    celix_thread_rwlock_t fsmMutex; //protects bundle state transition
     long bndId;
 
     celix_thread_mutex_t useMutex; //protects useCount


[celix] 04/08: Add support for bundle unload.

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 6008b3d734a204711b98c4b588bcd51dfa0b2384
Author: PengZheng <ho...@gmail.com>
AuthorDate: Thu Jun 1 21:40:26 2023 +0800

    Add support for bundle unload.
    
    Unloading a bundle from a framework instance will release all its resources but leave the bundle in cache so that it can be reloaded using `install`.
---
 bundles/shell/shell/CMakeLists.txt                 |  1 +
 bundles/shell/shell/gtest/src/ShellTestSuite.cc    |  3 +
 bundles/shell/shell/src/std_commands.c             |  9 ++-
 bundles/shell/shell/src/std_commands.h             |  2 +
 bundles/shell/shell/src/unload_command.c           | 24 +++++++
 .../src/CelixBundleContextBundlesTestSuite.cc      | 82 +++++++++++++++++++++-
 .../framework/gtest/src/CelixFrameworkTestSuite.cc |  9 +++
 libs/framework/include/celix_bundle_context.h      | 16 +++++
 libs/framework/include/celix_framework.h           | 22 ++++++
 libs/framework/src/bundle.c                        |  4 +-
 libs/framework/src/bundle_context.c                |  4 ++
 libs/framework/src/framework.c                     | 16 +++--
 .../src/framework_bundle_lifecycle_handler.c       | 14 ++--
 libs/framework/src/framework_private.h             |  6 +-
 14 files changed, 195 insertions(+), 17 deletions(-)

diff --git a/bundles/shell/shell/CMakeLists.txt b/bundles/shell/shell/CMakeLists.txt
index a07c76b6..34914da8 100644
--- a/bundles/shell/shell/CMakeLists.txt
+++ b/bundles/shell/shell/CMakeLists.txt
@@ -41,6 +41,7 @@ if (SHELL)
 			src/install_command.c
 			src/update_command.c
 			src/uninstall_command.c
+			src/unload_command.c
 			src/help_command.c
 			src/dm_shell_list_command.c
 			src/query_command.c
diff --git a/bundles/shell/shell/gtest/src/ShellTestSuite.cc b/bundles/shell/shell/gtest/src/ShellTestSuite.cc
index 36d1f9c2..4117f0ad 100644
--- a/bundles/shell/shell/gtest/src/ShellTestSuite.cc
+++ b/bundles/shell/shell/gtest/src/ShellTestSuite.cc
@@ -104,11 +104,14 @@ TEST_F(ShellTestSuite, testAllCommandsAreCallable) {
     callCommand(ctx, "start", false); // incorrect number of arguments
     callCommand(ctx, "uninstall not-a-number", false);
     callCommand(ctx, "uninstall", false); // incorrect number of arguments
+    callCommand(ctx, "unload not-a-number", false);
+    callCommand(ctx, "unload", false); // incorrect number of arguments
     callCommand(ctx, "update not-a-number", false);
     callCommand(ctx, "update", false); // incorrect number of arguments
     callCommand(ctx, "stop 15", false); //non existing bundle id
     callCommand(ctx, "start 15", false); //non existing bundle id
     callCommand(ctx, "uninstall 15", false); //non existing bundle id
+    callCommand(ctx, "unload 15", false); //non existing bundle id
     callCommand(ctx, "update 15", false); //non existing bundle id
 }
 
diff --git a/bundles/shell/shell/src/std_commands.c b/bundles/shell/shell/src/std_commands.c
index dd3934ad..8edbf092 100644
--- a/bundles/shell/shell/src/std_commands.c
+++ b/bundles/shell/shell/src/std_commands.c
@@ -82,7 +82,7 @@ celix_std_commands_t* celix_stdCommands_create(celix_bundle_context_t* ctx) {
                     .exec = uninstallCommand_execute,
                     .name = "celix::uninstall",
                     .description = "uninstall bundle(s).",
-                    .usage = "uninstall <file> [<file> ...]"
+                    .usage = "uninstall <id> [<id> ...]"
             };
     commands->std_commands[5] =
             (struct celix_shell_command_register_entry) {
@@ -133,6 +133,13 @@ celix_std_commands_t* celix_stdCommands_create(celix_bundle_context_t* ctx) {
                     .usage = "quit"
             };
     commands->std_commands[11] =
+        (struct celix_shell_command_register_entry) {
+            .exec = unloadCommand_execute,
+            .name = "celix::unload",
+            .description = "unload bundle(s).",
+            .usage = "unload <id> [<id> ...]"
+        };
+    commands->std_commands[12] =
             (struct celix_shell_command_register_entry) {
                     .exec = NULL
             };
diff --git a/bundles/shell/shell/src/std_commands.h b/bundles/shell/shell/src/std_commands.h
index 6c0a8d06..a2be1070 100644
--- a/bundles/shell/shell/src/std_commands.h
+++ b/bundles/shell/shell/src/std_commands.h
@@ -48,6 +48,8 @@ bool installCommand_execute(void *handle, const char *commandLine, FILE *outStre
 
 bool uninstallCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream);
 
+bool unloadCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream);
+
 bool updateCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream);
 
 bool helpCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream);
diff --git a/bundles/shell/shell/src/unload_command.c b/bundles/shell/shell/src/unload_command.c
new file mode 100644
index 00000000..b27a37e1
--- /dev/null
+++ b/bundles/shell/shell/src/unload_command.c
@@ -0,0 +1,24 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+ */
+
+#include "bundle_command.h"
+
+bool unloadCommand_execute(void *handle, const char* constCommandLine, FILE *outStream, FILE *errStream) {
+    return bundleCommand_execute(handle, constCommandLine, outStream, errStream, celix_framework_unloadBundleAsync);
+}
diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
index e6213766..f7672087 100644
--- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
@@ -203,11 +203,87 @@ TEST_F(CelixBundleContextBundlesTestSuite, InstallAndUninstallBundlesTest) {
     long bndId6 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
 
     ASSERT_TRUE(bndId4 >= 0L);
-    ASSERT_FALSE(bndId1 == bndId4); //bundle cache -> reuse of bundle id.
+    ASSERT_FALSE(bndId1 == bndId4);
     ASSERT_TRUE(bndId5 >= 0L);
-    ASSERT_FALSE(bndId2 == bndId5); //bundle cache -> reuse of bundle id.
+    ASSERT_FALSE(bndId2 == bndId5);
     ASSERT_TRUE(bndId6 >= 0L);
-    ASSERT_FALSE(bndId3 == bndId6); //bundle cache -> reuse of bundle id.
+    ASSERT_FALSE(bndId3 == bndId6);
+}
+
+TEST_F(CelixBundleContextBundlesTestSuite, InstallAndUnloadBundlesTest) {
+    //install bundles
+    long bndId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
+    long bndId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false);
+    long bndId3 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
+
+    ASSERT_TRUE(bndId1 >= 0L);
+    ASSERT_TRUE(bndId2 >= 0L);
+    ASSERT_TRUE(bndId3 >= 0L);
+
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
+
+    ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId1));
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2)); //not auto started
+    ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId3));
+
+    char *bndRoot1 = nullptr;
+    ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId1, &bndRoot1, [](void* handle, const celix_bundle_t* bnd) {
+      char **root = static_cast<char **>(handle);
+      *root = celix_bundle_getEntry(bnd, "/");
+    }));
+    ASSERT_TRUE(bndRoot1 != nullptr);
+    char* bndRoot2 = nullptr;
+    ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId2, &bndRoot2, [](void* handle, const celix_bundle_t* bnd) {
+      char **root = static_cast<char **>(handle);
+      *root = celix_bundle_getEntry(bnd, "/");
+    }));
+    ASSERT_TRUE(bndRoot2 != nullptr);
+    char* bndRoot3 = nullptr;
+    ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId3, &bndRoot3, [](void* handle, const celix_bundle_t* bnd) {
+      char **root = static_cast<char **>(handle);
+      *root = celix_bundle_getEntry(bnd, "/");
+    }));
+    ASSERT_TRUE(bndRoot3 != nullptr);
+
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot1));
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot2));
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot3));
+
+    //unload bundles
+    ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId2));
+    ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId3));
+
+    ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
+    ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
+
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId1)); //not uninstall -> not active
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2));
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId3));
+
+    // bundle cache is NOT cleaned up
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot1));
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot2));
+    ASSERT_TRUE(celix_utils_directoryExists(bndRoot3));
+
+    free(bndRoot1);
+    free(bndRoot2);
+    free(bndRoot3);
+
+    //reinstall bundles
+    long bndId4 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
+    long bndId5 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false);
+    long bndId6 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
+
+    ASSERT_TRUE(bndId4 >= 0L);
+    ASSERT_TRUE(bndId1 == bndId4); //bundle cache -> reuse of bundle id.
+    ASSERT_TRUE(bndId5 >= 0L);
+    ASSERT_TRUE(bndId2 == bndId5); //bundle cache -> reuse of bundle id.
+    ASSERT_TRUE(bndId6 >= 0L);
+    ASSERT_TRUE(bndId3 == bndId6); //bundle cache -> reuse of bundle id.
 }
 
 TEST_F(CelixBundleContextBundlesTestSuite, StartBundleWithException) {
diff --git a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc
index 1a3562c1..89c20f61 100644
--- a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc
+++ b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc
@@ -93,6 +93,15 @@ TEST_F(CelixFrameworkTestSuite, AsyncInstallStartStopAndUninstallBundleTest) {
     std::this_thread::sleep_for(std::chrono::milliseconds{100});
     EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId));
 
+    celix_framework_unloadBundleAsync(framework.get(), bndId);
+    std::this_thread::sleep_for(std::chrono::milliseconds{100});
+    EXPECT_FALSE(celix_framework_isBundleInstalled(framework.get(), bndId));
+
+    // reloaded bundle should reuse the same bundle id
+    EXPECT_EQ(bndId, celix_framework_installBundleAsync(framework.get(), SIMPLE_TEST_BUNDLE1_LOCATION, false));
+    EXPECT_TRUE(celix_framework_isBundleInstalled(framework.get(), bndId));
+    EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId));
+
     celix_framework_uninstallBundleAsync(framework.get(), bndId);
     std::this_thread::sleep_for(std::chrono::milliseconds{100});
     EXPECT_FALSE(celix_framework_isBundleInstalled(framework.get(), bndId));
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index 8b1ef2bc..fc73b180 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -905,6 +905,22 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_installBundle(celix_bundle_conte
  */
 CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_uninstallBundle(celix_bundle_context_t *ctx, long bndId);
 
+/**
+ * @brief Unload the bundle with the provided bundle id. If needed the bundle will be stopped first.
+ * Will silently ignore bundle ids < 0.
+ * Note that unloaded bundle is kept in bundle cache and can be reloaded with the celix_bundleContext_installBundle function.
+ *
+ * If this function is called on the Celix event thread, the actual stopping of the bundle will be done async and
+ * on a separate thread.
+ * If this function is called from a different thread than the Celix event thread, then the function will return after
+ * the bundle is stopped.
+ *
+ * @param ctx The bundle context
+ * @param bndId The bundle id to unload.
+ * @return true if the bundle is correctly unloaded. False if not.
+ */
+CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_unloadBundle(celix_bundle_context_t *ctx, long bndId);
+
 /**
  * @brief Stop the bundle with the provided bundle id.
  * Will silently ignore bundle ids < 0.
diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h
index e5beb0d2..2bfbd114 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -138,6 +138,17 @@ CELIX_FRAMEWORK_EXPORT long celix_framework_installBundle(celix_framework_t *fw,
  */
 CELIX_FRAMEWORK_EXPORT bool celix_framework_uninstallBundle(celix_framework_t *fw, long bndId);
 
+/**
+ * @brief Unload the bundle with the provided bundle id. If needed the bundle will be stopped first.
+ * Will silently ignore bundle ids < 0.
+ * Note that unloaded bundle is kept in bundle cache and can be reloaded with the celix_framework_installBundle function.
+ *
+ * @param fw The Celix framework
+ * @param bndId The bundle id to unload.
+ * @return true if the bundle is correctly unloaded. False if not.
+ */
+CELIX_FRAMEWORK_EXPORT bool celix_framework_unloadBundle(celix_framework_t *fw, long bndId);
+
 /**
  * @brief Update the bundle with the provided bundle id.
  *
@@ -221,6 +232,17 @@ CELIX_FRAMEWORK_EXPORT void celix_framework_updateBundleAsync(celix_framework_t
  */
 CELIX_FRAMEWORK_EXPORT void celix_framework_uninstallBundleAsync(celix_framework_t *fw, long bndId);
 
+/**
+ * @brief Unload the bundle with the provided bundle id async. If needed the bundle will be stopped first.
+ * Will silently ignore bundle ids < 0.
+ * Note that unloaded bundle is kept in bundle cache and can be reloaded with the celix_framework_installBundle function.
+ * The bundle will be unloaded on a separate spawned thread.
+ *
+ * @param fw The Celix framework
+ * @param bndId The bundle id to unload.
+ */
+CELIX_FRAMEWORK_EXPORT void celix_framework_unloadBundleAsync(celix_framework_t *fw, long bndId);
+
 /**
  * @brief Stop the bundle with the provided bundle id async.
  * Will silently ignore bundle ids < 0.
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c
index 7f08f15e..64eaa241 100644
--- a/libs/framework/src/bundle.c
+++ b/libs/framework/src/bundle.c
@@ -238,8 +238,8 @@ celix_status_t bundle_update(bundle_pt bundle, const char* updatedBundleUrl) {
 }
 
 celix_status_t bundle_stop(bundle_pt bundle) {
-    //note deprecated call use celix_bundleContext_startBundle instead
-    return celix_framework_startBundle(bundle->framework, celix_bundle_getId(bundle));
+    //note deprecated call use celix_bundleContext_stopBundle instead
+    return celix_framework_stopBundle(bundle->framework, celix_bundle_getId(bundle));
 }
 
 celix_status_t bundle_uninstall(bundle_pt bundle) {
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 8a802b7c..b3f70232 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -995,6 +995,10 @@ bool celix_bundleContext_uninstallBundle(bundle_context_t *ctx, long bndId) {
     return celix_framework_uninstallBundle(ctx->framework, bndId);
 }
 
+bool celix_bundleContext_unloadBundle(celix_bundle_context_t *ctx, long bndId) {
+    return celix_framework_unloadBundle(ctx->framework, bndId);
+}
+
 bool celix_bundleContext_useServiceWithId(
         bundle_context_t *ctx,
         long serviceId,
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 823d3d19..8671abac 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -1872,11 +1872,11 @@ long celix_framework_installBundleAsync(celix_framework_t *fw, const char *bundl
     return celix_framework_installAndStartBundleInternal(fw, bundleLoc, autoStart, true);
 }
 
-static bool celix_framework_uninstallBundleInternal(celix_framework_t *fw, long bndId, bool forcedAsync) {
+static bool celix_framework_uninstallBundleInternal(celix_framework_t *fw, long bndId, bool forcedAsync, bool permanent) {
     bool uninstalled = false;
     celix_framework_bundle_entry_t *bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId);
     if (bndEntry != NULL) {
-        celix_status_t status = celix_framework_uninstallBundleOnANonCelixEventThread(fw, bndEntry, forcedAsync);
+        celix_status_t status = celix_framework_uninstallBundleOnANonCelixEventThread(fw, bndEntry, forcedAsync, permanent);
         celix_framework_waitForBundleEvents(fw, bndId);
         //note not decreasing bndEntry, because this entry should now be deleted (uninstalled)
         uninstalled = status == CELIX_SUCCESS;
@@ -1885,11 +1885,19 @@ static bool celix_framework_uninstallBundleInternal(celix_framework_t *fw, long
 }
 
 bool celix_framework_uninstallBundle(celix_framework_t *fw, long bndId) {
-    return celix_framework_uninstallBundleInternal(fw, bndId, false);
+    return celix_framework_uninstallBundleInternal(fw, bndId, false, true);
 }
 
 void celix_framework_uninstallBundleAsync(celix_framework_t *fw, long bndId) {
-    celix_framework_uninstallBundleInternal(fw, bndId, true);
+    celix_framework_uninstallBundleInternal(fw, bndId, true, true);
+}
+
+bool celix_framework_unloadBundle(celix_framework_t *fw, long bndId) {
+    return celix_framework_uninstallBundleInternal(fw, bndId, false, false);
+}
+
+void celix_framework_unloadBundleAsync(celix_framework_t *fw, long bndId) {
+    celix_framework_uninstallBundleInternal(fw, bndId, true, false);
 }
 
 celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry, bool permanent) {
diff --git a/libs/framework/src/framework_bundle_lifecycle_handler.c b/libs/framework/src/framework_bundle_lifecycle_handler.c
index 669778d8..6ffa9bb3 100644
--- a/libs/framework/src/framework_bundle_lifecycle_handler.c
+++ b/libs/framework/src/framework_bundle_lifecycle_handler.c
@@ -49,11 +49,15 @@ static void* celix_framework_BundleLifecycleHandlingThread(void *data) {
             celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
             celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, true);
             break;
+        case CELIX_BUNDLE_LIFECYCLE_UNLOAD:
+            celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
+            celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, false);
+            break;
         default: //update
             celix_framework_updateBundleEntry(handler->framework, handler->bndEntry, handler->updatedBundleUrl);
             break;
     }
-    if (handler->command != CELIX_BUNDLE_LIFECYCLE_UNINSTALL) {
+    if (handler->command != CELIX_BUNDLE_LIFECYCLE_UNINSTALL && handler->command != CELIX_BUNDLE_LIFECYCLE_UNLOAD) {
         celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
     }
     celix_framework_cleanupBundleLifecycleHandler(handler->framework, handler);
@@ -132,18 +136,18 @@ celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_
     }
 }
 
-celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread) {
+celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent) {
     if (forceSpawnThread) {
         fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "uninstall bundle from a separate thread");
-        celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_UNINSTALL, NULL);
+        celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, permanent ? CELIX_BUNDLE_LIFECYCLE_UNINSTALL : CELIX_BUNDLE_LIFECYCLE_UNLOAD, NULL);
         return CELIX_SUCCESS;
     } else if (celix_framework_isCurrentThreadTheEventLoop(fw)) {
         fw_log(fw->logger, CELIX_LOG_LEVEL_DEBUG,
                "Cannot uninstall bundle from Celix event thread. Using a separate thread to uninstall bundle. See celix_bundleContext_uninstall Bundle for more info.");
-        celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_UNINSTALL, NULL);
+        celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, permanent ? CELIX_BUNDLE_LIFECYCLE_UNINSTALL : CELIX_BUNDLE_LIFECYCLE_UNLOAD, NULL);
         return CELIX_SUCCESS;
     } else {
-        return celix_framework_uninstallBundleEntry(fw, bndEntry, true);
+        return celix_framework_uninstallBundleEntry(fw, bndEntry, permanent);
     }
 }
 
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index f2944cac..c506e94b 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -113,7 +113,8 @@ enum celix_bundle_lifecycle_command {
     CELIX_BUNDLE_LIFECYCLE_START,
     CELIX_BUNDLE_LIFECYCLE_STOP,
     CELIX_BUNDLE_LIFECYCLE_UNINSTALL,
-    CELIX_BUNDLE_LIFECYCLE_UPDATE
+    CELIX_BUNDLE_LIFECYCLE_UPDATE,
+    CELIX_BUNDLE_LIFECYCLE_UNLOAD
 };
 
 typedef struct celix_framework_bundle_lifecycle_handler {
@@ -396,9 +397,10 @@ celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_
  * @param fw The Celix framework
  * @param bndEntry A bnd entry
  * @param forceSpawnThread If the true, the start bundle will always be done on a spawn thread
+ * @param permanent If true, the bundle will be permanently uninstalled (e.g. the bundle archive will be removed).
  * @return CELIX_SUCCESS of the call went alright.
  */
-celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread);
+celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent);
 
 /**
  * Update (and if needed stop and start) a bundle and ensure that this is not done on the Celix event thread.


[celix] 05/08: Update all bundle activator to use async service registration.

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 27383f6c7f7fe8b519bb9ebb9e6f6dc338294970
Author: PengZheng <ho...@gmail.com>
AuthorDate: Fri Jun 2 11:40:51 2023 +0800

    Update all bundle activator to use async service registration.
---
 bundles/http_admin/gtest/src/sut_activator.c                 |  8 ++++----
 bundles/http_admin/http_admin/src/http_admin.c               |  2 +-
 bundles/pubsub/integration/gtest/loopback_activator.c        |  2 +-
 bundles/pubsub/integration/gtest/tst_endpoint_activator.c    |  4 ++--
 bundles/pubsub/pubsub_admin_tcp/src/psa_activator.c          | 12 ++++++------
 bundles/pubsub/pubsub_admin_udp_mc/src/psa_activator.c       |  4 ++--
 bundles/pubsub/pubsub_admin_websocket/src/psa_activator.c    |  4 ++--
 .../src/pubsub_websocket_topic_receiver.c                    |  4 ++--
 .../src/pubsub_websocket_topic_sender.c                      |  4 ++--
 bundles/pubsub/pubsub_admin_zmq/src/psa_activator.c          |  4 ++--
 bundles/pubsub/pubsub_discovery/src/psd_activator.c          |  4 ++--
 .../pubsub_protocol_wire_v1/src/ps_wire_protocol_activator.c |  2 +-
 .../src/ps_wire_v2_protocol_activator.c                      |  2 +-
 .../src/ps_avrobin_serializer_activator.c                    |  2 +-
 .../src/ps_json_serializer_activator.c                       |  2 +-
 bundles/pubsub/pubsub_topology_manager/src/pstm_activator.c  |  4 ++--
 .../examples/calculator_service/src/calculator_activator.c   |  2 +-
 .../calculator_shell/src/calculator_shell_activator.c        |  6 +++---
 .../remote_example_service/src/remote_example_activator.c    |  2 +-
 .../remote_example_service/src/remote_example_impl.c         |  2 +-
 .../remote_service_admin_dfi/gtest/src/tst_activator.c       |  2 +-
 .../src/remote_service_admin_activator.c                     |  2 +-
 bundles/shell/shell_wui/src/shell_wui_bundle_activator.c     |  2 +-
 .../http_example/src/http_example_bundle_activator.c         |  2 +-
 .../services_example_c/src/simple_provider_example.c         |  2 +-
 .../celix-examples/track_tracker_example/src/activator.c     |  2 +-
 26 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/bundles/http_admin/gtest/src/sut_activator.c b/bundles/http_admin/gtest/src/sut_activator.c
index 2c15da49..c35256cd 100644
--- a/bundles/http_admin/gtest/src/sut_activator.c
+++ b/bundles/http_admin/gtest/src/sut_activator.c
@@ -45,23 +45,23 @@ celix_status_t bnd_start(struct activator *act, celix_bundle_context_t *ctx) {
     celix_properties_set(props, HTTP_ADMIN_URI, "/alias");
     act->httpSvc.handle = act;
     act->httpSvc.doPut = alias_test_put;
-    act->httpSvcId = celix_bundleContext_registerService(ctx, &act->httpSvc, HTTP_ADMIN_SERVICE_NAME, props);
+    act->httpSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->httpSvc, HTTP_ADMIN_SERVICE_NAME, props);
 
     celix_properties_t *props2 = celix_properties_create();
     celix_properties_set(props2, HTTP_ADMIN_URI, "/foo/bar");
     act->httpSvc2.handle = act;
-    act->httpSvcId2 = celix_bundleContext_registerService(ctx, &act->httpSvc2, HTTP_ADMIN_SERVICE_NAME, props2);
+    act->httpSvcId2 = celix_bundleContext_registerServiceAsync(ctx, &act->httpSvc2, HTTP_ADMIN_SERVICE_NAME, props2);
 
     celix_properties_t *props3 = celix_properties_create();
     celix_properties_set(props3, HTTP_ADMIN_URI, "/");
     act->httpSvc3.handle = act;
-    act->httpSvcId3 = celix_bundleContext_registerService(ctx, &act->httpSvc3, HTTP_ADMIN_SERVICE_NAME, props3);
+    act->httpSvcId3 = celix_bundleContext_registerServiceAsync(ctx, &act->httpSvc3, HTTP_ADMIN_SERVICE_NAME, props3);
 
     celix_properties_t *props4 = celix_properties_create();
     celix_properties_set(props4, WEBSOCKET_ADMIN_URI, "/");
     act->sockSvc.handle = act;
     act->sockSvc.data = websocket_data_echo;
-    act->sockSvcId = celix_bundleContext_registerService(ctx, &act->sockSvc, WEBSOCKET_ADMIN_SERVICE_NAME, props4);
+    act->sockSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->sockSvc, WEBSOCKET_ADMIN_SERVICE_NAME, props4);
 
     return CELIX_SUCCESS;
 }
diff --git a/bundles/http_admin/http_admin/src/http_admin.c b/bundles/http_admin/http_admin/src/http_admin.c
index b28f7e44..e20060da 100755
--- a/bundles/http_admin/http_admin/src/http_admin.c
+++ b/bundles/http_admin/http_admin/src/http_admin.c
@@ -374,7 +374,7 @@ static void httpAdmin_updateInfoSvc(http_admin_manager_t *admin) {
     if (resources_urls_size > 1) {
         celix_properties_set(properties, HTTP_ADMIN_INFO_RESOURCE_URLS, resources_urls);
     }
-    admin->infoSvcId = celix_bundleContext_registerService(admin->context, &admin->infoSvc, HTTP_ADMIN_INFO_SERVICE_NAME, properties);
+    admin->infoSvcId = celix_bundleContext_registerServiceAsync(admin->context, &admin->infoSvc, HTTP_ADMIN_INFO_SERVICE_NAME, properties);
 
     celixThreadMutex_unlock(&admin->admin_lock);
 
diff --git a/bundles/pubsub/integration/gtest/loopback_activator.c b/bundles/pubsub/integration/gtest/loopback_activator.c
index c718c4a7..a9d819c0 100644
--- a/bundles/pubsub/integration/gtest/loopback_activator.c
+++ b/bundles/pubsub/integration/gtest/loopback_activator.c
@@ -58,7 +58,7 @@ celix_status_t bnd_start(struct activator *act, celix_bundle_context_t *ctx) {
   celix_properties_set(props, PUBSUB_SUBSCRIBER_TOPIC, "pong2");
   act->subSvc.handle = act;
   act->subSvc.receive = tst_receive;
-  act->subSvcId = celix_bundleContext_registerService(ctx, &act->subSvc, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
+  act->subSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->subSvc, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
 
 
 	return CELIX_SUCCESS;
diff --git a/bundles/pubsub/integration/gtest/tst_endpoint_activator.c b/bundles/pubsub/integration/gtest/tst_endpoint_activator.c
index e01a8ea8..bd8a23a6 100644
--- a/bundles/pubsub/integration/gtest/tst_endpoint_activator.c
+++ b/bundles/pubsub/integration/gtest/tst_endpoint_activator.c
@@ -51,14 +51,14 @@ celix_status_t bnd_start(struct activator *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, PUBSUB_SUBSCRIBER_TOPIC, "pong3");
         act->subSvc.handle = act;
         act->subSvc.receive = tst_receive;
-        act->subSvcId = celix_bundleContext_registerService(ctx, &act->subSvc, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
+        act->subSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->subSvc, PUBSUB_SUBSCRIBER_SERVICE_NAME, props);
     }
 
 
     {
         act->countSvc.handle = act;
         act->countSvc.receiveCount = tst_count;
-        act->countSvcId = celix_bundleContext_registerService(ctx, &act->countSvc, CELIX_RECEIVE_COUNT_SERVICE_NAME, NULL);
+        act->countSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->countSvc, CELIX_RECEIVE_COUNT_SERVICE_NAME, NULL);
     }
 
 
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/psa_activator.c b/bundles/pubsub/pubsub_admin_tcp/src/psa_activator.c
index 008cb7ce..cc13d703 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/psa_activator.c
+++ b/bundles/pubsub/pubsub_admin_tcp/src/psa_activator.c
@@ -83,7 +83,7 @@ int psa_tcp_start(psa_tcp_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_t *props = celix_properties_create();
         celix_properties_set(props, PUBSUB_ADMIN_SERVICE_TYPE, PUBSUB_TCP_ADMIN_TYPE);
 
-        act->adminSvcId = celix_bundleContext_registerService(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
+        act->adminSvcId = celix_bundleContext_registerServiceAsync(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
     }
 
     if (status == CELIX_SUCCESS) {
@@ -94,10 +94,10 @@ int psa_tcp_start(psa_tcp_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, PUBSUB_ADMIN_SERVICE_TYPE, PUBSUB_TCP_ADMIN_TYPE);
 
         act->adminMetricsSvcId =
-            celix_bundleContext_registerService(ctx,
-                                                &act->adminMetricsService,
-                                                PUBSUB_ADMIN_METRICS_SERVICE_NAME,
-                                                props);
+            celix_bundleContext_registerServiceAsync(ctx,
+                                                     &act->adminMetricsService,
+                                                     PUBSUB_ADMIN_METRICS_SERVICE_NAME,
+                                                     props);
     }
 
     //register shell command service
@@ -108,7 +108,7 @@ int psa_tcp_start(psa_tcp_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "celix::psa_tcp");
         celix_properties_set(props, CELIX_SHELL_COMMAND_USAGE, "psa_tcp");
         celix_properties_set(props, CELIX_SHELL_COMMAND_DESCRIPTION, "Print the information about the TopicSender and TopicReceivers for the TCP PSA");
-        act->cmdSvcId = celix_bundleContext_registerService(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+        act->cmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
     }
 
     return status;
diff --git a/bundles/pubsub/pubsub_admin_udp_mc/src/psa_activator.c b/bundles/pubsub/pubsub_admin_udp_mc/src/psa_activator.c
index 0cc543c5..e9058a3a 100644
--- a/bundles/pubsub/pubsub_admin_udp_mc/src/psa_activator.c
+++ b/bundles/pubsub/pubsub_admin_udp_mc/src/psa_activator.c
@@ -80,7 +80,7 @@ int psa_udpmc_start(psa_udpmc_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_t *props = celix_properties_create();
         celix_properties_set(props, PUBSUB_ADMIN_SERVICE_TYPE, PUBSUB_UDPMC_ADMIN_TYPE);
 
-        act->adminSvcId = celix_bundleContext_registerService(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
+        act->adminSvcId = celix_bundleContext_registerServiceAsync(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
     }
 
     //register shell command service
@@ -91,7 +91,7 @@ int psa_udpmc_start(psa_udpmc_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "celix::psa_udpmc");
         celix_properties_set(props, CELIX_SHELL_COMMAND_USAGE, "psa_udpmc");
         celix_properties_set(props, CELIX_SHELL_COMMAND_DESCRIPTION, "Print the information about the TopicSender and TopicReceivers for the UDPMC PSA");
-        act->cmdSvcId = celix_bundleContext_registerService(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+        act->cmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
     }
 
     return status;
diff --git a/bundles/pubsub/pubsub_admin_websocket/src/psa_activator.c b/bundles/pubsub/pubsub_admin_websocket/src/psa_activator.c
index 33cc86f3..2a41fa50 100644
--- a/bundles/pubsub/pubsub_admin_websocket/src/psa_activator.c
+++ b/bundles/pubsub/pubsub_admin_websocket/src/psa_activator.c
@@ -70,7 +70,7 @@ int psa_websocket_start(psa_websocket_activator_t *act, celix_bundle_context_t *
         celix_properties_t *props = celix_properties_create();
         celix_properties_set(props, PUBSUB_ADMIN_SERVICE_TYPE, PUBSUB_WEBSOCKET_ADMIN_TYPE);
 
-        act->adminSvcId = celix_bundleContext_registerService(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
+        act->adminSvcId = celix_bundleContext_registerServiceAsync(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
     }
 
     //register shell command service
@@ -81,7 +81,7 @@ int psa_websocket_start(psa_websocket_activator_t *act, celix_bundle_context_t *
         celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "celix::psa_websocket");
         celix_properties_set(props, CELIX_SHELL_COMMAND_USAGE, "psa_websocket");
         celix_properties_set(props, CELIX_SHELL_COMMAND_DESCRIPTION, "Print the information about the TopicSender and TopicReceivers for the websocket PSA");
-        act->cmdSvcId = celix_bundleContext_registerService(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+        act->cmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
     }
 
     return status;
diff --git a/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_receiver.c b/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_receiver.c
index e163a7ca..9dc5fd78 100644
--- a/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_receiver.c
+++ b/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_receiver.c
@@ -193,8 +193,8 @@ pubsub_websocket_topic_receiver_t* pubsub_websocketTopicReceiver_create(celix_bu
         receiver->sockSvc.ready = psa_websocketTopicReceiver_ready;
         receiver->sockSvc.data = psa_websocketTopicReceiver_data;
         receiver->sockSvc.close = psa_websocketTopicReceiver_close;
-        receiver->svcId = celix_bundleContext_registerService(receiver->ctx, &receiver->sockSvc,
-                                                           WEBSOCKET_ADMIN_SERVICE_NAME, props);
+        receiver->svcId = celix_bundleContext_registerServiceAsync(receiver->ctx, &receiver->sockSvc,
+                                                                   WEBSOCKET_ADMIN_SERVICE_NAME, props);
     }
 
     const char *staticConnects = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_WEBSOCKET_STATIC_CONNECT_SOCKET_ADDRESSES_FOR, topic, scope);
diff --git a/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_sender.c b/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_sender.c
index e8ab0623..eb1dc6b1 100644
--- a/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_sender.c
+++ b/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_topic_sender.c
@@ -115,8 +115,8 @@ pubsub_websocket_topic_sender_t* pubsub_websocketTopicSender_create(
         sender->websockSvc.handle = sender;
         sender->websockSvc.ready = psa_websocketTopicSender_ready;
         sender->websockSvc.close = psa_websocketTopicSender_close;
-        sender->websockSvcId = celix_bundleContext_registerService(ctx, &sender->websockSvc,
-                                                                   WEBSOCKET_ADMIN_SERVICE_NAME, props);
+        sender->websockSvcId = celix_bundleContext_registerServiceAsync(ctx, &sender->websockSvc,
+                                                                        WEBSOCKET_ADMIN_SERVICE_NAME, props);
     } else {
         sender->websockSvcId = -1;
     }
diff --git a/bundles/pubsub/pubsub_admin_zmq/src/psa_activator.c b/bundles/pubsub/pubsub_admin_zmq/src/psa_activator.c
index 913ad34d..3943ff78 100644
--- a/bundles/pubsub/pubsub_admin_zmq/src/psa_activator.c
+++ b/bundles/pubsub/pubsub_admin_zmq/src/psa_activator.c
@@ -84,7 +84,7 @@ int psa_zmq_start(psa_zmq_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_t *props = celix_properties_create();
         celix_properties_set(props, PUBSUB_ADMIN_SERVICE_TYPE, PUBSUB_ZMQ_ADMIN_TYPE);
 
-        act->adminSvcId = celix_bundleContext_registerService(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
+        act->adminSvcId = celix_bundleContext_registerServiceAsync(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
     }
 
     //register shell command service
@@ -95,7 +95,7 @@ int psa_zmq_start(psa_zmq_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "celix::psa_zmq");
         celix_properties_set(props, CELIX_SHELL_COMMAND_USAGE, "psa_zmq");
         celix_properties_set(props, CELIX_SHELL_COMMAND_DESCRIPTION, "Print the information about the TopicSender and TopicReceivers for the ZMQ PSA");
-        act->cmdSvcId = celix_bundleContext_registerService(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+        act->cmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
     }
 
     return status;
diff --git a/bundles/pubsub/pubsub_discovery/src/psd_activator.c b/bundles/pubsub/pubsub_discovery/src/psd_activator.c
index d19cb0f1..0aaa3593 100644
--- a/bundles/pubsub/pubsub_discovery/src/psd_activator.c
+++ b/bundles/pubsub/pubsub_discovery/src/psd_activator.c
@@ -76,11 +76,11 @@ static celix_status_t psd_start(psd_activator_t *act, celix_bundle_context_t *ct
         celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "celix::psd_etcd");
         celix_properties_set(props, CELIX_SHELL_COMMAND_USAGE, "psd_etcd");
         celix_properties_set(props, CELIX_SHELL_COMMAND_DESCRIPTION, "Overview of discovered/announced endpoints from/to ETCD");
-        act->cmdSvcId = celix_bundleContext_registerService(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+        act->cmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
     }
 
     if (status == CELIX_SUCCESS) {
-        act->listenerSvcId = celix_bundleContext_registerService(ctx, &act->listenerSvc, PUBSUB_ANNOUNCE_ENDPOINT_LISTENER_SERVICE, NULL);
+        act->listenerSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->listenerSvc, PUBSUB_ANNOUNCE_ENDPOINT_LISTENER_SERVICE, NULL);
     } else {
         act->listenerSvcId = -1L;
     }
diff --git a/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v1/src/ps_wire_protocol_activator.c b/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v1/src/ps_wire_protocol_activator.c
index 64abebec..03b130f8 100644
--- a/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v1/src/ps_wire_protocol_activator.c
+++ b/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v1/src/ps_wire_protocol_activator.c
@@ -57,7 +57,7 @@ static int ps_wp_start(ps_wp_activator_t *act, celix_bundle_context_t *ctx) {
         act->protocolSvc.decodeMetadata = pubsubProtocol_v1_decodeMetadata;
         act->protocolSvc.decodeFooter = pubsubProtocol_decodeFooter;
 
-        act->wireProtocolSvcId = celix_bundleContext_registerService(ctx, &act->protocolSvc, PUBSUB_PROTOCOL_SERVICE_NAME, props);
+        act->wireProtocolSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->protocolSvc, PUBSUB_PROTOCOL_SERVICE_NAME, props);
     }
     return status;
 }
diff --git a/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v2/src/ps_wire_v2_protocol_activator.c b/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v2/src/ps_wire_v2_protocol_activator.c
index 86708eba..0b884123 100644
--- a/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v2/src/ps_wire_v2_protocol_activator.c
+++ b/bundles/pubsub/pubsub_protocol/pubsub_protocol_wire_v2/src/ps_wire_v2_protocol_activator.c
@@ -58,7 +58,7 @@ static int ps_wp_start(ps_wp_activator_t *act, celix_bundle_context_t *ctx) {
         act->protocolSvc.decodeMetadata = pubsubProtocol_wire_v2_decodeMetadata;
         act->protocolSvc.decodeFooter = pubsubProtocol_wire_v2_decodeFooter;
 
-        act->wireProtocolSvcId = celix_bundleContext_registerService(ctx, &act->protocolSvc, PUBSUB_PROTOCOL_SERVICE_NAME, props);
+        act->wireProtocolSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->protocolSvc, PUBSUB_PROTOCOL_SERVICE_NAME, props);
     }
     return status;
 }
diff --git a/bundles/pubsub/pubsub_serializer_avrobin/src/ps_avrobin_serializer_activator.c b/bundles/pubsub/pubsub_serializer_avrobin/src/ps_avrobin_serializer_activator.c
index 275a72da..11cfe152 100644
--- a/bundles/pubsub/pubsub_serializer_avrobin/src/ps_avrobin_serializer_activator.c
+++ b/bundles/pubsub/pubsub_serializer_avrobin/src/ps_avrobin_serializer_activator.c
@@ -46,7 +46,7 @@ static int psav_start(psav_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_t *props = celix_properties_create();
         celix_properties_set(props, PUBSUB_SERIALIZER_TYPE_KEY, PUBSUB_AVROBIN_SERIALIZER_TYPE);
 
-        act->serializerSvcId = celix_bundleContext_registerService(ctx, &act->serializerSvc, PUBSUB_SERIALIZER_SERVICE_NAME, props);
+        act->serializerSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->serializerSvc, PUBSUB_SERIALIZER_SERVICE_NAME, props);
     }
     return status;
 }
diff --git a/bundles/pubsub/pubsub_serializer_json/src/ps_json_serializer_activator.c b/bundles/pubsub/pubsub_serializer_json/src/ps_json_serializer_activator.c
index 9df8e13f..afb62505 100644
--- a/bundles/pubsub/pubsub_serializer_json/src/ps_json_serializer_activator.c
+++ b/bundles/pubsub/pubsub_serializer_json/src/ps_json_serializer_activator.c
@@ -44,7 +44,7 @@ static int psjs_start(psjs_activator_t *act, celix_bundle_context_t *ctx) {
         /* Set serializer type */
         celix_properties_t *props = celix_properties_create();
         celix_properties_set(props, PUBSUB_SERIALIZER_TYPE_KEY, PUBSUB_JSON_SERIALIZER_TYPE);
-        act->serializerSvcId = celix_bundleContext_registerService(ctx, &act->serializerSvc, PUBSUB_SERIALIZER_SERVICE_NAME, props);
+        act->serializerSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->serializerSvc, PUBSUB_SERIALIZER_SERVICE_NAME, props);
 
     }
     return status;
diff --git a/bundles/pubsub/pubsub_topology_manager/src/pstm_activator.c b/bundles/pubsub/pubsub_topology_manager/src/pstm_activator.c
index 347d6471..1bdfc69f 100644
--- a/bundles/pubsub/pubsub_topology_manager/src/pstm_activator.c
+++ b/bundles/pubsub/pubsub_topology_manager/src/pstm_activator.c
@@ -118,7 +118,7 @@ static int pstm_start(pstm_activator_t *act, celix_bundle_context_t *ctx) {
         act->discListenerSvc.handle = act->manager;
         act->discListenerSvc.addDiscoveredEndpoint = pubsub_topologyManager_addDiscoveredEndpoint;
         act->discListenerSvc.removeDiscoveredEndpoint = pubsub_topologyManager_removeDiscoveredEndpoint;
-        act->discListenerSvcId = celix_bundleContext_registerService(ctx, &act->discListenerSvc, PUBSUB_DISCOVERED_ENDPOINT_LISTENER_SERVICE, NULL);
+        act->discListenerSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->discListenerSvc, PUBSUB_DISCOVERED_ENDPOINT_LISTENER_SERVICE, NULL);
     }
 
     //register shell command
@@ -129,7 +129,7 @@ static int pstm_start(pstm_activator_t *act, celix_bundle_context_t *ctx) {
         celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "celix::pstm");
         celix_properties_set(props, CELIX_SHELL_COMMAND_USAGE, "pstm [topology|metrics]"); //TODO add search topic/scope option
         celix_properties_set(props, CELIX_SHELL_COMMAND_DESCRIPTION, "pubsub_topology_info: Overview of Topology information for PubSub");
-        act->shellCmdSvcId = celix_bundleContext_registerService(ctx, &act->shellCmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+        act->shellCmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &act->shellCmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
     }
 
     //TODO add tracker for pubsub_serializer and
diff --git a/bundles/remote_services/examples/calculator_service/src/calculator_activator.c b/bundles/remote_services/examples/calculator_service/src/calculator_activator.c
index 261169e0..e39aa484 100644
--- a/bundles/remote_services/examples/calculator_service/src/calculator_activator.c
+++ b/bundles/remote_services/examples/calculator_service/src/calculator_activator.c
@@ -44,7 +44,7 @@ celix_status_t calculatorBndStart(struct activator *act, celix_bundle_context_t
         celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, CALCULATOR_SERVICE_VERSION);
         celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, CALCULATOR_CONFIGURATION_TYPE);
 
-        act->svcId = celix_bundleContext_registerService(ctx, &act->service, CALCULATOR_SERVICE, properties);
+        act->svcId = celix_bundleContext_registerServiceAsync(ctx, &act->service, CALCULATOR_SERVICE, properties);
     }
     return CELIX_SUCCESS;
 }
diff --git a/bundles/remote_services/examples/calculator_shell/src/calculator_shell_activator.c b/bundles/remote_services/examples/calculator_shell/src/calculator_shell_activator.c
index 31e5c49a..523dab09 100644
--- a/bundles/remote_services/examples/calculator_shell/src/calculator_shell_activator.c
+++ b/bundles/remote_services/examples/calculator_shell/src/calculator_shell_activator.c
@@ -42,19 +42,19 @@ static celix_status_t calcShell_start(calc_shell_activator_t *activator, celix_b
     activator->addCmd.executeCommand = addCommand_execute;
     celix_properties_t *props = celix_properties_create();
     celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "add");
-    activator->addCmdSvcId = celix_bundleContext_registerService(ctx, &activator->addCmd, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+    activator->addCmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &activator->addCmd, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
 
     activator->subCmd.handle = ctx;
     activator->subCmd.executeCommand = subCommand_execute;
     props = celix_properties_create();
     celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "sub");
-    activator->subCmdSvcId = celix_bundleContext_registerService(ctx, &activator->subCmd, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+    activator->subCmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &activator->subCmd, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
 
     activator->sqrtCmd.handle = ctx;
     activator->sqrtCmd.executeCommand = sqrtCommand_execute;
     props = celix_properties_create();
     celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "sqrt");
-    activator->sqrtCmdSvcId = celix_bundleContext_registerService(ctx, &activator->sqrtCmd, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+    activator->sqrtCmdSvcId = celix_bundleContext_registerServiceAsync(ctx, &activator->sqrtCmd, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
 
     return CELIX_SUCCESS;
 }
diff --git a/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c b/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c
index 59522e30..d40163ee 100644
--- a/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c
+++ b/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c
@@ -46,7 +46,7 @@ celix_status_t remoteExampleBndStart(struct activator *act, celix_bundle_context
 
         celix_properties_t *properties = celix_properties_create();
         celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, REMOTE_EXAMPLE_NAME);
-        act->svcId = celix_bundleContext_registerService(ctx, &act->service, REMOTE_EXAMPLE_NAME, properties);
+        act->svcId = celix_bundleContext_registerServiceAsync(ctx, &act->service, REMOTE_EXAMPLE_NAME, properties);
     }
     return CELIX_SUCCESS;
 }
diff --git a/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c b/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c
index f462d342..a18b4d2d 100644
--- a/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c
+++ b/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c
@@ -161,7 +161,7 @@ int remoteExample_createAdditionalRemoteService(remote_example_impl_t* impl) {
     } else {
         celix_properties_t *properties = celix_properties_create();
         celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, REMOTE_EXAMPLE_NAME);
-        long newSvcId = celix_bundleContext_registerService(impl->ctx, &impl->additionalSvc, REMOTE_EXAMPLE_NAME, properties);
+        long newSvcId = celix_bundleContext_registerServiceAsync(impl->ctx, &impl->additionalSvc, REMOTE_EXAMPLE_NAME, properties);
         pthread_mutex_lock(&impl->mutex);
         prevSvcId = impl->additionalSvcId;
         if (prevSvcId == -1L) {
diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
index a571f1d0..66a977e5 100644
--- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
+++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
@@ -360,7 +360,7 @@ static celix_status_t bndStart(struct activator *act, celix_bundle_context_t* ct
     }
 
     //register test service
-    act->svcId = celix_bundleContext_registerService(ctx, &act->testSvc, TST_SERVICE_NAME, NULL);
+    act->svcId = celix_bundleContext_registerServiceAsync(ctx, &act->testSvc, TST_SERVICE_NAME, NULL);
     return CELIX_SUCCESS;
 }
 
diff --git a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c
index 0b470da7..a81ea815 100644
--- a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c
+++ b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c
@@ -56,7 +56,7 @@ static celix_status_t celix_rsa_start(celix_remote_service_admin_activator_t* ac
         activator->adminService.importRegistration_getException = importRegistration_getException;
         activator->adminService.importRegistration_getImportReference = importRegistration_getImportReference;
 
-        activator->svcIdRsa = celix_bundleContext_registerService(ctx, &activator->adminService, OSGI_RSA_REMOTE_SERVICE_ADMIN, NULL);
+        activator->svcIdRsa = celix_bundleContext_registerServiceAsync(ctx, &activator->adminService, OSGI_RSA_REMOTE_SERVICE_ADMIN, NULL);
     }
 
     return status;
diff --git a/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c b/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c
index d2bfac3b..b9c46c86 100644
--- a/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c
+++ b/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c
@@ -77,7 +77,7 @@ static celix_status_t shellWui_activator_start(shell_wui_activator_data_t *data,
     celix_properties_set(props, WEBSOCKET_ADMIN_URI, "/shell/socket");
     data->sockSvc.handle = data;
     data->sockSvc.data = websocket_data_handler;
-    data->sockSvcId = celix_bundleContext_registerService(ctx, &data->sockSvc, WEBSOCKET_ADMIN_SERVICE_NAME, props);
+    data->sockSvcId = celix_bundleContext_registerServiceAsync(ctx, &data->sockSvc, WEBSOCKET_ADMIN_SERVICE_NAME, props);
 
     return CELIX_SUCCESS;
 }
diff --git a/examples/celix-examples/http_example/src/http_example_bundle_activator.c b/examples/celix-examples/http_example/src/http_example_bundle_activator.c
index 923eda6b..5142958b 100644
--- a/examples/celix-examples/http_example/src/http_example_bundle_activator.c
+++ b/examples/celix-examples/http_example/src/http_example_bundle_activator.c
@@ -47,7 +47,7 @@ static celix_status_t httpExample_activator_start(http_example_activator_data_t
     celix_properties_set(props, WEBSOCKET_ADMIN_URI, "/hello/socket");
     data->sockSvc.handle = data;
     data->sockSvc.ready = websocket_ready_handler;
-    data->sockSvcId = celix_bundleContext_registerService(ctx, &data->sockSvc, WEBSOCKET_ADMIN_SERVICE_NAME, props);
+    data->sockSvcId = celix_bundleContext_registerServiceAsync(ctx, &data->sockSvc, WEBSOCKET_ADMIN_SERVICE_NAME, props);
 
     return CELIX_SUCCESS;
 }
diff --git a/examples/celix-examples/services_example_c/src/simple_provider_example.c b/examples/celix-examples/services_example_c/src/simple_provider_example.c
index 9f1b95c2..d23ac9b4 100644
--- a/examples/celix-examples/services_example_c/src/simple_provider_example.c
+++ b/examples/celix-examples/services_example_c/src/simple_provider_example.c
@@ -40,7 +40,7 @@ static celix_status_t activator_start(activator_data_t *data, celix_bundle_conte
     data->seed = 42;
     data->svcId = -1L;
 
-    data->svcId = celix_bundleContext_registerService(ctx, &data->svc, EXAMPLE_CALC_NAME, NULL);
+    data->svcId = celix_bundleContext_registerServiceAsync(ctx, &data->svc, EXAMPLE_CALC_NAME, NULL);
     printf("Registered calc service with service id %li\n", data->svcId);
 
     return CELIX_SUCCESS;
diff --git a/examples/celix-examples/track_tracker_example/src/activator.c b/examples/celix-examples/track_tracker_example/src/activator.c
index c5a05e57..1334a7c2 100644
--- a/examples/celix-examples/track_tracker_example/src/activator.c
+++ b/examples/celix-examples/track_tracker_example/src/activator.c
@@ -86,7 +86,7 @@ celix_status_t activator_start(activator_data_t* act, celix_bundle_context_t *ct
     act->svc.handle = act;
     act->svc.calc = calc;
     //note only triggers on calcTrk1, because of filter restrictions
-    act->svcId = celix_bundleContext_registerService(ctx, &act->svc, CALC_SERVICE_NAME, NULL);
+    act->svcId = celix_bundleContext_registerServiceAsync(ctx, &act->svc, CALC_SERVICE_NAME, NULL);
 
     return CELIX_SUCCESS;
 }


[celix] 08/08: Merge branch 'master' into feature/556-osgi-uninstall-2

Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/556-osgi-uninstall
in repository https://gitbox.apache.org/repos/asf/celix.git

commit fc85134971cbd75e9a38c4de784679c7028160e1
Merge: cccf30aa 2efed0a8
Author: PengZheng <ho...@gmail.com>
AuthorDate: Fri Jun 2 23:02:32 2023 +0800

    Merge branch 'master' into feature/556-osgi-uninstall-2

 bundles/deployment_admin/src/ioapi.c   |  3 +--
 bundles/deployment_admin/src/miniunz.c | 15 +++++++--------
 documents/building/README.md           |  2 +-
 3 files changed, 9 insertions(+), 11 deletions(-)