You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2021/01/15 19:47:15 UTC
[celix] branch feature/refactor_c_dep_man_service_trackers updated:
Refactors depenency manager further, so that starting,
stopping svc dep and registering svc is done async.
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/refactor_c_dep_man_service_trackers
in repository https://gitbox.apache.org/repos/asf/celix.git
The following commit(s) were added to refs/heads/feature/refactor_c_dep_man_service_trackers by this push:
new 07218d3 Refactors depenency manager further, so that starting, stopping svc dep and registering svc is done async.
07218d3 is described below
commit 07218d39bb7a5607f53180d928fa5e34917af2cf
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Fri Jan 15 20:47:00 2021 +0100
Refactors depenency manager further, so that starting, stopping svc dep and registering svc is done async.
---
.../pubsub/test/pstm_deadlock_test/test_runner.cc | 41 +-
.../gtest/src/DependencyManagerTestSuite.cc | 7 +-
.../gtest/src/bundle_context_services_test.cpp | 97 ++++-
libs/framework/include/celix/dm/Component.h | 34 +-
libs/framework/include/celix/dm/Component_Impl.h | 43 +-
.../framework/include/celix/dm/DependencyManager.h | 26 +-
.../include/celix/dm/DependencyManager_Impl.h | 66 ++-
.../include/celix/dm/ServiceDependency_Impl.h | 11 +-
libs/framework/include/celix_bundle_activator.h | 2 +-
libs/framework/include/celix_bundle_context.h | 15 +
libs/framework/include/celix_dependency_manager.h | 5 +
libs/framework/include/celix_dm_component.h | 12 +
.../include/celix_dm_service_dependency.h | 8 +
libs/framework/src/bundle_context.c | 17 +-
libs/framework/src/dm_component_impl.c | 473 ++++++++++++++-------
libs/framework/src/dm_component_impl.h | 2 +-
libs/framework/src/dm_dependency_manager_impl.c | 45 +-
libs/framework/src/dm_service_dependency.c | 139 ++++--
libs/framework/src/dm_service_dependency_impl.h | 26 +-
libs/framework/src/framework.c | 10 +-
libs/utils/src/array_list.c | 8 +-
21 files changed, 772 insertions(+), 315 deletions(-)
diff --git a/bundles/pubsub/test/pstm_deadlock_test/test_runner.cc b/bundles/pubsub/test/pstm_deadlock_test/test_runner.cc
index abc5353..1b409be 100644
--- a/bundles/pubsub/test/pstm_deadlock_test/test_runner.cc
+++ b/bundles/pubsub/test/pstm_deadlock_test/test_runner.cc
@@ -23,26 +23,29 @@
#include "pubsub/api.h"
#include <unistd.h>
#include <memory>
+#include <mutex>
#include <gtest/gtest.h>
+#include <future>
constexpr const char *deadlockSutBundleFile = DEADLOCK_SUT_BUNDLE_FILE;
struct DeadlockTestSuite : public ::testing::Test {
celix_framework_t *fw = NULL;
celix_bundle_context_t *ctx = NULL;
- std::unique_ptr<DependencyManager> mng = NULL;
+ std::shared_ptr<DependencyManager> mng = NULL;
long sutBundleId = 0;
DeadlockTestSuite() {
celixLauncher_launch("config.properties", &fw);
ctx = celix_framework_getFrameworkContext(fw);
- mng = std::unique_ptr<DependencyManager>(new DependencyManager(ctx));
+ mng = std::shared_ptr<DependencyManager>(new DependencyManager(ctx));
sutBundleId = celix_bundleContext_installBundle(ctx, deadlockSutBundleFile, false);
}
~DeadlockTestSuite() override {
celix_bundleContext_uninstallBundle(ctx, sutBundleId);
+ mng = nullptr;
celixLauncher_stop(fw);
celixLauncher_waitForShutdown(fw);
celixLauncher_destroy(fw);
@@ -57,8 +60,10 @@ struct DeadlockTestSuite : public ::testing::Test {
class DependencyCmp;
struct activator {
- Component<DependencyCmp> *cmp;
- celix_bundle_context_t *ctx;
+ std::string cmpUUID{};
+ celix_bundle_context_t *ctx{};
+ std::promise<void> promise{};
+ std::shared_ptr<celix::dm::DependencyManager> mng{};
};
class IDependency {
@@ -86,14 +91,22 @@ public:
return 1.0;
}
- void setPublisher(const pubsub_publisher_t *pub __attribute__((unused))) {
- act->cmp->createCServiceDependency<pubsub_publisher_t>(PUBSUB_PUBLISHER_SERVICE_NAME)
- .setVersionRange("[3.0.0,4)")
- .setFilter("(topic=deadlock)(scope=scope2)")
- .setStrategy(celix::dm::DependencyUpdateStrategy::suspend)
- .setCallbacks([](const pubsub_publisher_t *, Properties&&) { std::cout << "success\n"; })
- .setRequired(true)
- .build();
+ void setPublisher(const pubsub_publisher_t *pub) {
+ if (pub == nullptr) {
+ return; //nothing on "unsetting" svc
+ }
+ auto cmp = act->mng->findComponent<DependencyCmp>(act->cmpUUID);
+ EXPECT_TRUE(cmp);
+ if (cmp) {
+ cmp->createCServiceDependency<pubsub_publisher_t>(PUBSUB_PUBLISHER_SERVICE_NAME)
+ .setVersionRange("[3.0.0,4)")
+ .setFilter("(topic=deadlock)(scope=scope2)")
+ .setStrategy(celix::dm::DependencyUpdateStrategy::suspend)
+ .setCallbacks([](const pubsub_publisher_t *, Properties&&) { std::cout << "success\n"; })
+ .setRequired(true)
+ .build();
+ }
+ act->promise.set_value();
}
int init() {
@@ -124,7 +137,8 @@ TEST_F(DeadlockTestSuite, test) {
activator act{};
act.ctx = ctx;
- act.cmp = &cmp;
+ act.mng = mng;
+ act.cmpUUID = cmp.getUUID();
cmp.getInstance().act = &act;
cmp.createCServiceDependency<pubsub_publisher_t>(PUBSUB_PUBLISHER_SERVICE_NAME)
@@ -139,5 +153,6 @@ TEST_F(DeadlockTestSuite, test) {
celix_bundleContext_startBundle(ctx, sutBundleId);
+ act.promise.get_future().wait(); //wait till setPublisher has added an service dependency (NOTE dep man is not thread safe!)
mng->stop();
}
diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index bb4fec9..c68d25a 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -33,6 +33,8 @@ public:
properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
+ properties_set(properties, "CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace");
+
fw = celix_frameworkFactory_createFramework(properties);
ctx = framework_getContext(fw);
@@ -286,6 +288,7 @@ TEST_F(DependencyManagerTestSuite, AddSvcDepAfterBuild) {
dep.build();
dep.build(); //should be ok to call twice
+ celix_bundleContext_waitForEvents(ctx);
ASSERT_EQ(1, count); //service dep build -> so count is 1;
//create another service dep
@@ -304,9 +307,9 @@ TEST_F(DependencyManagerTestSuite, AddSvcDepAfterBuild) {
TEST_F(DependencyManagerTestSuite, InCompleteBuildShouldNotLeak) {
celix::dm::DependencyManager dm{ctx};
- dm.createComponent<TestComponent>(std::make_shared<TestComponent>(), "test1"); //note not build
+ dm.createComponent<TestComponent>(std::make_shared<TestComponent>(), "test1"); //NOTE NOT BUILD
- auto& cmp2 = dm.createComponent<Cmp1>(std::make_shared<Cmp1>(), "test2").build();
+ auto& cmp2 = dm.createComponent<Cmp1>(std::make_shared<Cmp1>(), "test2").build(); //NOTE BUILD
cmp2.createCServiceDependency<TestService>("TestService").setFilter("(key=value"); //note not build
cmp2.createServiceDependency<TestService>().setFilter("(key=value)"); //note not build
diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index c12fc7b..a63049a 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -1196,19 +1196,35 @@ TEST_F(CelixBundleContextServicesTests, onlyCallAsyncCallbackWithAsyncApi) {
}
TEST_F(CelixBundleContextServicesTests, unregisterSvcBeforeAsyncRegistration) {
+ struct callback_data {
+ std::atomic<int> count{};
+ celix_bundle_context_t* ctx{nullptr};
+ };
+ callback_data cbData{};
+ cbData.ctx = ctx;
+
celix_framework_fireGenericEvent(
fw,
-1,
celix_bundle_getId(celix_framework_getFrameworkBundle(fw)),
"registerAsync",
- (void*)ctx,
+ (void*)&cbData,
[](void *data) {
- auto context = (celix_bundle_context_t*)data;
+ auto cbd = static_cast<struct callback_data*>(data);
+
+ celix_service_registration_options_t opts{};
+ opts.serviceName = "test-service";
+ opts.svc = (void*)0x42;
+ opts.asyncData = data;
+ opts.asyncCallback = [](void *data, long /*svcId*/) {
+ auto* cbd = static_cast<struct callback_data*>(data);
+ cbd->count.fetch_add(1);
+ };
//note register async. So a event on the event queue, but because this is done on the event queue this cannot be completed
- long svcId = celix_bundleContext_registerServiceAsync(context, (void*)0x42, "test-service", nullptr);
+ long svcId = celix_bundleContext_registerServiceAsync(cbd->ctx, (void*)0x42, "test-service", nullptr);
- celix_bundleContext_unregisterService(context, svcId); //trying to unregister still queued svc registration -> should cancel event.
+ celix_bundleContext_unregisterService(cbd->ctx, svcId); //trying to unregister still queued svc registration -> should cancel event.
},
nullptr,
nullptr);
@@ -1216,67 +1232,110 @@ TEST_F(CelixBundleContextServicesTests, unregisterSvcBeforeAsyncRegistration) {
celix_bundleContext_waitForEvents(ctx);
long svcId = celix_bundleContext_findService(ctx, "test-service");
EXPECT_LT(svcId, 0);
+ EXPECT_EQ(0, cbData.count.load()); //note create tracker canceled -> no callback
}
TEST_F(CelixBundleContextServicesTests, stopSvcTrackerBeforeAsyncTrackerIsCreated) {
+ struct callback_data {
+ std::atomic<int> count{};
+ celix_bundle_context_t* ctx{nullptr};
+ };
+ callback_data cbData{};
+ cbData.ctx = ctx;
+
celix_framework_fireGenericEvent(
fw,
-1,
celix_bundle_getId(celix_framework_getFrameworkBundle(fw)),
"create tracker async",
- (void*)ctx,
+ (void*)&cbData,
[](void *data) {
- auto context = (celix_bundle_context_t*)data;
+ auto cbd = static_cast<struct callback_data*>(data);
- //note register async. So a event on the event queue, but because this is done on the event queue this cannot be completed
- long trkId = celix_bundleContext_trackServicesAsync(context, "test-service", nullptr, nullptr,nullptr);
+ celix_service_tracking_options_t opts{};
+ opts.filter.serviceName = "test-service";
+ opts.trackerCreatedCallbackData = data;
+ opts.trackerCreatedCallback = [](void *data) {
+ auto* cbd = static_cast<struct callback_data*>(data);
+ cbd->count.fetch_add(1);
+ };
+
+ //note create async. So a event on the event queue, but because this is done on the event queue this cannot be completed
+ long trkId = celix_bundleContext_trackServicesWithOptionsAsync(cbd->ctx, &opts);
- celix_bundleContext_stopTracker(context, trkId);
+ celix_bundleContext_stopTracker(cbd->ctx, trkId);
},
nullptr,
nullptr);
celix_bundleContext_waitForEvents(ctx);
+ EXPECT_EQ(0, cbData.count.load()); //note create tracker canceled -> no callback
}
TEST_F(CelixBundleContextServicesTests, stopBundleTrackerBeforeAsyncTrackerIsCreated) {
+ struct callback_data {
+ std::atomic<int> count{};
+ celix_bundle_context_t* ctx{nullptr};
+ };
+ callback_data cbData{};
+ cbData.ctx = ctx;
+
celix_framework_fireGenericEvent(
fw,
-1,
celix_bundle_getId(celix_framework_getFrameworkBundle(fw)),
"create tracker async",
- (void*)ctx,
+ (void*)&cbData,
[](void *data) {
- auto context = (celix_bundle_context_t*)data;
+ auto cbd = static_cast<struct callback_data*>(data);
- //note register async. So a event on the event queue, but because this is done on the event queue this cannot be completed
- long trkId = celix_bundleContext_trackBundlesAsync(context, nullptr, nullptr,nullptr);
+ celix_bundle_tracking_options_t opts{};
+ opts.trackerCreatedCallbackData = data;
+ opts.trackerCreatedCallback = [](void *data) {
+ auto* cbd = static_cast<struct callback_data*>(data);
+ cbd->count.fetch_add(1);
+ };
+
+ //note create async. So a event on the event queue, but because this is done on the event queue this cannot be completed
+ long trkId = celix_bundleContext_trackBundlesWithOptionsAsync(cbd->ctx, &opts);
- celix_bundleContext_stopTracker(context, trkId);
+ celix_bundleContext_stopTracker(cbd->ctx, trkId);
},
nullptr,
nullptr);
celix_bundleContext_waitForEvents(ctx);
+ EXPECT_EQ(0, cbData.count.load()); //note create tracker canceled -> no callback
}
TEST_F(CelixBundleContextServicesTests, stopMetaTrackerBeforeAsyncTrackerIsCreated) {
+ struct callback_data {
+ std::atomic<int> count{};
+ celix_bundle_context_t* ctx{nullptr};
+ };
+ callback_data cbData{};
+ cbData.ctx = ctx;
+
celix_framework_fireGenericEvent(
fw,
-1,
celix_bundle_getId(celix_framework_getFrameworkBundle(fw)),
"create tracker async",
- (void*)ctx,
+ (void*)&cbData,
[](void *data) {
- auto context = (celix_bundle_context_t*)data;
+ auto cbd = static_cast<struct callback_data*>(data);
- //note register async. So a event on the event queue, but because this is done on the event queue this cannot be completed
- long trkId = celix_bundleContext_trackServiceTrackers(context, "test-service", nullptr, nullptr,nullptr);
+ //note create async. So a event on the event queue, but because this is done on the event queue this cannot be completed
+ long trkId = celix_bundleContext_trackServiceTrackersAsync(cbd->ctx, "test-service", nullptr, nullptr, nullptr, data, [](void *data) {
+ auto* cbd = static_cast<struct callback_data*>(data);
+ cbd->count.fetch_add(1);
+ });
- celix_bundleContext_stopTracker(context, trkId);
+ celix_bundleContext_stopTracker(cbd->ctx, trkId);
},
nullptr,
nullptr);
celix_bundleContext_waitForEvents(ctx);
+ EXPECT_EQ(0, cbData.count.load()); //note create tracker canceled -> no callback
}
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/Component.h b/libs/framework/include/celix/dm/Component.h
index c5d9c59..9a50c78 100644
--- a/libs/framework/include/celix/dm/Component.h
+++ b/libs/framework/include/celix/dm/Component.h
@@ -26,14 +26,16 @@
#include <string>
#include <vector>
#include <atomic>
+#include <mutex>
namespace celix { namespace dm {
class BaseComponent {
public:
- BaseComponent(celix_bundle_context_t *con, celix_dependency_manager_t* cdm, const std::string &name) : context{con}, cDepMan{cdm}, cCmp{nullptr} {
- this->cCmp = celix_dmComponent_create(this->context, name.c_str());
+ BaseComponent(celix_bundle_context_t *con, celix_dependency_manager_t* cdm, std::string name, std::string uuid) : context{con}, cDepMan{cdm}, cCmp{nullptr} {
+ this->cCmp = celix_dmComponent_createWithUUID(this->context, name.c_str(), uuid.empty() ? nullptr : uuid.c_str());
celix_dmComponent_setImplementation(this->cCmp, this);
+ cmpUUID = std::string{celix_dmComponent_getUUID(this->cCmp)};
}
virtual ~BaseComponent() noexcept;
@@ -50,15 +52,19 @@ namespace celix { namespace dm {
*/
celix_bundle_context_t* bundleContext() const { return this->context; }
+ const std::string& getUUID() const {
+ return cmpUUID;
+ }
+
void runBuild();
protected:
std::vector<std::shared_ptr<BaseServiceDependency>> dependencies{};
std::vector<std::shared_ptr<BaseProvidedService>> providedServices{};
- private:
celix_bundle_context_t* context;
celix_dependency_manager_t* cDepMan;
celix_dm_component_t *cCmp;
+ std::string cmpUUID{};
std::atomic<bool> cmpAddedToDepMan{false};
};
@@ -67,6 +73,7 @@ namespace celix { namespace dm {
class Component : public BaseComponent {
using type = T;
private:
+ std::mutex instanceMutex{};
std::unique_ptr<T> instance {nullptr};
std::shared_ptr<T> sharedInstance {nullptr};
std::vector<T> valInstance {};
@@ -80,24 +87,23 @@ namespace celix { namespace dm {
int (T::*startFpNoExc)() = {};
int (T::*stopFpNoExc)() = {};
int (T::*deinitFpNoExc)() = {};
+
+ /**
+ * Ctor is private, use static create function member instead
+ * @param context
+ * @param cDepMan
+ * @param name
+ */
+ Component(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, std::string name, std::string uuid);
public:
- Component(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, const std::string &name);
~Component() override;
/**
* Creates a Component using the provided bundle context
* and component name.
- * Will use new(nothrow) if exceptions are disabled.
- * @return newly created DM Component or nullptr
- */
- static Component<T>* create(celix_bundle_context_t*, celix_dependency_manager_t* cDepMan, const std::string &name);
-
- /**
- * Creates a Component using the provided bundle context.
- * Will use new(nothrow) if exceptions are disabled.
- * @return newly created DM Component or nullptr
+ * @return newly created DM Component.
*/
- static Component<T>* create(celix_bundle_context_t*, celix_dependency_manager_t* cDepMan);
+ static std::shared_ptr<Component<T>> create(celix_bundle_context_t*, celix_dependency_manager_t* cDepMan, std::string name, std::string uuid);
/**
* Whether the component is valid. Invalid component can occurs when no new components can be created and
diff --git a/libs/framework/include/celix/dm/Component_Impl.h b/libs/framework/include/celix/dm/Component_Impl.h
index 4b80892..498b9a1 100644
--- a/libs/framework/include/celix/dm/Component_Impl.h
+++ b/libs/framework/include/celix/dm/Component_Impl.h
@@ -49,16 +49,19 @@ inline void BaseComponent::runBuild() {
if (!alreadyAdded) {
celix_dependencyManager_add(cDepMan, cCmp);
}
-}
-inline BaseComponent::~BaseComponent() noexcept {
- if (context != nullptr && !cmpAddedToDepMan) {
- celix_dmComponent_destroy(cCmp);
+ if (context) {
+ auto *fw = celix_bundleContext_getFramework(context);
+ if (!celix_framework_isCurrentThreadTheEventLoop(fw)) {
+ celix_framework_waitForEmptyEventQueue(fw);
+ }
}
}
+inline BaseComponent::~BaseComponent() noexcept = default;
+
template<class T>
-Component<T>::Component(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, const std::string &name) : BaseComponent(context, cDepMan, name) {}
+Component<T>::Component(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, std::string name, std::string uuid) : BaseComponent(context, cDepMan, std::move(name), std::move(uuid)) {}
template<class T>
Component<T>::~Component() = default;
@@ -161,19 +164,19 @@ Component<T>& Component<T>::remove(CServiceDependency<T,I>& dep) {
}
template<class T>
-Component<T>* Component<T>::create(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan) {
- std::string name = typeName<T>();
- return Component<T>::create(context, cDepMan, name);
-}
-
-template<class T>
-Component<T>* Component<T>::create(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, const std::string &name) {
- static Component<T> invalid{nullptr, nullptr, std::string{}};
- Component<T>* cmp = new (std::nothrow) Component<T>(context, cDepMan, name);
- if (cmp == nullptr) {
- cmp = &invalid;
- }
- return cmp;
+std::shared_ptr<Component<T>> Component<T>::create(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, std::string name, std::string uuid) {
+ std::string cmpName = name.empty() ? celix::dm::typeName<T>() : std::move(name);
+ return std::shared_ptr<Component<T>>{new Component<T>(context, cDepMan, std::move(cmpName), std::move(uuid)), [](Component<T>* cmp){
+ if (cmp->cmpAddedToDepMan) {
+ celix_dependencyManager_removeWithoutDestroy(cmp->cDepMan, cmp->cCmp); //remove
+ }
+ //NOTE using a callback of async destroy to ensure that the cmp instance is still exist while the
+ //dm component is async disabled and destroyed.
+ celix_dmComponent_destroyAsync(cmp->cCmp, cmp, [](void *data) {
+ auto* c = static_cast<Component<T>*>(data);
+ delete c;
+ });
+ }};
}
template<class T>
@@ -198,6 +201,7 @@ createInstance() {
template<class T>
T& Component<T>::getInstance() {
+ std::lock_guard<std::mutex> lck{instanceMutex};
if (!valInstance.empty()) {
return valInstance.front();
} else if (sharedInstance) {
@@ -213,6 +217,7 @@ T& Component<T>::getInstance() {
template<class T>
Component<T>& Component<T>::setInstance(std::shared_ptr<T> inst) {
+ std::lock_guard<std::mutex> lck{instanceMutex};
this->valInstance.clear();
this->instance = std::unique_ptr<T> {nullptr};
this->sharedInstance = std::move(inst);
@@ -221,6 +226,7 @@ Component<T>& Component<T>::setInstance(std::shared_ptr<T> inst) {
template<class T>
Component<T>& Component<T>::setInstance(std::unique_ptr<T>&& inst) {
+ std::lock_guard<std::mutex> lck{instanceMutex};
this->valInstance.clear();
this->sharedInstance = std::shared_ptr<T> {nullptr};
this->instance = std::move(inst);
@@ -229,6 +235,7 @@ Component<T>& Component<T>::setInstance(std::unique_ptr<T>&& inst) {
template<class T>
Component<T>& Component<T>::setInstance(T&& inst) {
+ std::lock_guard<std::mutex> lck{instanceMutex};
this->instance = std::unique_ptr<T> {nullptr};
this->sharedInstance = std::shared_ptr<T> {nullptr};
this->valInstance.clear();
diff --git a/libs/framework/include/celix/dm/DependencyManager.h b/libs/framework/include/celix/dm/DependencyManager.h
index 6dc8a94..1f2688e 100644
--- a/libs/framework/include/celix/dm/DependencyManager.h
+++ b/libs/framework/include/celix/dm/DependencyManager.h
@@ -57,7 +57,7 @@ namespace celix { namespace dm {
*/
template<class T>
typename std::enable_if<std::is_default_constructible<T>::value, Component<T>&>::type
- createComponent(std::string name = std::string{});
+ createComponent(std::string name = std::string{}, std::string uuid = {});
/**
* Creates and adds a new DM Component for a component of type T and setting
@@ -66,7 +66,7 @@ namespace celix { namespace dm {
* @return Returns a reference to the DM Component
*/
template<class T>
- Component<T>& createComponent(std::unique_ptr<T>&& rhs, std::string name = std::string{});
+ Component<T>& createComponent(std::unique_ptr<T>&& rhs, std::string name = std::string{}, std::string uuid = {});
/**
* Creates and adds a new DM Component for a component of type T and setting
@@ -75,7 +75,7 @@ namespace celix { namespace dm {
* @return Returns a reference to the DM Component
*/
template<class T>
- Component<T>& createComponent(std::shared_ptr<T> rhs, std::string name = std::string{});
+ Component<T>& createComponent(std::shared_ptr<T> rhs, std::string name = std::string{}, std::string uuid = {});
/**
* Creates and adds a new DM Component for a component of type T and setting
@@ -84,7 +84,7 @@ namespace celix { namespace dm {
* @return Returns a reference to the DM Component
*/
template<class T>
- Component<T>& createComponent(T rhs, std::string name = std::string{});
+ Component<T>& createComponent(T rhs, std::string name = std::string{}, std::string uuid = {});
/**
* Build the dependency manager.
@@ -127,9 +127,25 @@ namespace celix { namespace dm {
* Returns the nr of configured components for this dependency manager.
*/
std::size_t getNrOfComponents() const;
+
+ /**
+ * Tries to find the component with UUID and staticly cast it to
+ * dm component of type T
+ * @return pointer to found component or null if the component cannot be found.
+ *
+ * Note: DependencyManager is not thread safe!
+ */
+ template<typename T>
+ std::shared_ptr<Component<T>> findComponent(const std::string& uuid) const;
private:
template<class T>
- Component<T>& createComponentInternal(std::string name);
+ Component<T>& createComponentInternal(std::string name, std::string uuid);
+
+ /**
+ * Wait until current Celix event queue is empty.
+ * Note: will just return if the current thread is the Celix event thread
+ */
+ void wait() const;
std::shared_ptr<celix_bundle_context_t> context;
std::shared_ptr<celix_dependency_manager_t> cDepMan;
diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h b/libs/framework/include/celix/dm/DependencyManager_Impl.h
index 2d3b578..aaff50a 100644
--- a/libs/framework/include/celix/dm/DependencyManager_Impl.h
+++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h
@@ -17,6 +17,7 @@
* under the License.
*/
+#include <cassert>
#include "DependencyManager.h"
using namespace celix::dm;
@@ -25,15 +26,16 @@ inline DependencyManager::DependencyManager(celix_bundle_context_t *ctx) :
context{ctx, [](celix_bundle_context_t*){/*nop*/}},
cDepMan{celix_bundleContext_getDependencyManager(ctx), [](celix_dependency_manager_t*){/*nop*/}} {}
-inline DependencyManager::~DependencyManager() {/*nop*/}
+inline DependencyManager::~DependencyManager() {
+ clear();
+}
template<class T>
-Component<T>& DependencyManager::createComponentInternal(std::string name) {
- Component<T>* cmp = name.empty() ?
- Component<T>::create(this->context.get(), this->cDepMan.get()) :
- Component<T>::create(this->context.get(), this->cDepMan.get(), name);
+Component<T>& DependencyManager::createComponentInternal(std::string name, std::string uuid) {
+ auto cmp = Component<T>::create(this->context.get(), this->cDepMan.get(), std::move(name), std::move(uuid));
if (cmp->isValid()) {
- this->components.push_back(std::shared_ptr<BaseComponent>{cmp});
+ auto baseCmp = std::static_pointer_cast<BaseComponent>(cmp);
+ this->components.push_back(baseCmp);
}
return *cmp;
@@ -42,23 +44,23 @@ Component<T>& DependencyManager::createComponentInternal(std::string name) {
template<class T>
inline
typename std::enable_if<std::is_default_constructible<T>::value, Component<T>&>::type
-DependencyManager::createComponent(std::string name) {
- return createComponentInternal<T>(name);
+DependencyManager::createComponent(std::string name, std::string uuid) {
+ return createComponentInternal<T>(name, uuid);
}
template<class T>
-Component<T>& DependencyManager::createComponent(std::unique_ptr<T>&& rhs, std::string name) {
- return createComponentInternal<T>(name).setInstance(std::move(rhs));
+Component<T>& DependencyManager::createComponent(std::unique_ptr<T>&& rhs, std::string name, std::string uuid) {
+ return createComponentInternal<T>(name, uuid).setInstance(std::move(rhs));
}
template<class T>
-Component<T>& DependencyManager::createComponent(std::shared_ptr<T> rhs, std::string name) {
- return createComponentInternal<T>(name).setInstance(rhs);
+Component<T>& DependencyManager::createComponent(std::shared_ptr<T> rhs, std::string name, std::string uuid) {
+ return createComponentInternal<T>(name, uuid).setInstance(rhs);
}
template<class T>
-Component<T>& DependencyManager::createComponent(T rhs, std::string name) {
- return createComponentInternal<T>(name).setInstance(std::forward<T>(rhs));
+Component<T>& DependencyManager::createComponent(T rhs, std::string name, std::string uuid) {
+ return createComponentInternal<T>(name, uuid).setInstance(std::forward<T>(rhs));
}
inline void DependencyManager::start() {
@@ -69,16 +71,33 @@ inline void DependencyManager::build() {
for (auto& cmp : components) {
cmp->runBuild();
}
+ wait();
}
template<typename T>
void DependencyManager::destroyComponent(Component<T> &component) {
- celix_dependencyManager_remove(cDepMan.get(), component.cComponent());
+ for (auto it = components.begin(); it != components.end(); ++it) {
+ if ( (*it).get() == &component) {
+ //found
+ components.erase(it);
+ break;
+ }
+ }
+ wait();
}
inline void DependencyManager::clear() {
- celix_dependencyManager_removeAllComponents(cDepMan.get());
components.clear();
+ wait();
+}
+
+inline void DependencyManager::wait() const {
+ if (context) {
+ auto *fw = celix_bundleContext_getFramework(context.get());
+ if (!celix_framework_isCurrentThreadTheEventLoop(fw)) {
+ celix_framework_waitForEmptyEventQueue(fw);
+ }
+ }
}
inline void DependencyManager::stop() {
@@ -89,3 +108,18 @@ inline std::size_t DependencyManager::getNrOfComponents() const {
return celix_dependencyManager_nrOfComponents(cDepMan.get());
}
+template<typename T>
+inline std::shared_ptr<Component<T>> DependencyManager::findComponent(const std::string& uuid) const {
+ std::shared_ptr<BaseComponent> found{nullptr};
+ for (const auto& cmp : components) {
+ if (cmp->getUUID() == uuid) {
+ found = cmp;
+ }
+ }
+ if (found) {
+ return std::static_pointer_cast<Component<T>>(found);
+ } else {
+ return nullptr;
+ }
+}
+
diff --git a/libs/framework/include/celix/dm/ServiceDependency_Impl.h b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
index a9dd5d2..c2f6824 100644
--- a/libs/framework/include/celix/dm/ServiceDependency_Impl.h
+++ b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
@@ -22,6 +22,8 @@
#include <cstring>
#include "celix_constants.h"
#include "celix_properties.h"
+#include "celix_bundle_context.h"
+#include "celix_framework.h"
#include "ServiceDependency.h"
@@ -32,11 +34,18 @@ inline void BaseServiceDependency::runBuild() {
if (!alreadyAdded) {
celix_dmComponent_addServiceDependency(cCmp, cServiceDep);
}
+ auto* ctx = celix_dmComponent_getBundleContext(cCmp);
+ if (ctx != nullptr) {
+ auto* fw = celix_bundleContext_getFramework(ctx);
+ if (!celix_framework_isCurrentThreadTheEventLoop(fw)) {
+ celix_framework_waitForEmptyEventQueue(fw);
+ }
+ }
}
inline BaseServiceDependency::~BaseServiceDependency() noexcept {
if (!depAddedToCmp) {
- celix_dmServiceDependency_destroy(cServiceDep);
+ celix_dmServiceDependency_destroyAsync(cServiceDep, nullptr, nullptr);
}
}
diff --git a/libs/framework/include/celix_bundle_activator.h b/libs/framework/include/celix_bundle_activator.h
index ab02ed2..37c978c 100644
--- a/libs/framework/include/celix_bundle_activator.h
+++ b/libs/framework/include/celix_bundle_activator.h
@@ -194,7 +194,7 @@ extern "C" celix_status_t bundleActivator_start(void *userData, celix_bundle_con
extern "C" celix_status_t bundleActivator_stop(void *userData, celix_bundle_context_t*) { \
auto* data = static_cast<BundleActivatorData*>(userData); \
if (data != nullptr) { \
- data->mng->stop(); \
+ data->mng->clear() \
data->activator = nullptr; \
data->mng = nullptr; \
} \
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index b99c8b5..af010ea 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -177,6 +177,10 @@ typedef struct celix_service_registration_options {
/**
* Async callback. Will be called after the a service is registered in the service registry using a async call.
* Will be called on the Celix event loop.
+ *
+ * If a asyns service registration is combined with a _sync_ service unregistration, it can happen that
+ * unregistration happens before the registration event is processed. In this case the asyncCallback
+ * will not be called.
*/
void (*asyncCallback)(void *data, long serviceId) OPTS_INIT;
} celix_service_registration_options_t;
@@ -524,6 +528,10 @@ typedef struct celix_service_tracking_options {
/**
* The callback called when the tracker has ben created (and is active) when using a async call.
+ *
+ * If a asyns track service is combined with a _sync_ stop tracker, it can happen that
+ * "stop tracker" happens before the "create tracker" event is processed. In this case the asyncCallback
+ * will not be called.
*/
void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) OPTS_INIT;
} celix_service_tracking_options_t;
@@ -958,6 +966,10 @@ typedef struct celix_bundle_tracker_options {
/**
* The callback called when the tracker has ben created (and is active) when using the
* track bundles ascync calls.
+ *
+ * If a asyns track service is combined with a _sync_ stop tracker, it can happen that
+ * "stop tracker" happens before the "create tracker" event is processed. In this case the asyncCallback
+ * will not be called.
*/
void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) OPTS_INIT;
} celix_bundle_tracking_options_t;
@@ -1086,6 +1098,9 @@ typedef struct celix_service_tracker_info {
* @param trackerRemove Called when a service tracker is removed, which tracks the provided service name
* @param doneCallbackData call back data argument provided to the done callback function.
* @param doneCallback If not NULL will be called when the service tracker tracker is created.
+ * If a asyns track service is combined with a _sync_ stop tracker, it can happen that
+ * "stop tracker" happens before the "create tracker" event is processed.
+ * In this case the doneCallback will not be called.
* @return The tracker id or <0 if something went wrong (will log an error).
*/
long celix_bundleContext_trackServiceTrackersAsync(
diff --git a/libs/framework/include/celix_dependency_manager.h b/libs/framework/include/celix_dependency_manager.h
index 2bff28b..630172f 100644
--- a/libs/framework/include/celix_dependency_manager.h
+++ b/libs/framework/include/celix_dependency_manager.h
@@ -42,6 +42,11 @@ celix_status_t celix_dependencyManager_add(celix_dependency_manager_t *manager,
celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component);
/**
+ * Removes a DM component from the dependency manager.
+ */
+celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_manager_t *manager, celix_dm_component_t *component);
+
+/**
* Removes all DM components from the dependency manager
*/
celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_manager_t *manager);
diff --git a/libs/framework/include/celix_dm_component.h b/libs/framework/include/celix_dm_component.h
index 3998086..244111e 100644
--- a/libs/framework/include/celix_dm_component.h
+++ b/libs/framework/include/celix_dm_component.h
@@ -69,6 +69,13 @@ const char* celix_dmComponent_getUUID(celix_dm_component_t* cmp);
void celix_dmComponent_destroy(celix_dm_component_t *cmp);
/**
+ * Destroys a DM Component on the event thread.
+ * Will call doneCallback when done.
+ *
+ */
+void celix_dmComponent_destroyAsync(celix_dm_component_t *cmp, void *doneData, void (*doneCallback)(void*));
+
+/**
* Specify if a default 'service.lang=C' should be added to the properties of interfaces if no 'service.lang' has been
* provided. Default is false. Note that this should be set before using component_addInterface.
*/
@@ -162,6 +169,11 @@ bool celix_dmComponent_isActive(celix_dm_component_t *component);
*/
void celix_dmComponent_destroyComponentInfo(dm_component_info_pt info);
+/**
+ * Returns the string value of a provided state
+ */
+const char* celix_dmComponent_stateToString(celix_dm_component_state_t state);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/framework/include/celix_dm_service_dependency.h b/libs/framework/include/celix_dm_service_dependency.h
index 9ef51a8..dd9732d 100644
--- a/libs/framework/include/celix_dm_service_dependency.h
+++ b/libs/framework/include/celix_dm_service_dependency.h
@@ -78,6 +78,14 @@ celix_dm_service_dependency_t* celix_dmServiceDependency_create(void);
*/
void celix_dmServiceDependency_destroy(celix_dm_service_dependency_t *dep);
+void celix_dmServiceDependency_destroyAsync(celix_dm_service_dependency_t *dep, void *doneData, void (*doneCallback)(void*));
+
+/**
+ * Note free resource of dm service dependency.
+ * Should only be called on a disabled service dependency.
+ */
+void celix_dmServiceDependency_free(celix_dm_service_dependency_t *dep);
+
/**
* Specify if the service dependency is required. default is false
*/
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index ce4d4ce..0bdf1e7 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -670,6 +670,9 @@ void celix_bundleContext_trackBundlesWithOptionsCallback(void *data) {
free(entry);
} else {
fw_addBundleListener(entry->ctx->framework, entry->ctx->bundle, &entry->listener);
+ if (entry->opts.trackerCreatedCallback) {
+ entry->opts.trackerCreatedCallback(entry->opts.trackerCreatedCallbackData);
+ }
}
}
@@ -692,9 +695,8 @@ static long celix_bundleContext_trackBundlesWithOptionsInternal(
trackerId = entry->trackerId;
celixThreadMutex_unlock(&ctx->mutex);
- void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) = NULL;
- if (async) { //note only using the async callback if this is a async call.
- trackerCreatedCallback = opts->trackerCreatedCallback;
+ if (!async) { //note only using the async callback if this is a async call.
+ entry->opts.callbackHandle = NULL;
}
long id = celix_framework_fireGenericEvent(
ctx->framework,
@@ -703,8 +705,8 @@ static long celix_bundleContext_trackBundlesWithOptionsInternal(
"add bundle listener",
entry,
celix_bundleContext_trackBundlesWithOptionsCallback,
- opts->trackerCreatedCallbackData,
- trackerCreatedCallback);
+ NULL,
+ NULL);
if (!async) {
celix_framework_waitForGenericEvent(ctx->framework, id);
@@ -1383,12 +1385,11 @@ static void celix_bundleContext_doneCreatingTrackerOnEventLoop(void *data) {
celixThreadMutex_lock(&entry->ctx->mutex);
bool cancelled = entry->cancelled;
celixThreadMutex_unlock(&entry->ctx->mutex);
- if (entry->trackerCreatedCallback != NULL) {
- entry->trackerCreatedCallback(entry->trackerCreatedCallbackData);
- }
if (cancelled) {
//tracker creation cancelled -> entry already removed from map, but memory needs to be freed.
free(entry);
+ } else if (entry->trackerCreatedCallback != NULL) {
+ entry->trackerCreatedCallback(entry->trackerCreatedCallbackData);
}
}
diff --git a/libs/framework/src/dm_component_impl.c b/libs/framework/src/dm_component_impl.c
index 08a4e01..c04e617 100644
--- a/libs/framework/src/dm_component_impl.c
+++ b/libs/framework/src/dm_component_impl.c
@@ -48,15 +48,23 @@ struct celix_dm_component_struct {
celix_array_list_t* providedInterfaces; //type = dm_interface_t*
celix_array_list_t* dependencies; //type = celix_dm_service_dependency_t*
+ /**
+ * Removed dependencies, which are potential still being stopped async
+ */
+ celix_array_list_t* removedDependencies; //type = celix_dm_service_dependency_t*
+
celix_dm_component_state_t state;
/**
- * Nr of active set, add or remove svc calls in progress.
+ * Nr of svc depedencies in progress:
+ * - this means a set, add or remove svc callback are in progress and/or
+ * - a service dependency is being stopped
* Should be 0 before destroying cmp or removing service dependencies
*/
- size_t nrOfSetAddRemCallsInProgress;
+ size_t nrOfSvcDepependenciesInProgress;
- bool isStarted;
+
+ bool isEnabled;
};
typedef struct dm_interface_struct {
@@ -66,19 +74,21 @@ typedef struct dm_interface_struct {
long svcId;
} dm_interface_t;
-static celix_status_t component_registerServices(celix_dm_component_t *component);
-static celix_status_t component_unregisterServices(celix_dm_component_t *component);
-static bool component_areAllRequiredServiceDependenciesResolved(celix_dm_component_t *component);
-static celix_status_t component_performTransition(celix_dm_component_t *component, celix_dm_component_state_t oldState, celix_dm_component_state_t newState, bool *transition);
-static celix_status_t component_calculateNewState(celix_dm_component_t *component, celix_dm_component_state_t currentState, celix_dm_component_state_t *newState);
-static celix_status_t component_handleChange(celix_dm_component_t *component);
-static celix_status_t component_handleAdd(celix_dm_component_t *component, const celix_dm_event_t* event);
-static celix_status_t component_handleRemove(celix_dm_component_t *component, const celix_dm_event_t* event);
-static celix_status_t component_handleSet(celix_dm_component_t *component, const celix_dm_event_t* event);
-static celix_status_t component_startDependencies(celix_dm_component_t *component);
-static celix_status_t component_suspend(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency);
-static celix_status_t component_resume(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency);
-static celix_status_t celix_dmComponent_stop(celix_dm_component_t *component);
+static celix_status_t celix_dmComponent_registerServices(celix_dm_component_t *component);
+static celix_status_t celix_dmComponent_unregisterServices(celix_dm_component_t *component);
+static bool celix_dmComponent_areAllRequiredServiceDependenciesResolved(celix_dm_component_t *component);
+static celix_status_t celix_dmComponent_performTransition(celix_dm_component_t *component, celix_dm_component_state_t oldState, celix_dm_component_state_t newState, bool *transition);
+static celix_status_t celix_dmComponent_calculateNewState(celix_dm_component_t *component, celix_dm_component_state_t currentState, celix_dm_component_state_t *newState);
+static celix_status_t celix_dmComponent_handleChange(celix_dm_component_t *component);
+static celix_status_t celix_dmComponent_handleAdd(celix_dm_component_t *component, const celix_dm_event_t* event);
+static celix_status_t celix_dmComponent_handleRemove(celix_dm_component_t *component, const celix_dm_event_t* event);
+static celix_status_t celix_dmComponent_handleSet(celix_dm_component_t *component, const celix_dm_event_t* event);
+static celix_status_t celix_dmComponent_disableDependencies(celix_dm_component_t *component);
+static celix_status_t celix_dmComponent_suspend(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency);
+static celix_status_t celix_dmComponent_resume(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency);
+static celix_status_t celix_dmComponent_disable(celix_dm_component_t *component);
+static bool celix_dmComponent_isDisabled(celix_dm_component_t *component);
+static void celix_dmComponent_cleanupRemovedDependencies(celix_dm_component_t* component);
celix_dm_component_t* celix_dmComponent_create(bundle_context_t *context, const char* name) {
@@ -124,9 +134,10 @@ celix_dm_component_t* celix_dmComponent_createWithUUID(bundle_context_t *context
component->providedInterfaces = celix_arrayList_create();
component->dependencies = celix_arrayList_create();
+ component->removedDependencies = celix_arrayList_create();
celixThreadMutex_create(&component->mutex, NULL);
celixThreadCondition_init(&component->cond, NULL);
- component->isStarted = false;
+ component->isEnabled = false;
return component;
}
@@ -145,28 +156,48 @@ void component_destroy(celix_dm_component_t *component) {
celix_dmComponent_destroy(component);
}
-static void celix_dmComponent_waitForNoAddRemOrSetDependencyInProgress(celix_dm_component_t* component, bool lockOnMutex) {
- if (lockOnMutex) {
- celixThreadMutex_lock(&component->mutex);
- }
- struct timespec start = celix_gettime(CLOCK_MONOTONIC);
- while (component->nrOfSetAddRemCallsInProgress > 0) {
- celixThreadCondition_timedwaitRelative(&component->cond, &component->mutex, 1, 0);
- struct timespec now = celix_gettime(CLOCK_MONOTONIC);
- if (celix_difftime(&start, &now) > 5) {
- start = celix_gettime(CLOCK_MONOTONIC);
- fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_WARNING, "Add, remove or set dependency call still in progress for component %s (uuid=%s)", component->name, component->uuid);
+//static void celix_dmComponent_waitForNoAddRemOrSetDependencyInProgress(celix_dm_component_t* component, bool lockOnMutex) {
+// if (lockOnMutex) {
+// celixThreadMutex_lock(&component->mutex);
+// }
+// struct timespec start = celix_gettime(CLOCK_MONOTONIC);
+// while (component->nrOfSvcDepependenciesInProgress > 0) {
+// celixThreadCondition_timedwaitRelative(&component->cond, &component->mutex, 1, 0);
+// struct timespec now = celix_gettime(CLOCK_MONOTONIC);
+// if (celix_difftime(&start, &now) > 5) {
+// start = celix_gettime(CLOCK_MONOTONIC);
+// fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_WARNING, "Add, remove or set dependency call still in progress or a stop service tracker is still in progress for component %s (uuid=%s)", component->name, component->uuid);
+// }
+// }
+// if (lockOnMutex) {
+// celixThreadMutex_unlock(&component->mutex);
+// }
+//}
+
+void celix_dmComponent_destroy(celix_dm_component_t *component) {
+ if (component != NULL) {
+ celix_dmComponent_destroyAsync(component, NULL, NULL);
+ if (celix_framework_isCurrentThreadTheEventLoop(component->context->framework)) {
+ fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_ERROR,
+ "Cannot synchonized destroy dm component on Celix event thread. Use celix_dmComponent_destroyAsync instead!");
+ } else {
+ //TODO use done callback to sync (note that eventid is not enough, because another destroy event can be created.
+ celix_bundleContext_waitForEvents(component->context);
}
}
- if (lockOnMutex) {
- celixThreadMutex_unlock(&component->mutex);
- }
}
-void celix_dmComponent_destroy(celix_dm_component_t *component) {
- if (component) {
- celix_dmComponent_stop(component); //all service deregistered // all svc tracker stopped
+struct celix_dm_component_destroy_data {
+ celix_dm_component_t* cmp;
+ void* doneData;
+ void (*doneCallback)(void*);
+};
+static void celix_dmComponent_destroyCallback(void *voidData) {
+ struct celix_dm_component_destroy_data *data = voidData;
+ celix_dm_component_t *component = data->cmp;
+ celix_dmComponent_disable(component); //all service deregistered // all svc tracker stopped
+ if (celix_dmComponent_isDisabled(component)) {
for (int i = 0; i < celix_arrayList_size(component->providedInterfaces); ++i) {
dm_interface_t *interface = celix_arrayList_get(component->providedInterfaces, i);
@@ -178,18 +209,54 @@ void celix_dmComponent_destroy(celix_dm_component_t *component) {
}
celix_arrayList_destroy(component->providedInterfaces);
-
- celix_dmComponent_waitForNoAddRemOrSetDependencyInProgress(component, true);
-
for (int i = 0; i < celix_arrayList_size(component->dependencies); ++i) {
- celix_dm_service_dependency_t* dep = celix_arrayList_get(component->dependencies, i);
- celix_dmServiceDependency_destroy(dep);
+ celix_dm_service_dependency_t *dep = celix_arrayList_get(component->dependencies, i);
+ celix_dmServiceDependency_free(dep);
}
celix_arrayList_destroy(component->dependencies);
+
+ for (int i = 0; i < celix_arrayList_size(component->removedDependencies); ++i) {
+ celix_dm_service_dependency_t *dep = celix_arrayList_get(component->removedDependencies, i);
+ celix_dmServiceDependency_free(dep);
+ }
+ celix_arrayList_destroy(component->removedDependencies);
+
celixThreadMutex_destroy(&component->mutex);
celixThreadCondition_destroy(&component->cond);
-
free(component);
+
+ if (data->doneCallback) {
+ data->doneCallback(data->doneData);
+ }
+ free(data);
+ } else {
+ //not yet disabled, adding a new event on the event queue
+ celix_bundle_t* bnd = celix_bundleContext_getBundle(component->context);
+ celix_framework_fireGenericEvent(
+ component->context->framework, -1, celix_bundle_getId(bnd),
+ "destroy dm component",
+ data,
+ celix_dmComponent_destroyCallback,
+ NULL,
+ NULL);
+ }
+}
+
+void celix_dmComponent_destroyAsync(celix_dm_component_t *component, void *doneData, void (*doneCallback)(void*)) {
+ if (component != NULL) {
+ struct celix_dm_component_destroy_data* data = malloc(sizeof(*data));
+ data->cmp = component;
+ data->doneData = doneData;
+ data->doneCallback = doneCallback;
+
+ celix_bundle_t* bnd = celix_bundleContext_getBundle(component->context);
+ celix_framework_fireGenericEvent(
+ component->context->framework, -1, celix_bundle_getId(bnd),
+ "destroy dm component",
+ data,
+ celix_dmComponent_destroyCallback,
+ NULL,
+ NULL);
}
}
@@ -198,21 +265,21 @@ const char* celix_dmComponent_getUUID(celix_dm_component_t* cmp) {
return cmp->uuid;
}
-//call with lock
-static void celix_dmComponent_updateFilterOutOwnSvcDependencies(celix_dm_component_t* component) {
- for (int i = 0; i < celix_arrayList_size(component->dependencies); ++i) {
- celix_dm_service_dependency_t* dep = celix_arrayList_get(component->dependencies, i);
- bool filterOut = false;
- for (int k = 0; k < celix_arrayList_size(component->providedInterfaces); ++k) {
- dm_interface_t* intf = celix_arrayList_get(component->providedInterfaces, k);
- if (celix_utils_stringEquals(intf->serviceName, dep->serviceName)) {
- filterOut = true;
- break;
- }
- }
- celix_dmServiceDependency_setFilterOutOwnSvcDependencies(dep, filterOut);
- }
-}
+////call with lock
+//static void celix_dmComponent_updateFilterOutOwnSvcDependencies(celix_dm_component_t* component) {
+// for (int i = 0; i < celix_arrayList_size(component->dependencies); ++i) {
+// celix_dm_service_dependency_t* dep = celix_arrayList_get(component->dependencies, i);
+// bool filterOut = false;
+// for (int k = 0; k < celix_arrayList_size(component->providedInterfaces); ++k) {
+// dm_interface_t* intf = celix_arrayList_get(component->providedInterfaces, k);
+// if (celix_utils_stringEquals(intf->serviceName, dep->serviceName)) {
+// filterOut = true;
+// break;
+// }
+// }
+// celix_dmServiceDependency_setFilterOutOwnSvcDependencies(dep, filterOut);
+// }
+//}
celix_status_t component_addServiceDependency(celix_dm_component_t *component, celix_dm_service_dependency_t *dep) {
return celix_dmComponent_addServiceDependency(component, dep);
@@ -220,35 +287,37 @@ celix_status_t component_addServiceDependency(celix_dm_component_t *component, c
celix_status_t celix_dmComponent_addServiceDependency(celix_dm_component_t *component, celix_dm_service_dependency_t *dep) {
celix_status_t status = CELIX_SUCCESS;
- celix_serviceDependency_setComponent(dep, component);
+ celix_dmServiceDependency_setComponent(dep, component);
celixThreadMutex_lock(&component->mutex);
arrayList_add(component->dependencies, dep);
bool startDep = component->state != DM_CMP_STATE_INACTIVE;
if (startDep) {
- celix_serviceDependency_start(dep);
+ celix_dmServiceDependency_enable(dep);
}
- celix_dmComponent_updateFilterOutOwnSvcDependencies(component);
+ //celix_dmComponent_updateFilterOutOwnSvcDependencies(component);
+ celix_dmComponent_cleanupRemovedDependencies(component);
celixThreadMutex_unlock(&component->mutex);
- component_handleChange(component);
+ celix_dmComponent_handleChange(component);
return status;
}
celix_status_t celix_dmComponent_removeServiceDependency(celix_dm_component_t *component, celix_dm_service_dependency_t *dep) {
celixThreadMutex_lock(&component->mutex);
- celix_dmComponent_waitForNoAddRemOrSetDependencyInProgress(component, false);
- arrayList_removeElement(component->dependencies, dep);
- bool stopDependency = component->state != DM_CMP_STATE_INACTIVE;
- if (stopDependency) {
- celix_serviceDependency_stop(dep);
- }
- celix_dmServiceDependency_destroy(dep);
- celix_dmComponent_updateFilterOutOwnSvcDependencies(component);
+ //celix_dmComponent_waitForNoAddRemOrSetDependencyInProgress(component, false);
+ celix_arrayList_remove(component->dependencies, dep);
+ bool disableDependency = component->state != DM_CMP_STATE_INACTIVE;
+ if (disableDependency) {
+ celix_dmServiceDependency_disable(dep);
+ }
+ celix_arrayList_add(component->removedDependencies, dep);
+ //celix_dmComponent_updateFilterOutOwnSvcDependencies(component);
+ celix_dmComponent_cleanupRemovedDependencies(component);
celixThreadMutex_unlock(&component->mutex);
- component_handleChange(component);
+ celix_dmComponent_handleChange(component);
return CELIX_SUCCESS;
}
@@ -280,26 +349,72 @@ celix_status_t component_removeServiceDependency(celix_dm_component_t *component
return celix_dmComponent_removeServiceDependency(component, dependency);
}
-celix_status_t celix_private_dmComponent_start(celix_dm_component_t *component) {
+celix_status_t celix_private_dmComponent_enable(celix_dm_component_t *component) {
celixThreadMutex_lock(&component->mutex);
- if (!component->isStarted) {
- component->isStarted = true;
+ if (!component->isEnabled) {
+ component->isEnabled = true;
}
celixThreadMutex_unlock(&component->mutex);
- component_handleChange(component);
+ celix_dmComponent_handleChange(component);
return CELIX_SUCCESS;
}
-static celix_status_t celix_dmComponent_stop(celix_dm_component_t *component) {
+static celix_status_t celix_dmComponent_disable(celix_dm_component_t *component) {
celixThreadMutex_lock(&component->mutex);
- if (component->isStarted) {
- component->isStarted = false;
+ if (component->isEnabled) {
+ component->isEnabled = false;
}
celixThreadMutex_unlock(&component->mutex);
- component_handleChange(component);
+ celix_dmComponent_handleChange(component);
return CELIX_SUCCESS;
}
+static void celix_dmComponent_cleanupRemovedDependencies(celix_dm_component_t* component) {
+ //note should be called with lock
+ bool removedDep = true;
+ while (removedDep) {
+ removedDep = false;
+ for (int i = 0 ; i < celix_arrayList_size(component->removedDependencies); ++i) {
+ celix_dm_service_dependency_t* dep = celix_arrayList_get(component->removedDependencies, i);
+ if (celix_dmServiceDependency_isDisabled(dep)) {
+ celix_arrayList_remove(component->removedDependencies, dep);
+ celix_dmServiceDependency_destroy(dep);
+ removedDep = true;
+ break;
+ }
+ }
+ }
+}
+
+static bool celix_dmComponent_areAllDependenciesDisabled(celix_dm_component_t* component) {
+ //note should be called with lock
+ bool allDisabled = true;
+ for (int i = 0 ; allDisabled && i < celix_arrayList_size(component->dependencies); ++i) {
+ celix_dm_service_dependency_t* dep = celix_arrayList_get(component->dependencies, i);
+ if (!celix_dmServiceDependency_isDisabled(dep)) {
+ allDisabled = false;
+ }
+ }
+ for (int i = 0 ; allDisabled && i < celix_arrayList_size(component->removedDependencies); ++i) {
+ celix_dm_service_dependency_t* dep = celix_arrayList_get(component->removedDependencies, i);
+ if (!celix_dmServiceDependency_isDisabled(dep)) {
+ allDisabled = false;
+ }
+ }
+ return allDisabled;
+}
+
+static bool celix_dmComponent_isDisabled(celix_dm_component_t *component) {
+ bool isStopped;
+ celixThreadMutex_lock(&component->mutex);
+ isStopped =
+ !component->isEnabled &&
+ component->state == DM_CMP_STATE_INACTIVE &&
+ celix_dmComponent_areAllDependenciesDisabled(component);
+ celixThreadMutex_unlock(&component->mutex);
+ return isStopped;
+}
+
celix_status_t component_setCLanguageProperty(celix_dm_component_t *component, bool setCLangProp) {
return celix_dmComponent_setCLanguageProperty(component, setCLangProp);
@@ -342,7 +457,7 @@ celix_status_t celix_dmComponent_addInterface(celix_dm_component_t *component, c
interface->svcId= -1L;
celix_arrayList_add(component->providedInterfaces, interface);
if (component->state == DM_CMP_STATE_TRACKING_OPTIONAL) {
- component_registerServices(component);
+ celix_dmComponent_registerServices(component);
}
celixThreadMutex_unlock(&component->mutex);
} else {
@@ -409,13 +524,13 @@ celix_status_t celix_private_dmComponent_handleEvent(celix_dm_component_t *compo
celix_status_t status = CELIX_SUCCESS;
switch (event->eventType) {
case CELIX_DM_EVENT_SVC_ADD:
- component_handleAdd(component, event);
+ celix_dmComponent_handleAdd(component, event);
break;
case CELIX_DM_EVENT_SVC_REM:
- component_handleRemove(component, event);
+ celix_dmComponent_handleRemove(component, event);
break;
case CELIX_DM_EVENT_SVC_SET:
- component_handleSet(component, event);
+ celix_dmComponent_handleSet(component, event);
break;
default:
break;
@@ -423,34 +538,42 @@ celix_status_t celix_private_dmComponent_handleEvent(celix_dm_component_t *compo
return status;
}
-static celix_status_t component_suspend(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency) {
+static celix_status_t celix_dmComponent_suspend(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency) {
celix_status_t status = CELIX_SUCCESS;
dm_service_dependency_strategy_t strategy = celix_dmServiceDependency_getStrategy(dependency);
if (strategy == DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND && component->callbackStop != NULL) {
- component_unregisterServices(component);
+ fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_TRACE,
+ "Suspending component %s (uuid=%s)",
+ component->name,
+ component->uuid);
+ celix_dmComponent_unregisterServices(component);
status = component->callbackStop(component->implementation);
}
return status;
}
-static celix_status_t component_resume(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency) {
+static celix_status_t celix_dmComponent_resume(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency) {
celix_status_t status = CELIX_SUCCESS;
dm_service_dependency_strategy_t strategy = celix_dmServiceDependency_getStrategy(dependency);
if (strategy == DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND && component->callbackStop != NULL) {
- component_registerServices(component);
+ fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_TRACE,
+ "Resuming component %s (uuid=%s)",
+ component->name,
+ component->uuid);
+ celix_dmComponent_registerServices(component);
status = component->callbackStart(component->implementation);
}
return status;
}
-static celix_status_t component_handleEvent(celix_dm_component_t *component, const celix_dm_event_t* event, celix_status_t (*setAddOrRemFp)(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props)) {
+static celix_status_t celix_dmComponent_handleEvent(celix_dm_component_t *component, const celix_dm_event_t* event, celix_status_t (*setAddOrRemFp)(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props), const char *invokeName) {
bool needSuspend = false;
celixThreadMutex_lock(&component->mutex);
- component->nrOfSetAddRemCallsInProgress += 1;
+ component->nrOfSvcDepependenciesInProgress += 1;
celixThreadCondition_broadcast(&component->cond);
switch (component->state) {
case DM_CMP_STATE_TRACKING_OPTIONAL:
- if (celix_serviceDependency_hasAddCallback(event->dep)) { //if to prevent unneeded suspends
+ if (celix_dmServiceDependency_hasAddCallback(event->dep)) { //if to prevent unneeded suspends
needSuspend = true;
}
break;
@@ -459,40 +582,46 @@ static celix_status_t component_handleEvent(celix_dm_component_t *component, con
}
celixThreadMutex_unlock(&component->mutex);
if (needSuspend) {
- component_suspend(component, event->dep);
- }
+ celix_dmComponent_suspend(component, event->dep);
+ }
+ fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_TRACE,
+ "Calling %s service for component %s (uuid=%s) on service dependency with type %s",
+ invokeName,
+ component->name,
+ component->uuid,
+ event->dep->serviceName);
setAddOrRemFp(event->dep, event->svc, event->props);
if (needSuspend) {
- component_resume(component, event->dep);
+ celix_dmComponent_resume(component, event->dep);
}
celixThreadMutex_lock(&component->mutex);
- component->nrOfSetAddRemCallsInProgress -= 1;
+ component->nrOfSvcDepependenciesInProgress -= 1;
celixThreadCondition_broadcast(&component->cond);
celixThreadMutex_unlock(&component->mutex);
- component_handleChange(component);
+ celix_dmComponent_handleChange(component);
return CELIX_SUCCESS;
}
-static celix_status_t component_handleAdd(celix_dm_component_t *component, const celix_dm_event_t* event) {
- return component_handleEvent(component, event, celix_serviceDependency_invokeAdd);
+static celix_status_t celix_dmComponent_handleAdd(celix_dm_component_t *component, const celix_dm_event_t* event) {
+ return celix_dmComponent_handleEvent(component, event, celix_dmServiceDependency_invokeAdd, "add");
}
-static celix_status_t component_handleRemove(celix_dm_component_t *component, const celix_dm_event_t* event) {
- return component_handleEvent(component, event, celix_serviceDependency_invokeRemove);
+static celix_status_t celix_dmComponent_handleRemove(celix_dm_component_t *component, const celix_dm_event_t* event) {
+ return celix_dmComponent_handleEvent(component, event, celix_dmServiceDependency_invokeRemove, "remove");
}
-static celix_status_t component_handleSet(celix_dm_component_t *component, const celix_dm_event_t* event) {
- return component_handleEvent(component, event, celix_serviceDependency_invokeSet);
+static celix_status_t celix_dmComponent_handleSet(celix_dm_component_t *component, const celix_dm_event_t* event) {
+ return celix_dmComponent_handleEvent(component, event, celix_dmServiceDependency_invokeSet, "set");
}
/**
* perform state transition. This call should be called with the component->mutex locked.
*/
-static celix_status_t component_startDependencies(celix_dm_component_t *component) {
+static celix_status_t celix_dmComponent_disableDependencies(celix_dm_component_t *component) {
for (int i = 0; i < celix_arrayList_size(component->dependencies); i++) {
celix_dm_service_dependency_t *dependency = arrayList_get(component->dependencies, i);
if (!celix_dmServiceDependency_isTrackerOpen(dependency)) {
- celix_serviceDependency_start(dependency);
+ celix_dmServiceDependency_enable(dependency);
}
}
return CELIX_SUCCESS;
@@ -501,13 +630,35 @@ static celix_status_t component_startDependencies(celix_dm_component_t *componen
/**
* perform state transition. This call should be called with the component->mutex locked.
*/
-static celix_status_t component_stopDependencies(celix_dm_component_t *component) {
+static celix_status_t celix_dmComponent_enableDependencies(celix_dm_component_t *component) {
+
+ celix_array_list_t* depsToStop = NULL;
+
for (int i = 0; i < celix_arrayList_size(component->dependencies); i++) {
celix_dm_service_dependency_t *dependency = arrayList_get(component->dependencies, i);
if (celix_dmServiceDependency_isTrackerOpen(dependency)) {
- celix_serviceDependency_stop(dependency);
+ if (depsToStop == NULL) {
+ depsToStop = celix_arrayList_create();
+ }
+ celix_arrayList_add(depsToStop, dependency);
+ component->nrOfSvcDepependenciesInProgress += 1;
+ celixThreadCondition_broadcast(&component->cond);
}
}
+
+ if (depsToStop != NULL) {
+ celixThreadMutex_unlock(&component->mutex);
+ for (int i = 0; i < celix_arrayList_size(depsToStop); ++i) {
+ celix_dm_service_dependency_t *dependency = arrayList_get(depsToStop, i);
+ celix_dmServiceDependency_disable(dependency);
+ }
+ celixThreadMutex_lock(&component->mutex);
+
+ component->nrOfSvcDepependenciesInProgress -= celix_arrayList_size(depsToStop);
+ celixThreadCondition_broadcast(&component->cond);
+ celix_arrayList_destroy(depsToStop);
+ }
+
return CELIX_SUCCESS;
}
@@ -515,7 +666,7 @@ static celix_status_t component_stopDependencies(celix_dm_component_t *component
/**
* Calculate and handle state change. This call should be called with the component->mutex locked.
*/
-static void component_handleChangeOnEventThread(void *data) {
+static void celix_dmComponent_handleChangeOnEventThread(void *data) {
celix_dm_component_t* component = data;
assert(celix_framework_isCurrentThreadTheEventLoop(component->context->framework));
@@ -525,9 +676,9 @@ static void component_handleChangeOnEventThread(void *data) {
bool transition = false;
do {
oldState = component->state;
- celix_status_t status = component_calculateNewState(component, oldState, &newState);
+ celix_status_t status = celix_dmComponent_calculateNewState(component, oldState, &newState);
if (status == CELIX_SUCCESS) {
- status = component_performTransition(component, oldState, newState, &transition);
+ status = celix_dmComponent_performTransition(component, oldState, newState, &transition);
component->state = newState;
}
@@ -538,9 +689,9 @@ static void component_handleChangeOnEventThread(void *data) {
celixThreadMutex_unlock(&component->mutex);
}
-static celix_status_t component_handleChange(celix_dm_component_t *component) {
+static celix_status_t celix_dmComponent_handleChange(celix_dm_component_t *component) {
if (celix_framework_isCurrentThreadTheEventLoop(component->context->framework)) {
- component_handleChangeOnEventThread(component);
+ celix_dmComponent_handleChangeOnEventThread(component);
} else {
long eventId = celix_framework_fireGenericEvent(
component->context->framework,
@@ -548,7 +699,7 @@ static celix_status_t component_handleChange(celix_dm_component_t *component) {
celix_bundle_getId(component->context->bundle),
"dm component handle change",
component,
- component_handleChangeOnEventThread,
+ celix_dmComponent_handleChangeOnEventThread,
NULL,
NULL);
celix_framework_waitForGenericEvent(component->context->framework, eventId);
@@ -556,38 +707,21 @@ static celix_status_t component_handleChange(celix_dm_component_t *component) {
return CELIX_SUCCESS;
}
-
-///**
-// * Check if service trackers are still open for the dependencies.
-// * This call should be called with the component->mutex locked.
-// */
-//static bool component_allDependencyStopped(celix_dm_component_t* component) {
-// bool anyOpen = false;
-// for (int i = 0; i < celix_arrayList_size(component->dependencies); ++i) {
-// celix_dm_service_dependency_t *dep = celix_arrayList_get(component->dependencies, i);
-// if (celix_dmServiceDependency_isTrackerOpen(dep)) {
-// anyOpen = true;
-// break;
-// }
-// }
-// return !anyOpen;
-//}
-
/**
* Calculate possible state change. This call should be called with the component->mutex locked.
*/
-static celix_status_t component_calculateNewState(celix_dm_component_t *component, celix_dm_component_state_t currentState, celix_dm_component_state_t *newState) {
+static celix_status_t celix_dmComponent_calculateNewState(celix_dm_component_t *component, celix_dm_component_state_t currentState, celix_dm_component_state_t *newState) {
celix_status_t status = CELIX_SUCCESS;
- bool allResolved = component_areAllRequiredServiceDependenciesResolved(component);
+ bool allResolved = celix_dmComponent_areAllRequiredServiceDependenciesResolved(component);
if (currentState == DM_CMP_STATE_INACTIVE) {
- if (component->isStarted) {
+ if (component->isEnabled) {
*newState = DM_CMP_STATE_WAITING_FOR_REQUIRED;
} else {
*newState = currentState;
}
} else if (currentState == DM_CMP_STATE_WAITING_FOR_REQUIRED) {
- if (!component->isStarted) {
+ if (!component->isEnabled) {
*newState = DM_CMP_STATE_INACTIVE;
} else {
if (allResolved) {
@@ -597,7 +731,7 @@ static celix_status_t component_calculateNewState(celix_dm_component_t *componen
}
}
} else if (currentState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
- if (!component->isStarted) {
+ if (!component->isEnabled) {
*newState = DM_CMP_STATE_WAITING_FOR_REQUIRED;
} else {
if (allResolved) {
@@ -607,7 +741,7 @@ static celix_status_t component_calculateNewState(celix_dm_component_t *componen
}
}
} else if (currentState == DM_CMP_STATE_TRACKING_OPTIONAL) {
- if (component->isStarted && allResolved) {
+ if (component->isEnabled && allResolved) {
*newState = currentState;
} else {
*newState = DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED;
@@ -624,14 +758,23 @@ static celix_status_t component_calculateNewState(celix_dm_component_t *componen
/**
* perform state transition. This call should be called with the component->mutex locked.
*/
-static celix_status_t component_performTransition(celix_dm_component_t *component, celix_dm_component_state_t oldState, celix_dm_component_state_t newState, bool *transition) {
- celix_status_t status = CELIX_SUCCESS;
- fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_TRACE, "performing transition for component %s from state %i to state %i\n", component->name, oldState, newState);
-
+static celix_status_t celix_dmComponent_performTransition(celix_dm_component_t *component, celix_dm_component_state_t oldState, celix_dm_component_state_t newState, bool *transition) {
if (oldState == newState) {
*transition = false;
- } else if (oldState == DM_CMP_STATE_INACTIVE && newState == DM_CMP_STATE_WAITING_FOR_REQUIRED) {
- component_startDependencies(component);
+ return CELIX_SUCCESS;
+ }
+
+ fw_log(component->context->framework->logger,
+ CELIX_LOG_LEVEL_TRACE,
+ "performing transition for component '%s' (uuid=%s) from state %s to state %s",
+ component->name,
+ component->uuid,
+ celix_dmComponent_stateToString(oldState),
+ celix_dmComponent_stateToString(newState));
+
+ celix_status_t status = CELIX_SUCCESS;
+ if (oldState == DM_CMP_STATE_INACTIVE && newState == DM_CMP_STATE_WAITING_FOR_REQUIRED) {
+ celix_dmComponent_disableDependencies(component);
*transition = true;
} else if (oldState == DM_CMP_STATE_WAITING_FOR_REQUIRED && newState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
if (component->callbackInit) {
@@ -642,10 +785,10 @@ static celix_status_t component_performTransition(celix_dm_component_t *componen
if (component->callbackStart) {
status = component->callbackStart(component->implementation);
}
- component_registerServices(component);
+ celix_dmComponent_registerServices(component);
*transition = true;
} else if (oldState == DM_CMP_STATE_TRACKING_OPTIONAL && newState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
- component_unregisterServices(component);
+ celix_dmComponent_unregisterServices(component);
if (component->callbackStop) {
status = component->callbackStop(component->implementation);
}
@@ -656,7 +799,7 @@ static celix_status_t component_performTransition(celix_dm_component_t *componen
}
*transition = true;
} else if (oldState == DM_CMP_STATE_WAITING_FOR_REQUIRED && newState == DM_CMP_STATE_INACTIVE) {
- component_stopDependencies(component);
+ celix_dmComponent_enableDependencies(component);
*transition = true;
}
@@ -666,13 +809,13 @@ static celix_status_t component_performTransition(celix_dm_component_t *componen
/**
* Check if all required dependencies are resolved. This call should be called with the component->mutex locked.
*/
-static bool component_areAllRequiredServiceDependenciesResolved(celix_dm_component_t *component) {
+static bool celix_dmComponent_areAllRequiredServiceDependenciesResolved(celix_dm_component_t *component) {
bool allResolved = true;
for (int i = 0; i < celix_arrayList_size(component->dependencies); i++) {
celix_dm_service_dependency_t *dependency = celix_arrayList_get(component->dependencies, i);
bool started = celix_dmServiceDependency_isTrackerOpen(dependency);
bool required = celix_dmServiceDependency_isRequired(dependency);
- bool available = celix_serviceDependency_isAvailable(dependency);
+ bool available = celix_dmServiceDependency_isAvailable(dependency);
if (!started) {
allResolved = false;
break;
@@ -688,7 +831,7 @@ static bool component_areAllRequiredServiceDependenciesResolved(celix_dm_compone
/**
* Register component services (if not already registered). This call should be called with the component->mutex locked.
*/
-static celix_status_t component_registerServices(celix_dm_component_t *component) {
+static celix_status_t celix_dmComponent_registerServices(celix_dm_component_t *component) {
for (int i = 0; i < celix_arrayList_size(component->providedInterfaces); i++) {
dm_interface_t *interface = arrayList_get(component->providedInterfaces, i);
if (interface->svcId == -1L) {
@@ -698,6 +841,11 @@ static celix_status_t component_registerServices(celix_dm_component_t *component
opts.svc = (void*)interface->service;
opts.serviceName = interface->serviceName;
opts.serviceLanguage = celix_properties_get(regProps, CELIX_FRAMEWORK_SERVICE_LANGUAGE, NULL);
+ fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_TRACE,
+ "Async registering service %s for component %s (uuid=%s)",
+ interface->serviceName,
+ component->name,
+ component->uuid);
interface->svcId = celix_bundleContext_registerServiceWithOptionsAsync(component->context, &opts);
if (!celix_framework_isCurrentThreadTheEventLoop(component->context->framework)) {
celix_framework_waitForAsyncRegistration(component->context->framework, interface->svcId);
@@ -711,23 +859,33 @@ static celix_status_t component_registerServices(celix_dm_component_t *component
/**
* Unregister component services. This call should be called with the component->mutex locked.
*/
-static celix_status_t component_unregisterServices(celix_dm_component_t *component) {
+static celix_status_t celix_dmComponent_unregisterServices(celix_dm_component_t *component) {
celix_status_t status = CELIX_SUCCESS;
- celix_array_list_t* ids = celix_arrayList_create();
+ celix_array_list_t* ids = NULL;
for (int i = 0; i < celix_arrayList_size(component->providedInterfaces); ++i) {
dm_interface_t *interface = arrayList_get(component->providedInterfaces, i);
+ if (ids == NULL) {
+ ids = celix_arrayList_create();
+ }
celix_arrayList_addLong(ids, interface->svcId);
interface->svcId = -1L;
+ fw_log(component->context->framework->logger, CELIX_LOG_LEVEL_TRACE,
+ "Unregistering service %s for component %s (uuid=%s)",
+ interface->serviceName,
+ component->name,
+ component->uuid);
}
- celixThreadMutex_unlock(&component->mutex);
- for (int i = 0; i < celix_arrayList_size(ids); ++i) {
- long svcId = celix_arrayList_getLong(ids, i);
- celix_bundleContext_unregisterService(component->context, svcId);
+ if (ids != NULL) {
+ celixThreadMutex_unlock(&component->mutex);
+ for (int i = 0; i < celix_arrayList_size(ids); ++i) {
+ long svcId = celix_arrayList_getLong(ids, i);
+ celix_bundleContext_unregisterService(component->context, svcId);
+ }
+ celix_arrayList_destroy(ids);
+ celixThreadMutex_lock(&component->mutex);
}
- celixThreadMutex_lock(&component->mutex);
- celix_arrayList_destroy(ids);
return status;
}
@@ -848,3 +1006,16 @@ bool celix_dmComponent_isActive(celix_dm_component_t *component) {
celixThreadMutex_unlock(&component->mutex);
return active;
}
+
+const char* celix_dmComponent_stateToString(celix_dm_component_state_t state) {
+ switch(state) {
+ case DM_CMP_STATE_INACTIVE:
+ return "DM_CMP_STATE_INACTIVE";
+ case DM_CMP_STATE_WAITING_FOR_REQUIRED:
+ return "DM_CMP_STATE_WAITING_FOR_REQUIRED";
+ case DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+ return "DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED";
+ default: //only DM_CMP_STATE_TRACKING_OPTIONAL left
+ return "DM_CMP_STATE_TRACKING_OPTIONAL";
+ }
+}
diff --git a/libs/framework/src/dm_component_impl.h b/libs/framework/src/dm_component_impl.h
index 452f89f..83485f3 100644
--- a/libs/framework/src/dm_component_impl.h
+++ b/libs/framework/src/dm_component_impl.h
@@ -35,7 +35,7 @@ extern "C" {
#include "dm_service_dependency_impl.h"
#include "celix_dm_event.h"
-celix_status_t celix_private_dmComponent_start(celix_dm_component_t *component);
+celix_status_t celix_private_dmComponent_enable(celix_dm_component_t *component);
celix_status_t celix_private_dmComponent_handleEvent(celix_dm_component_t *component, const celix_dm_event_t* event);
#ifdef __cplusplus
diff --git a/libs/framework/src/dm_dependency_manager_impl.c b/libs/framework/src/dm_dependency_manager_impl.c
index 5073072..7725491 100644
--- a/libs/framework/src/dm_dependency_manager_impl.c
+++ b/libs/framework/src/dm_dependency_manager_impl.c
@@ -28,7 +28,8 @@
#include "celix_dependency_manager.h"
#include "celix_bundle.h"
#include "celix_framework.h"
-
+#include "bundle_context_private.h"
+#include "framework_private.h"
celix_dependency_manager_t* celix_private_dependencyManager_create(celix_bundle_context_t *context) {
celix_dependency_manager_t *manager = calloc(1, sizeof(*manager));
@@ -59,32 +60,38 @@ celix_status_t celix_dependencyManager_add(celix_dependency_manager_t *manager,
celix_arrayList_add(manager->components, component);
celixThreadMutex_unlock(&manager->mutex);
- status = celix_private_dmComponent_start(component);
+ status = celix_private_dmComponent_enable(component);
return status;
}
-
-celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
- celix_status_t status;
-
- celix_array_list_entry_t entry;
- memset(&entry, 0, sizeof(entry));
- entry.voidPtrVal = component;
+celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
+ celix_status_t status;
celixThreadMutex_lock(&manager->mutex);
- int index = celix_arrayList_indexOf(manager->components, entry);
+ bool found = false;
+ for (int i = 0; i < celix_arrayList_size(manager->components); ++i) {
+ celix_dm_component_t* visit = celix_arrayList_get(manager->components, i);
+ if (visit == component) {
+ celix_arrayList_removeAt(manager->components, i);
+ found = true;
+ break;
+ }
+ }
+ celixThreadMutex_unlock(&manager->mutex);
- if (index >= 0) {
- celix_arrayList_removeAt(manager->components, index);
- celixThreadMutex_unlock(&manager->mutex);
- celix_dmComponent_destroy(component);
- } else {
- celixThreadMutex_unlock(&manager->mutex);
- fprintf(stderr, "Cannot find component with pointer %p\n", component);
- status = CELIX_BUNDLE_EXCEPTION;
- }
+ if (!found) {
+ fw_log(manager->ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot find component %s (uuid=%s)",
+ celix_dmComponent_getName(component),
+ celix_dmComponent_getUUID(component));
+ status = CELIX_BUNDLE_EXCEPTION;
+ }
+ return status;
+}
+celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
+ celix_status_t status = celix_dependencyManager_removeWithoutDestroy(manager, component);
+ celix_dmComponent_destroy(component);
return status;
}
diff --git a/libs/framework/src/dm_service_dependency.c b/libs/framework/src/dm_service_dependency.c
index 80bf71a..ebaf76b 100644
--- a/libs/framework/src/dm_service_dependency.c
+++ b/libs/framework/src/dm_service_dependency.c
@@ -19,6 +19,8 @@
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
+#include <celix_bundle.h>
#include "celix_constants.h"
#include "celix_utils.h"
@@ -48,6 +50,8 @@ celix_status_t serviceDependency_create(celix_dm_service_dependency_t **dependen
celix_dm_service_dependency_t* celix_dmServiceDependency_create() {
celix_dm_service_dependency_t *dep = calloc(1, sizeof(*dep));
dep->strategy = DM_SERVICE_DEPENDENCY_DEFAULT_STRATEGY;
+ dep->svcTrackerId = -1;
+ celixThreadMutex_create(&dep->mutex, NULL);
return dep;
}
@@ -58,16 +62,81 @@ celix_status_t serviceDependency_destroy(celix_dm_service_dependency_t **depende
return CELIX_SUCCESS;
}
-void celix_dmServiceDependency_destroy(celix_dm_service_dependency_t *dep) {
- if (dep != NULL) {
- celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(dep->component);
- celix_bundleContext_waitForAsyncStopTracker(ctx, dep->svcTrackerId);
+void celix_dmServiceDependency_free(celix_dm_service_dependency_t* dep) {
+ if (dep != NULL) {
celixThreadMutex_destroy(&dep->mutex);
free(dep->serviceName);
free(dep->versionRange);
free(dep->filter);
- free(dep);
- }
+ free(dep);
+ }
+}
+
+void celix_dmServiceDependency_destroy(celix_dm_service_dependency_t *dep) {
+ if (dep != NULL && dep->component != NULL) {
+ celix_bundle_context_t *ctx = celix_dmComponent_getBundleContext(dep->component);
+ celix_dmServiceDependency_destroyAsync(dep, NULL, NULL);
+ if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+ fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR,
+ "Cannot synchonized destroy dm service dependency on Celix event thread. Use celix_dmServiceDependency_destroyAsync instead!");
+ } else {
+ //TODO use done callback to sync (note that eventid is not enough, because another destroy event can be created.
+ celix_bundleContext_waitForEvents(ctx);
+ }
+ } else {
+ celix_dmServiceDependency_free(dep);
+ }
+}
+
+
+
+struct celix_dm_service_dependency_destroy_data {
+ celix_dm_service_dependency_t* dep;
+ void* doneData;
+ void (*doneCallback)(void*);
+};
+
+static void celix_dmServiceDependency_destroyCallback(void *voidData) {
+ struct celix_dm_service_dependency_destroy_data* data = voidData;
+
+ celix_dmServiceDependency_disable(data->dep);
+ if (data->dep->component == NULL || celix_dmServiceDependency_isDisabled(data->dep)) {
+ celix_dmServiceDependency_free(data->dep);
+ if (data->doneCallback) {
+ data->doneCallback(data->doneData);
+ }
+ free(data);
+ } else {
+ celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(data->dep->component);
+ celix_bundle_t* bnd = celix_bundleContext_getBundle(ctx);
+ celix_framework_fireGenericEvent(
+ ctx->framework, -1, celix_bundle_getId(bnd),
+ "destroy dm service dependency",
+ data,
+ celix_dmServiceDependency_destroyCallback,
+ NULL,
+ NULL);
+ }
+}
+
+void celix_dmServiceDependency_destroyAsync(celix_dm_service_dependency_t *dep, void *doneData, void (*doneCallback)(void*)) {
+ if (dep != NULL && dep->component != NULL) {
+ celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(dep->component);
+ celix_bundle_t* bnd = celix_bundleContext_getBundle(ctx);
+ struct celix_dm_service_dependency_destroy_data* data = malloc(sizeof(*data));
+ data->dep = dep;
+ data->doneData = doneData;
+ data->doneCallback = doneCallback;
+ celix_framework_fireGenericEvent(
+ ctx->framework, -1, celix_bundle_getId(bnd),
+ "destroy dm service dependency",
+ data,
+ celix_dmServiceDependency_destroyCallback,
+ NULL,
+ NULL);
+ } else if (dep != NULL) {
+ celix_dmServiceDependency_free(dep);
+ }
}
celix_status_t serviceDependency_setRequired(celix_dm_service_dependency_t *dependency, bool required) {
@@ -180,12 +249,12 @@ celix_status_t celix_dmServiceDependency_setCallbacksWithOptions(celix_dm_servic
return CELIX_SUCCESS;
}
-celix_status_t celix_serviceDependency_setComponent(celix_dm_service_dependency_t *dependency, celix_dm_component_t *component) {
+celix_status_t celix_dmServiceDependency_setComponent(celix_dm_service_dependency_t *dependency, celix_dm_component_t *component) {
dependency->component = component;
return CELIX_SUCCESS;
}
-celix_status_t celix_serviceDependency_start(celix_dm_service_dependency_t *dependency) {
+celix_status_t celix_dmServiceDependency_enable(celix_dm_service_dependency_t *dependency) {
celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(dependency->component);
if (dependency->serviceName == NULL && dependency->filter == NULL) {
@@ -195,8 +264,7 @@ celix_status_t celix_serviceDependency_start(celix_dm_service_dependency_t *depe
}
celixThreadMutex_lock(&dependency->mutex);
- if (!dependency->isTrackerOpen) {
- dependency->isTrackerOpen = true;
+ if (dependency->svcTrackerId == -1L) {
celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
opts.filter.filter = dependency->filter;
opts.filter.serviceName = dependency->serviceName;
@@ -218,31 +286,48 @@ celix_status_t celix_serviceDependency_start(celix_dm_service_dependency_t *depe
return CELIX_SUCCESS;
}
-celix_status_t celix_serviceDependency_stop(celix_dm_service_dependency_t *dependency) {
- celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(dependency->component);
+static void celix_serviceDependency_stopCallback(void *data) {
+ celix_dm_service_dependency_t* dependency = data;
+ celixThreadMutex_lock(&dependency->mutex);
+ dependency->nrOfActiveStoppingTrackers -= 1;
+ celixThreadMutex_unlock(&dependency->mutex);
+}
+celix_status_t celix_dmServiceDependency_disable(celix_dm_service_dependency_t *dependency) {
celixThreadMutex_lock(&dependency->mutex);
- bool open = dependency->isTrackerOpen;
- dependency->isTrackerOpen = false;
- if (open && dependency->svcTrackerId >= 0) {
- celix_bundleContext_stopTrackerAsync(ctx, dependency->svcTrackerId, NULL, NULL);
+ if (dependency->svcTrackerId >= 0) {
+ celix_bundle_context_t* ctx = celix_dmComponent_getBundleContext(dependency->component);
+ celix_bundleContext_stopTrackerAsync(ctx, dependency->svcTrackerId, dependency, celix_serviceDependency_stopCallback);
+ dependency->svcTrackerId = -1;
+ dependency->nrOfActiveStoppingTrackers += 1;
}
celixThreadMutex_unlock(&dependency->mutex);
return CELIX_SUCCESS;
}
+bool celix_dmServiceDependency_isDisabled(celix_dm_service_dependency_t *dependency) {
+ bool isStopped;
+ celixThreadMutex_lock(&dependency->mutex);
+ isStopped = dependency->svcTrackerId == -1L && dependency->nrOfActiveStoppingTrackers == 0;
+ celixThreadMutex_unlock(&dependency->mutex);
+ return isStopped;
+}
+
/**
* checks whether the service dependency needs to be ignore. This can be needed if a component depends on the same service types as it provides
*/
static bool serviceDependency_ignoreSvcCallback(celix_dm_service_dependency_t* dependency, const celix_properties_t* props) {
+ return false;
+ /* TODO still needed
bool filterOut = celix_dmServiceDependency_filterOutOwnSvcDependencies(dependency);
if (filterOut) {
const char *uuid = celix_dmComponent_getUUID(dependency->component);
const char *svcCmpUUID = celix_properties_get(props, CELIX_DM_COMPONENT_UUID, NULL);
- return svcCmpUUID != NULL && celix_utils_stringEquals(uuid, svcCmpUUID);
+ bool ignore = svcCmpUUID != NULL && celix_utils_stringEquals(uuid, svcCmpUUID);
+ return ignore;
}
- return false;
+ return false;*/
}
static void serviceDependency_setServiceTrackerCallback(void *handle, void *svc, const celix_properties_t *props) {
@@ -260,7 +345,7 @@ static void serviceDependency_setServiceTrackerCallback(void *handle, void *svc,
celix_private_dmComponent_handleEvent(dependency->component, &event);
}
-celix_status_t celix_serviceDependency_invokeSet(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props) {
+celix_status_t celix_dmServiceDependency_invokeSet(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props) {
if (dependency->set) {
dependency->set(serviceDependency_getCallbackHandle(dependency), svc);
}
@@ -289,7 +374,7 @@ static void serviceDependency_addServiceTrackerCallback(void *handle, void *svc,
celix_private_dmComponent_handleEvent(dependency->component, &event);
}
-celix_status_t celix_serviceDependency_invokeAdd(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props) {
+celix_status_t celix_dmServiceDependency_invokeAdd(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props) {
void *handle = serviceDependency_getCallbackHandle(dependency);
if (dependency->add) {
dependency->add(handle, svc);
@@ -319,7 +404,7 @@ static void serviceDependency_removeServiceTrackerCallback(void *handle, void *s
celix_private_dmComponent_handleEvent(dependency->component, &event);
}
-celix_status_t celix_serviceDependency_invokeRemove(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props) {
+celix_status_t celix_dmServiceDependency_invokeRemove(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props) {
if (dependency->remove) {
dependency->remove(serviceDependency_getCallbackHandle(dependency), svc);
}
@@ -329,19 +414,19 @@ celix_status_t celix_serviceDependency_invokeRemove(celix_dm_service_dependency_
return CELIX_SUCCESS;
}
-bool celix_serviceDependency_hasSetCallback(const celix_dm_service_dependency_t *dependency) {
+bool celix_dmServiceDependency_hasSetCallback(const celix_dm_service_dependency_t *dependency) {
return dependency->set != NULL || dependency->setWithProperties != NULL;
}
-bool celix_serviceDependency_hasAddCallback(const celix_dm_service_dependency_t *dependency) {
+bool celix_dmServiceDependency_hasAddCallback(const celix_dm_service_dependency_t *dependency) {
return dependency->add != NULL || dependency->addWithProperties != NULL;
}
-bool celix_serviceDependency_hasRemoveCallback(const celix_dm_service_dependency_t *dependency) {
+bool celix_dmServiceDependency_hasRemoveCallback(const celix_dm_service_dependency_t *dependency) {
return dependency->remove != NULL || dependency->remWithProperties != NULL;
}
-bool celix_serviceDependency_isAvailable(celix_dm_service_dependency_t *dependency) {
+bool celix_dmServiceDependency_isAvailable(celix_dm_service_dependency_t *dependency) {
bool avail;
celixThreadMutex_lock(&dependency->mutex);
avail = dependency->trackedSvcCount > 0;
@@ -355,9 +440,9 @@ bool celix_dmServiceDependency_isRequired(const celix_dm_service_dependency_t* d
bool celix_dmServiceDependency_isTrackerOpen(celix_dm_service_dependency_t* dependency) {
celixThreadMutex_lock(&dependency->mutex);
- bool started = dependency->isTrackerOpen;
+ bool isOpen = dependency->svcTrackerId >= 0;
celixThreadMutex_unlock(&dependency->mutex);
- return started;
+ return isOpen;
}
bool celix_dmServiceDependency_filterOutOwnSvcDependencies(celix_dm_service_dependency_t* dependency) {
diff --git a/libs/framework/src/dm_service_dependency_impl.h b/libs/framework/src/dm_service_dependency_impl.h
index df48b22..cafa910 100644
--- a/libs/framework/src/dm_service_dependency_impl.h
+++ b/libs/framework/src/dm_service_dependency_impl.h
@@ -57,8 +57,8 @@ struct celix_dm_service_dependency {
celix_dm_component_t *component;
celix_thread_mutex_t mutex; //protects below
- long svcTrackerId;
- bool isTrackerOpen;
+ long svcTrackerId; //active tracker id
+ size_t nrOfActiveStoppingTrackers; //nr of async stop tracker still active (should be 0 or 1)
size_t trackedSvcCount;
void* callbackHandle; //This handle can be set to be used instead of the component implementation
@@ -71,20 +71,22 @@ struct celix_dm_service_dependency {
bool filterOutOwnSvcDependencies;
};
-celix_status_t celix_serviceDependency_start(celix_dm_service_dependency_t *dependency);
-celix_status_t celix_serviceDependency_stop(celix_dm_service_dependency_t *dependency);
+celix_status_t celix_dmServiceDependency_enable(celix_dm_service_dependency_t *dependency);
+celix_status_t celix_dmServiceDependency_disable(celix_dm_service_dependency_t *dependency);
-celix_status_t celix_serviceDependency_setComponent(celix_dm_service_dependency_t *dependency, celix_dm_component_t *component);
+bool celix_dmServiceDependency_isDisabled(celix_dm_service_dependency_t *dependency);
-celix_status_t celix_serviceDependency_invokeSet(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props);
-celix_status_t celix_serviceDependency_invokeAdd(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props);
-celix_status_t celix_serviceDependency_invokeRemove(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props);
+celix_status_t celix_dmServiceDependency_setComponent(celix_dm_service_dependency_t *dependency, celix_dm_component_t *component);
-bool celix_serviceDependency_hasSetCallback(const celix_dm_service_dependency_t *dependency);
-bool celix_serviceDependency_hasAddCallback(const celix_dm_service_dependency_t *dependency);
-bool celix_serviceDependency_hasRemoveCallback(const celix_dm_service_dependency_t *dependency);
+celix_status_t celix_dmServiceDependency_invokeSet(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props);
+celix_status_t celix_dmServiceDependency_invokeAdd(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props);
+celix_status_t celix_dmServiceDependency_invokeRemove(celix_dm_service_dependency_t *dependency, void* svc, const celix_properties_t* props);
-bool celix_serviceDependency_isAvailable(celix_dm_service_dependency_t *dependency);
+bool celix_dmServiceDependency_hasSetCallback(const celix_dm_service_dependency_t *dependency);
+bool celix_dmServiceDependency_hasAddCallback(const celix_dm_service_dependency_t *dependency);
+bool celix_dmServiceDependency_hasRemoveCallback(const celix_dm_service_dependency_t *dependency);
+
+bool celix_dmServiceDependency_isAvailable(celix_dm_service_dependency_t *dependency);
bool celix_dmServiceDependency_isRequired(const celix_dm_service_dependency_t* dependency);
bool celix_dmServiceDependency_isTrackerOpen(celix_dm_service_dependency_t* dependency);
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 957003b..0cb8e21 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -69,14 +69,14 @@ static inline celix_framework_bundle_entry_t* fw_bundleEntry_create(celix_bundle
static inline void fw_bundleEntry_waitTillUseCountIs(celix_framework_bundle_entry_t *entry, size_t desiredUseCount) {
celixThreadMutex_lock(&entry->useMutex);
- time_t start = time(NULL);
+ struct timespec start = celix_gettime(CLOCK_MONOTONIC);
while (entry->useCount != desiredUseCount) {
celixThreadCondition_timedwaitRelative(&entry->useCond, &entry->useMutex, 5, 0);
if (entry->useCount != desiredUseCount) {
- time_t now = time(NULL);
- if ((now-start) > 5) {
+ struct timespec now = celix_gettime(CLOCK_MONOTONIC);
+ if (celix_difftime(&start, &now) > 5) {
fw_log(celix_frameworkLogger_globalLogger(), CELIX_LOG_LEVEL_WARNING, "Bundle '%s' (bnd id = %li) still in use. Use count is %u, desired is %li", celix_bundle_getSymbolicName(entry->bnd), entry->bndId, entry->useCount, desiredUseCount);
- start = time(NULL);
+ start = celix_gettime(CLOCK_MONOTONIC);
}
}
}
@@ -1990,7 +1990,7 @@ static void fw_handleEventRequest(celix_framework_t *framework, celix_framework_
}
}
- if (event->doneCallback != NULL) {
+ if (event->doneCallback != NULL && !event->cancelled) {
event->doneCallback(event->doneData);
}
}
diff --git a/libs/utils/src/array_list.c b/libs/utils/src/array_list.c
index 1013cc3..7de9365 100644
--- a/libs/utils/src/array_list.c
+++ b/libs/utils/src/array_list.c
@@ -372,9 +372,11 @@ celix_array_list_t* celix_arrayList_createWithEquals(celix_arrayList_equals_fp e
}
void celix_arrayList_destroy(celix_array_list_t *list) {
- list->size = 0;
- free(list->elementData);
- free(list);
+ if (list != NULL) {
+ list->size = 0;
+ free(list->elementData);
+ free(list);
+ }
}
int celix_arrayList_size(const celix_array_list_t *list) {