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:04 UTC
[celix] 03/08: Implement OSGi uninstall, and make install/uninstall thread-safe.
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.