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/17 15:18:28 UTC

[celix] branch feature/refactor_c_dep_man_service_trackers updated: Adds mutex usage to C++ dep man and adds getInfo(s) to C++ dep man.

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 f788226  Adds mutex usage to C++ dep man and adds getInfo(s) to C++ dep man.
f788226 is described below

commit f7882262e0f77ca5bbe9eba5f363941f260f2310
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Jan 17 16:18:11 2021 +0100

    Adds mutex usage to C++ dep man and adds getInfo(s) to C++ dep man.
---
 bundles/shell/shell/src/dm_shell_list_command.c    |  18 +--
 libs/dependency_manager_cxx/src/dm_activator.cc    |   6 +-
 .../gtest/src/DependencyManagerTestSuite.cc        |  76 ++++++++---
 libs/framework/include/celix/dm/Component.h        |   6 +-
 libs/framework/include/celix/dm/Component_Impl.h   |  12 +-
 .../framework/include/celix/dm/DependencyManager.h |  43 +++++--
 .../include/celix/dm/DependencyManagerInfo.h       | 142 +++++++++++++++++++++
 .../include/celix/dm/DependencyManager_Impl.h      | 105 ++++++++++++---
 .../framework/include/celix/dm/ServiceDependency.h |   2 +-
 libs/framework/include/celix_bundle_context.h      |   6 +
 libs/framework/include/celix_dependency_manager.h  |  47 ++++++-
 libs/framework/include/celix_dm_info.h             |  11 +-
 libs/framework/src/bundle_context.c                |   5 +
 libs/framework/src/dm_component_impl.c             |   9 +-
 libs/framework/src/dm_dependency_manager_impl.c    |  33 +++--
 15 files changed, 446 insertions(+), 75 deletions(-)

diff --git a/bundles/shell/shell/src/dm_shell_list_command.c b/bundles/shell/shell/src/dm_shell_list_command.c
index 34b0fcc..df1fdca 100644
--- a/bundles/shell/shell/src/dm_shell_list_command.c
+++ b/bundles/shell/shell/src/dm_shell_list_command.c
@@ -54,7 +54,7 @@ static void parseCommandLine(const char*line, celix_array_list_t **requestedBund
     free (str);
 }
 
-static void printFullInfo(FILE *out, bool colors, long bundleId, dm_component_info_pt compInfo) {
+static void printFullInfo(FILE *out, bool colors, long bundleId, const char* bndName, dm_component_info_pt compInfo) {
     const char *startColors = "";
     const char *endColors = "";
     if (colors) {
@@ -65,7 +65,9 @@ static void printFullInfo(FILE *out, bool colors, long bundleId, dm_component_in
     fprintf(out, "|- UUID   = %s\n", compInfo->id);
     fprintf(out, "|- Active = %s\n", compInfo->active ? "true" : "false");
     fprintf(out, "|- State  = %s\n", compInfo->state);
-    fprintf(out, "|- Bundle = %li\n", bundleId);
+    fprintf(out, "|- Bundle = %li (%s)\n", bundleId, bndName);
+    fprintf(out, "|- Nr of times started = %i\n", (int)compInfo->nrOfTimesStarted);
+    fprintf(out, "|- Nr of times resumed = %i\n", (int)compInfo->nrOfTimesResumed);
 
     fprintf(out, "|- Interfaces (%d):\n", celix_arrayList_size(compInfo->interfaces));
     for (int interfCnt = 0; interfCnt < celix_arrayList_size(compInfo->interfaces); interfCnt++) {
@@ -101,15 +103,15 @@ static void printFullInfo(FILE *out, bool colors, long bundleId, dm_component_in
 
 }
 
-static void printBasicInfo(FILE *out, bool colors, long bundleId, dm_component_info_pt compInfo) {
+static void printBasicInfo(FILE *out, bool colors, long bundleId, const char* bndName, dm_component_info_pt compInfo) {
     const char *startColors = "";
     const char *endColors = "";
     if (colors) {
         startColors = compInfo->active ? OK_COLOR : NOK_COLOR;
         endColors = END_COLOR;
     }
-    fprintf(out, "Component: Name=%s, ID=%s, %sActive=%s%s, State=%s, Bundle=%li\n", compInfo->name, compInfo->id,
-            startColors, compInfo->active ? "true " : "false", endColors, compInfo->state, bundleId);
+    fprintf(out, "Component: Name=%s, ID=%s, %sActive=%s%s, State=%s, Bundle=%li (%s)\n", compInfo->name, compInfo->id,
+            startColors, compInfo->active ? "true " : "false", endColors, compInfo->state, bundleId, bndName);
 
 }
 
@@ -120,9 +122,9 @@ static void dm_printInfo(FILE *out, bool useColors, bool fullInfo, celix_depende
             for (unsigned int cmpCnt = 0; cmpCnt < size; cmpCnt++) {
                 dm_component_info_pt compInfo = celix_arrayList_get(info->components, cmpCnt);
                 if (fullInfo) {
-                    printFullInfo(out, useColors, info->bndId, compInfo);
+                    printFullInfo(out, useColors, info->bndId, info->bndSymbolicName, compInfo);
                 } else {
-                    printBasicInfo(out, useColors, info->bndId, compInfo);
+                    printBasicInfo(out, useColors, info->bndId, info->bndSymbolicName, compInfo);
                 }
             }
             fprintf(out, "\n");
@@ -155,7 +157,7 @@ celix_status_t dmListCommand_execute(void* handle, char * line, FILE *out, FILE
                 nrOfComponents += 1;
                 if (!cmpInfo->active) {
                     allActive = false;
-                    printFullInfo(out, useColors, info->bndId, cmpInfo);
+                    printFullInfo(out, useColors, info->bndId, info->bndSymbolicName, cmpInfo);
                 }
             }
         }
diff --git a/libs/dependency_manager_cxx/src/dm_activator.cc b/libs/dependency_manager_cxx/src/dm_activator.cc
index 2d5e0b6..0bba0a5 100644
--- a/libs/dependency_manager_cxx/src/dm_activator.cc
+++ b/libs/dependency_manager_cxx/src/dm_activator.cc
@@ -29,7 +29,7 @@
  * Deprecated. Use the CELIX_GEN_CXX_BUNDLE_ACTIVATOR marco from celix_bundle_activator.h instead
  */
 struct BundleActivatorData {
-    DependencyManager mng;
+    std::shared_ptr<DependencyManager> mng;
     std::unique_ptr<celix::dm::DmActivator> act;
 };
 
@@ -39,7 +39,7 @@ extern "C" celix_status_t bundleActivator_create(celix_bundle_context_t *context
     BundleActivatorData* data = nullptr;
 #ifdef __EXCEPTIONS
     data = new BundleActivatorData{
-        .mng = celix::dm::DependencyManager{context},
+        .mng = std::make_shared<celix::dm::DependencyManager>(context),
         .act = nullptr
     };
 #else
@@ -49,7 +49,7 @@ extern "C" celix_status_t bundleActivator_create(celix_bundle_context_t *context
     };
 #endif
     if (data != nullptr) {
-        data->act = std::unique_ptr<celix::dm::DmActivator>{celix::dm::DmActivator::create(data->mng)};
+        data->act = std::unique_ptr<celix::dm::DmActivator>{celix::dm::DmActivator::create(*data->mng)};
     }
 
     if (data == nullptr || data->act == nullptr) {
diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index 03163d1..78bce4f 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -84,7 +84,7 @@ TEST_F(DependencyManagerTestSuite, DmComponentAddRemove) {
     ASSERT_EQ(0, celix_dependencyManager_nrOfComponents(mng));
 }
 
-TEST_F(DependencyManagerTestSuite, DmGetInfo) {
+TEST_F(DependencyManagerTestSuite, CDmGetInfo) {
     auto* mng = celix_bundleContext_getDependencyManager(ctx);
     auto* cmp = celix_dmComponent_create(ctx, "test1");
 
@@ -108,7 +108,6 @@ TEST_F(DependencyManagerTestSuite, DmGetInfo) {
     celix_dependencyManager_destroyInfos(mng, infos);
 }
 
-
 TEST_F(DependencyManagerTestSuite, TestCheckActive) {
     auto *mng = celix_bundleContext_getDependencyManager(ctx);
     auto *cmp = celix_dmComponent_create(ctx, "test1");
@@ -127,6 +126,64 @@ class TestComponent {
 
 };
 
+struct TestService {
+    void *handle = nullptr;
+};
+
+class Cmp1 : public TestService {
+
+};
+
+class Cmp2 : public TestService {
+public:
+    explicit Cmp2(const std::string& name) {
+        std::cout << "usage arg: " << name << std::endl;
+    }
+};
+
+
+TEST_F(DependencyManagerTestSuite, CxxDmGetInfo) {
+    celix::dm::DependencyManager mng{ctx};
+
+    auto& cmp = mng.createComponent<Cmp1>();
+    cmp.createProvidedService<TestService>().addProperty("key", "value");
+    cmp.createServiceDependency<TestService>().setVersionRange("[1,2)").setRequired(true);
+
+    auto infos = mng.getInfos();
+    EXPECT_EQ(infos.size(), 1);
+
+    auto info = mng.getInfo();
+    EXPECT_EQ(info.bndId, 0);
+    EXPECT_EQ(info.bndSymbolicName, "Framework");
+    EXPECT_EQ(info.components.size(), 0); //not build yet
+
+    mng.build();
+    info = mng.getInfo(); //new info
+    ASSERT_EQ(info.components.size(), 1); //build
+
+    auto& cmpInfo = info.components[0];
+    EXPECT_TRUE(!cmpInfo.uuid.empty());
+    EXPECT_EQ(cmpInfo.name, "Cmp1");
+    EXPECT_EQ(cmpInfo.state, "WAITING_FOR_REQUIRED");
+    EXPECT_FALSE(cmpInfo.isActive);
+    EXPECT_EQ(cmpInfo.nrOfTimesStarted, 0);
+    EXPECT_EQ(cmpInfo.nrOfTimesResumed, 0);
+
+    ASSERT_EQ(cmpInfo.interfacesInfo.size(), 1);
+    auto& intf = cmpInfo.interfacesInfo[0];
+    EXPECT_EQ(intf.serviceName, "TestService");
+    EXPECT_TRUE(intf.properties.size() > 0);
+    EXPECT_NE(intf.properties.find("key"), intf.properties.end());
+
+    ASSERT_EQ(cmpInfo.dependenciesInfo.size(), 1);
+    auto& dep = cmpInfo.dependenciesInfo[0];
+    EXPECT_EQ(dep.serviceName, "TestService");
+    EXPECT_EQ(dep.isRequired, true);
+    EXPECT_EQ(dep.versionRange, "[1,2)");
+    EXPECT_EQ(dep.isAvailable, false);
+    EXPECT_EQ(dep.nrOfTrackedServices, 0);
+}
+
 TEST_F(DependencyManagerTestSuite, OnlyActiveAfterBuildCheck) {
     celix::dm::DependencyManager dm{ctx};
     EXPECT_EQ(0, dm.getNrOfComponents());
@@ -159,21 +216,6 @@ TEST_F(DependencyManagerTestSuite, StartDmWillBuildCmp) {
     EXPECT_EQ(0, dm.getNrOfComponents()); //dm cleared so no components
 }
 
-struct TestService {
-    void *handle = nullptr;
-};
-
-class Cmp1 : public TestService {
-
-};
-
-class Cmp2 : public TestService {
-public:
-    explicit Cmp2(const std::string& name) {
-        std::cout << "usage arg: " << name << std::endl;
-    }
-};
-
 TEST_F(DependencyManagerTestSuite, CreateComponentVariant) {
     celix::dm::DependencyManager dm{ctx};
 
diff --git a/libs/framework/include/celix/dm/Component.h b/libs/framework/include/celix/dm/Component.h
index 05e3989..87954a7 100644
--- a/libs/framework/include/celix/dm/Component.h
+++ b/libs/framework/include/celix/dm/Component.h
@@ -301,9 +301,9 @@ namespace celix { namespace dm {
          Component<T>& build();
 
         /**
-         * Same as build, but this call will not wait until all service registrations and tracker are created on the
-         * Celix event thread.
-         * Can also be called on the Celix event thread.
+         * Same as build, but this call will not wait til all service registrations and tracker are registered/openend
+         * on the Celix event thread.
+         * Can be called on the Celix event thread.
          */
         Component<T>& buildAsync();
     };
diff --git a/libs/framework/include/celix/dm/Component_Impl.h b/libs/framework/include/celix/dm/Component_Impl.h
index 704438c..c19bf84 100644
--- a/libs/framework/include/celix/dm/Component_Impl.h
+++ b/libs/framework/include/celix/dm/Component_Impl.h
@@ -47,7 +47,7 @@ inline void BaseComponent::runBuild() {
 
     bool alreadyAdded = cmpAddedToDepMan.exchange(true);
     if (!alreadyAdded) {
-        celix_dependencyManager_add(cDepMan, cCmp);
+        celix_dependencyManager_addAsync(cDepMan, cCmp);
     }
 }
 
@@ -58,7 +58,15 @@ inline void BaseComponent::wait() const {
 }
 
 template<class T>
-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)) {}
+Component<T>::Component(
+        celix_bundle_context_t *context,
+        celix_dependency_manager_t* cDepMan,
+        std::string name,
+        std::string uuid) : BaseComponent(
+                context,
+                cDepMan,
+                name.empty() ? celix::dm::typeName<T>() : std::move(name),
+                std::move(uuid)) {}
 
 template<class T>
 Component<T>::~Component() = default;
diff --git a/libs/framework/include/celix/dm/DependencyManager.h b/libs/framework/include/celix/dm/DependencyManager.h
index 0ca43de..e294702 100644
--- a/libs/framework/include/celix/dm/DependencyManager.h
+++ b/libs/framework/include/celix/dm/DependencyManager.h
@@ -22,6 +22,7 @@
 #include "celix/dm/types.h"
 #include "celix/dm/Component.h"
 #include "celix/dm/ServiceDependency.h"
+#include "celix/dm/DependencyManagerInfo.h"
 
 #include "bundle_context.h"
 #include "celix_bundle_context.h"
@@ -32,7 +33,15 @@
 namespace celix { namespace dm {
 
     /**
-     * The Dependency Manager, Component, ServiceDependency and Properties are not thread safe!
+     *
+     * The build() methods For celix::dm::DependencyManager, celix::dm::Component and
+     * celix::dm::(C)ServiceDependency should be called outside the Celix event thread.
+     * Note that bundle activators are started and stopped outside the Celix event thread and thus the build()
+     * methods can be used in bundle activators.
+     *
+     * Inside the Celix event thread - i.e. during a useService callback or add/rem/set call from a service tracker -
+     * the buildAsync version should be used. After a buildASync method has returned, service registration and opening
+     * service trackers are (possibly) still in progress.
      */
     class DependencyManager {
     public:
@@ -40,8 +49,8 @@ namespace celix { namespace dm {
 
         virtual ~DependencyManager();
 
-        DependencyManager(DependencyManager&& mgr) = default;
-        DependencyManager& operator=(DependencyManager&& rhs) = default;
+        DependencyManager(DependencyManager&& mgr) = delete;
+        DependencyManager& operator=(DependencyManager&& rhs) = delete;
 
         DependencyManager(const DependencyManager&) = delete;
         DependencyManager& operator=(const DependencyManager&) = delete;
@@ -97,17 +106,17 @@ namespace celix { namespace dm {
          * If a component is updated after the dependency manager build is called, an new build call will result in
          * that the changes to the component are enabled.
          *
-         * Note that the after this call the components will be created and if the components can be started, they
+         * After this call the components will be created and if the components can be started, they
          * will be started and the services will be registered.
          *
-         * Should not be called from the Celix event  thread.
+         * Should not be called from the Celix event thread.
          */
         void build();
 
         /**
-         * Same as build, but this call will not wait until all service registrations and tracker are created on the
-         * Celix event thread.
-         * Can also be called on the Celix event thread.
+         * Same as build, but this call will not wait until all service registrations and tracker are registered/opened
+         * on the Celix event thread.
+         * Can be called on the Celix event thread.
          */
          void buildAsync();
 
@@ -149,21 +158,33 @@ namespace celix { namespace dm {
         std::size_t getNrOfComponents() const;
 
         /**
-         * Tries to find the component with UUID and staticly cast it to
+         * Tries to find the component with UUID and statically 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;
+
+        /**
+         * Get Dependency Management info for this component manager.
+         * @return A DependencyManagerInfo struct.
+         */
+        celix::dm::DependencyManagerInfo getInfo() const;
+
+        /**
+         * Get Dependency Management info for all component manager (for all bundles).
+         * @return A vector of DependencyManagerInfo structs.
+         */
+        std::vector<celix::dm::DependencyManagerInfo> getInfos() const;
     private:
         template<class T>
         Component<T>& createComponentInternal(std::string name, std::string uuid);
 
         std::shared_ptr<celix_bundle_context_t> context;
         std::shared_ptr<celix_dependency_manager_t> cDepMan;
-        std::vector<std::shared_ptr<BaseComponent>> components {};
+        mutable std::mutex mutex{}; //protects below
+        std::vector<std::shared_ptr<BaseComponent>> components{};
     };
 
 }}
diff --git a/libs/framework/include/celix/dm/DependencyManagerInfo.h b/libs/framework/include/celix/dm/DependencyManagerInfo.h
new file mode 100644
index 0000000..56524c3
--- /dev/null
+++ b/libs/framework/include/celix/dm/DependencyManagerInfo.h
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+
+namespace celix { namespace dm {
+
+    /**
+     * Trivial struct containing interface info.
+     */
+    struct InterfaceInfo {
+        /**
+         * The service name of the interface.
+         */
+        std::string serviceName{};
+
+        /**
+         * All the meta information for the component interface.
+         */
+        std::unordered_map<std::string, std::string> properties{};
+    };
+
+    /**
+     * Trivial struct containing service dependency info.
+     */
+    struct ServiceDependencyInfo {
+        /**
+         * The service name targeted by this service dependency.
+         */
+        std::string serviceName{};
+
+        /**
+         * The additional filter used to track services.
+         */
+        std::string filter{};
+
+        /**
+         * The optional version range used to track services.
+         */
+        std::string versionRange{};
+
+        /**
+         * Whether the service is available (at least 1 dependency found).
+         */
+        bool isAvailable{};
+
+        /**
+         * Whether the service is required (need at least 1 available service to be resolved).
+         */
+        bool isRequired{};
+
+        /**
+         * Nummer tracker services.
+         */
+        std::size_t nrOfTrackedServices{0};
+    };
+
+    /**
+     * Trivial struct component info.
+     */
+    struct ComponentInfo {
+        /**
+         * The UUID of the component.
+         */
+        std::string uuid{};
+
+        /**
+         * The name of the component.
+         */
+        std::string name{};
+
+        /**
+         * Whether the component is active.
+         */
+        bool isActive{};
+
+        /**
+         * The state of the component.
+         */
+        std::string state{};
+
+        /**
+         * Number of time started.
+         */
+         std::size_t nrOfTimesStarted{0};
+
+        /**
+        * Number of time resumed cycles.
+        */
+        std::size_t nrOfTimesResumed{0};
+
+        /**
+         * The interface provided by the component (when active).
+         */
+        std::vector<InterfaceInfo> interfacesInfo{};
+
+        /**
+         * The service dependencies of the component.
+         */
+        std::vector<ServiceDependencyInfo> dependenciesInfo{};
+    };
+
+    /**
+     * Trivial struct containing Dependency Manager info.
+     */
+    struct DependencyManagerInfo {
+        /**
+         * The owning bundle id of the dependency manager where information is extracted from.
+         */
+        long bndId{};
+
+        /**
+         * The owning bundle symbolic name of the dependency manager where information is extracted from.
+         */
+        std::string bndSymbolicName{};
+
+        /**
+         * vector of component info for all the (build) components for this dependency manager
+         */
+        std::vector<ComponentInfo> components{};
+    };
+}}
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h b/libs/framework/include/celix/dm/DependencyManager_Impl.h
index 68dc7cb..d976b08 100644
--- a/libs/framework/include/celix/dm/DependencyManager_Impl.h
+++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h
@@ -35,6 +35,7 @@ Component<T>& DependencyManager::createComponentInternal(std::string name, std::
     auto cmp = Component<T>::create(this->context.get(), this->cDepMan.get(), std::move(name), std::move(uuid));
     if (cmp->isValid()) {
         auto baseCmp = std::static_pointer_cast<BaseComponent>(cmp);
+        std::lock_guard<std::mutex> lck{mutex};
         this->components.push_back(baseCmp);
     }
 
@@ -45,22 +46,22 @@ template<class T>
 inline
 typename std::enable_if<std::is_default_constructible<T>::value, Component<T>&>::type
 DependencyManager::createComponent(std::string name, std::string uuid) {
-    return createComponentInternal<T>(name, uuid);
+    return createComponentInternal<T>(std::move(name), std::move(uuid));
 }
 
 template<class T>
 Component<T>& DependencyManager::createComponent(std::unique_ptr<T>&& rhs, std::string name, std::string uuid) {
-    return createComponentInternal<T>(name, uuid).setInstance(std::move(rhs));
+    return createComponentInternal<T>(std::move(name), std::move(uuid)).setInstance(std::move(rhs));
 }
 
 template<class T>
 Component<T>& DependencyManager::createComponent(std::shared_ptr<T> rhs, std::string name, std::string uuid) {
-    return createComponentInternal<T>(name, uuid).setInstance(rhs);
+    return createComponentInternal<T>(std::move(name), std::move(uuid)).setInstance(rhs);
 }
 
 template<class T>
 Component<T>& DependencyManager::createComponent(T rhs, std::string name, std::string uuid) {
-    return createComponentInternal<T>(name, uuid).setInstance(std::forward<T>(rhs));
+    return createComponentInternal<T>(std::move(name), std::move(uuid)).setInstance(std::forward<T>(rhs));
 }
 
 inline void DependencyManager::start() {
@@ -68,29 +69,40 @@ inline void DependencyManager::start() {
 }
 
 inline void DependencyManager::build() {
-    for (auto& cmp : components) {
-        cmp->runBuild();
-    }
+    buildAsync();
     wait();
 }
 
 inline void DependencyManager::buildAsync() {
-    build();
+    std::lock_guard<std::mutex> lck{mutex};
+    for (auto& cmp : components) {
+        cmp->runBuild();
+    }
 }
 
 template<typename T>
 void DependencyManager::destroyComponent(Component<T> &component) {
-    for (auto it = components.begin(); it != components.end(); ++it) {
-        if ( (*it).get() == &component) {
-            //found
-            components.erase(it);
-            break;
+    std::shared_ptr<BaseComponent> tmpStore{};
+    {
+        std::lock_guard<std::mutex> lck{mutex};
+        for (auto it = components.begin(); it != components.end(); ++it) {
+            if ( (*it).get() == &component) {
+                //found
+                tmpStore = *it; //prevents destruction in lock
+                components.erase(it);
+                break;
+            }
         }
     }
 }
 
 inline void DependencyManager::clear() {
-    components.clear();
+    std::vector<std::shared_ptr<BaseComponent>> swappedComponents{};
+    {
+        std::lock_guard<std::mutex> lck{mutex};
+        std::swap(swappedComponents, components);
+    }
+    swappedComponents.clear();
 }
 
 inline void DependencyManager::wait() const {
@@ -106,7 +118,8 @@ inline std::size_t DependencyManager::getNrOfComponents() const {
 }
 
 template<typename T>
-inline std::shared_ptr<Component<T>> DependencyManager::findComponent(const std::string& uuid) const  {
+inline std::shared_ptr<Component<T>> DependencyManager::findComponent(const std::string& uuid) const {
+    std::lock_guard<std::mutex> lck{mutex};
     std::shared_ptr<BaseComponent> found{nullptr};
     for (const auto& cmp : components) {
         if (cmp->getUUID() == uuid) {
@@ -120,3 +133,65 @@ inline std::shared_ptr<Component<T>> DependencyManager::findComponent(const std:
     }
 }
 
+static celix::dm::DependencyManagerInfo createDepManInfoFromC(celix_dependency_manager_info_t* cInfo) {
+    celix::dm::DependencyManagerInfo info{};
+    info.bndId = cInfo->bndId;
+    info.bndSymbolicName = std::string{cInfo->bndSymbolicName};
+
+    for (int i = 0; i < celix_arrayList_size(cInfo->components); ++i) {
+        auto* cCmpInfo = static_cast<dm_component_info_t*>(celix_arrayList_get(cInfo->components, i));
+        celix::dm::ComponentInfo cmpInfo{};
+        cmpInfo.uuid = std::string{cCmpInfo->id};
+        cmpInfo.name = std::string{cCmpInfo->name};
+        cmpInfo.isActive = cCmpInfo->active;
+        cmpInfo.state = std::string{cCmpInfo->state};
+        cmpInfo.nrOfTimesStarted = cCmpInfo->nrOfTimesStarted;
+        cmpInfo.nrOfTimesResumed = cCmpInfo->nrOfTimesResumed;
+
+        for (int k = 0; k < celix_arrayList_size(cCmpInfo->interfaces); ++k) {
+            auto* cIntInfo = static_cast<dm_interface_info_t*>(celix_arrayList_get(cCmpInfo->interfaces, k));
+            celix::dm::InterfaceInfo intInfo{};
+            intInfo.serviceName = std::string{cIntInfo->name};
+            const char* key;
+            CELIX_PROPERTIES_FOR_EACH(cIntInfo->properties, key) {
+                const char* val =celix_properties_get(cIntInfo->properties, key, nullptr);
+                intInfo.properties[std::string{key}] = std::string{val};
+            }
+            cmpInfo.interfacesInfo.emplace_back(std::move(intInfo));
+        }
+
+        for (int k = 0; k < celix_arrayList_size(cCmpInfo->dependency_list); ++k) {
+            auto *cDepInfo = static_cast<dm_service_dependency_info_t *>(celix_arrayList_get(cCmpInfo->dependency_list, k));
+            celix::dm::ServiceDependencyInfo depInfo{};
+            depInfo.serviceName = std::string{cDepInfo->serviceName == nullptr ? "" : cDepInfo->serviceName};
+            depInfo.filter = std::string{cDepInfo->filter == nullptr ? "" : cDepInfo->filter};
+            depInfo.versionRange = std::string{cDepInfo->versionRange == nullptr ? "" : cDepInfo->versionRange};
+            depInfo.isAvailable = cDepInfo->available;
+            depInfo.isRequired = cDepInfo->required;
+            depInfo.nrOfTrackedServices = cDepInfo->count;
+            cmpInfo.dependenciesInfo.emplace_back(std::move(depInfo));
+        }
+
+        info.components.emplace_back(std::move(cmpInfo));
+    }
+    return info;
+}
+
+inline celix::dm::DependencyManagerInfo DependencyManager::getInfo() const {
+    auto* cInfo = celix_dependencyManager_createInfo(cDependencyManager(), celix_bundleContext_getBundleId(context.get()));
+    auto result = createDepManInfoFromC(cInfo);
+    celix_dependencyManager_destroyInfo(cDependencyManager(), cInfo);
+    return result;
+}
+
+
+inline std::vector<celix::dm::DependencyManagerInfo> DependencyManager::getInfos() const {
+    std::vector<celix::dm::DependencyManagerInfo> result{};
+    auto* cInfos = celix_dependencyManager_createInfos(cDependencyManager());
+    for (int i = 0; i < celix_arrayList_size(cInfos); ++i) {
+        auto* cInfo = static_cast<celix_dependency_manager_info_t*>(celix_arrayList_get(cInfos, i));
+        result.emplace_back(createDepManInfoFromC(cInfo));
+    }
+    celix_dependencyManager_destroyInfos(cDependencyManager(), cInfos);
+    return result;
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/ServiceDependency.h b/libs/framework/include/celix/dm/ServiceDependency.h
index 11874ff..ad95c00 100644
--- a/libs/framework/include/celix/dm/ServiceDependency.h
+++ b/libs/framework/include/celix/dm/ServiceDependency.h
@@ -361,7 +361,7 @@ namespace celix { namespace dm {
         ServiceDependency<T,I>& build();
 
         /**
-         * Same a build, but will not wait till the underlining service tracker is created.
+         * Same a build, but will not wait till the underlining service trackers are opened.
          * Can be called on the Celix event thread.
          */
         ServiceDependency<T,I>& buildAsync();
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index 1d62fa3..4e23e2e 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -1158,6 +1158,12 @@ void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx);
  */
 celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx);
 
+
+/**
+ * Returns the bundle if for the bundle of this bundle context.
+ */
+long celix_bundleContext_getBundleId(const celix_bundle_context_t *ctx);
+
 celix_framework_t* celix_bundleContext_getFramework(const celix_bundle_context_t* ctx);
 
 /**
diff --git a/libs/framework/include/celix_dependency_manager.h b/libs/framework/include/celix_dependency_manager.h
index 8a9897e..6710f12 100644
--- a/libs/framework/include/celix_dependency_manager.h
+++ b/libs/framework/include/celix_dependency_manager.h
@@ -30,18 +30,53 @@
 extern "C" {
 #endif
 
+/**
+ * The `celix_dependencyManager_add`, `celix_dependencyManager_remove` and `celix_dependencyManager_removeAllComponents`
+ * funcions for celix_dependency_manager_t should be called outside the Celix event thread.
+ * Note that bundle activators are started and stopped outside the Celix event thread and thus these
+ * functions can be used in bundle activators.
+ *
+ * Inside the Celix event thread - i.e. during a useService callback or add/rem/set call from a service tracker -
+ * the async versions should be used. After a async function has returned, service registration and opening
+ * service trackers are (possibly) still in progress.
+ */
+
 
 /**
  * Adds a DM component to the dependency manager
+ *
+ * After this call the components will be created and if the components can be started, they
+ * will be started and the services will be registered.
+ *
+ * Should not be called from the Celix event thread.
  */
 celix_status_t celix_dependencyManager_add(celix_dependency_manager_t *manager, celix_dm_component_t *component);
 
 /**
+ * Same as celix_dependencyManager_add, but this call will not wait until all service registrations and
+ * tracker are registered/opened on the Celix event thread.
+ * Can be called on the Celix event thread.
+ */
+celix_status_t celix_dependencyManager_addAsync(celix_dependency_manager_t *manager, celix_dm_component_t *component);
+
+/**
  * Removes a DM component from the dependency manager and destroys it
+ *
+ * After this call the components will be destroyed and if the components was started, the service registrations
+ * and service tracked of this component will be unregistered and closed.
+ *
+ * Should not be called from the Celix event thread.
  */
 celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component);
 
 /**
+ * Same as celix_dependencyManager_remove, but this call will not wait until all service registrations and
+ * tracker are unregistered/closed on the Celix event thread.
+ * Can be called on the Celix event thread.
+ */
+celix_status_t celix_dependencyManager_removeAsync(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);
@@ -49,11 +84,19 @@ celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_man
 /**
  * Removes all DM components from the dependency manager.
  *
- * This function cannot be called on the Celix event thread.
+ * Should not be called from the Celix event thread.
  */
 celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_manager_t *manager);
 
 /**
+ * Same as celix_dependencyManager_removeAllComponents, but this call will not wait til all
+ * service registration and service trackers are unregistered/closed.
+ *
+ * Can be called on the Celix event thread.
+ */
+celix_status_t celix_dependencyManager_removeAllComponentsAsync(celix_dependency_manager_t *manager);
+
+/**
  * Create and returns a dependency manager info struct for the specified bundle.
  * The dependency manager info contains information about the state of the dependency manager components
  *
@@ -75,7 +118,7 @@ celix_dependency_manager_info_t* celix_dependencyManager_createInfo(celix_depend
  * @returns A Celix array of dependency manager infos (celix_dependency_manager_info_t*)
  * for the provided bundle id or NULL if the bundle id is invalid.
  */
-celix_array_list_t * /*celix_dependency_manager_info_t entries*/ celix_dependencyManager_createInfos(celix_dependency_manager_t *manager);
+celix_array_list_t * /*celix_dependency_manager_info_t* entries*/ celix_dependencyManager_createInfos(celix_dependency_manager_t *manager);
 
 /**
  * Destroys a DM info struct.
diff --git a/libs/framework/include/celix_dm_info.h b/libs/framework/include/celix_dm_info.h
index b7cfda9..fa66d95 100644
--- a/libs/framework/include/celix_dm_info.h
+++ b/libs/framework/include/celix_dm_info.h
@@ -55,9 +55,11 @@ struct celix_dm_component_info_struct {
     char id[64];
     char name[128];
     bool active;
-    char * state;
-    celix_array_list_t *interfaces;   // type dm_interface_info_pt
-    celix_array_list_t *dependency_list;  // type dm_service_dependency_info_pt
+    char* state;
+    size_t nrOfTimesStarted;
+    size_t nrOfTimesResumed;
+    celix_array_list_t *interfaces;   // type dm_interface_info_t*
+    celix_array_list_t *dependency_list;  // type dm_service_dependency_info_t*
 };
 typedef struct celix_dm_component_info_struct *dm_component_info_pt; //deprecated
 typedef struct celix_dm_component_info_struct dm_component_info_t; //deprecated
@@ -65,7 +67,8 @@ typedef struct celix_dm_component_info_struct celix_dm_component_info_t;
 
 struct celix_dm_dependency_manager_info_struct {
     long bndId;
-    celix_array_list_t *components;      // type dm_component_info
+    char* bndSymbolicName;
+    celix_array_list_t *components;      // type dm_component_info_t*
 };
 typedef struct celix_dm_dependency_manager_info_struct *dm_dependency_manager_info_pt; //deprecated
 typedef struct celix_dm_dependency_manager_info_struct dm_dependency_manager_info_t; //deprecated
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 1cffcce..674ab68 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -1616,6 +1616,11 @@ celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx)
     return bnd;
 }
 
+long celix_bundleContext_getBundleId(const celix_bundle_context_t *ctx) {
+    celix_bundle_t *bnd = celix_bundleContext_getBundle(ctx);
+    return bnd == NULL ? -1L : celix_bundle_getId(bnd);
+}
+
 celix_framework_t* celix_bundleContext_getFramework(const celix_bundle_context_t *ctx) {
     celix_framework_t *fw = NULL;
     if (ctx != NULL) {
diff --git a/libs/framework/src/dm_component_impl.c b/libs/framework/src/dm_component_impl.c
index da767dc..332ce58 100644
--- a/libs/framework/src/dm_component_impl.c
+++ b/libs/framework/src/dm_component_impl.c
@@ -63,6 +63,9 @@ struct celix_dm_component_struct {
      */
     size_t nrOfSvcDepependenciesInProgress;
 
+    size_t nrOfTimesStarted;
+    size_t nrOfTimesResumed;
+
 
     bool isEnabled;
 };
@@ -519,13 +522,14 @@ static celix_status_t celix_dmComponent_suspend(celix_dm_component_t *component,
 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) {
+	if (strategy == DM_SERVICE_DEPENDENCY_STRATEGY_SUSPEND &&  component->callbackStart != NULL) {
         celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_TRACE,
                "Resuming component %s (uuid=%s)",
                component->name,
                component->uuid);
         celix_dmComponent_registerServices(component);
 		status = component->callbackStart(component->implementation);
+		component->nrOfTimesResumed += 1;
 	}
 	return status;
 }
@@ -750,6 +754,7 @@ static celix_status_t celix_dmComponent_performTransition(celix_dm_component_t *
         	status = component->callbackStart(component->implementation);
         }
         celix_dmComponent_registerServices(component);
+        component->nrOfTimesStarted += 1;
         *transition = true;
     } else if (oldState == DM_CMP_STATE_TRACKING_OPTIONAL && newState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) {
         celix_dmComponent_unregisterServices(component);
@@ -901,6 +906,8 @@ celix_status_t celix_dmComponent_getComponentInfo(celix_dm_component_t *componen
     info->active = false;
     memcpy(info->id, component->uuid, DM_COMPONENT_MAX_ID_LENGTH);
     memcpy(info->name, component->name, DM_COMPONENT_MAX_NAME_LENGTH);
+    info->nrOfTimesStarted = component->nrOfTimesStarted;
+    info->nrOfTimesResumed = component->nrOfTimesResumed;
 
     switch (component->state) {
         case DM_CMP_STATE_INACTIVE :
diff --git a/libs/framework/src/dm_dependency_manager_impl.c b/libs/framework/src/dm_dependency_manager_impl.c
index f3811e7..dced291 100644
--- a/libs/framework/src/dm_dependency_manager_impl.c
+++ b/libs/framework/src/dm_dependency_manager_impl.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <dm_dependency_manager.h>
 #include <memory.h>
+#include <celix_utils.h>
 
 #include "bundle_context.h"
 #include "dm_component_impl.h"
@@ -52,20 +53,22 @@ void celix_private_dependencyManager_destroy(celix_dependency_manager_t *manager
 	}
 }
 
-
 celix_status_t celix_dependencyManager_add(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
-	celix_status_t status;
+	celix_status_t status = celix_dependencyManager_addAsync(manager, component);
+	celix_dependencyManager_wait(manager);
+	return status;
+}
 
+celix_status_t celix_dependencyManager_addAsync(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
     celixThreadMutex_lock(&manager->mutex);
 	celix_arrayList_add(manager->components, component);
     celixThreadMutex_unlock(&manager->mutex);
 
-	status = celix_private_dmComponent_enable(component);
-	return status;
+	return celix_private_dmComponent_enable(component);
 }
 
 celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
-    celix_status_t status;
+    celix_status_t status = CELIX_SUCCESS;
 
     celixThreadMutex_lock(&manager->mutex);
     bool found = false;
@@ -90,13 +93,24 @@ celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_man
 }
 
 celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
+	celix_status_t  status = celix_dependencyManager_removeAsync(manager, component);
+	celix_dependencyManager_wait(manager);
+	return status;
+}
+
+celix_status_t celix_dependencyManager_removeAsync(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;
 }
 
-
 celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_manager_t *manager) {
+	celix_status_t status = celix_dependencyManager_removeAllComponentsAsync(manager);
+	celix_dependencyManager_wait(manager);
+	return status;
+}
+
+celix_status_t celix_dependencyManager_removeAllComponentsAsync(celix_dependency_manager_t *manager) {
 	celix_status_t status = CELIX_SUCCESS;
     celix_array_list_t *toRemoveComponents = celix_arrayList_create();
 
@@ -119,7 +133,6 @@ celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_mana
 	return status;
 }
 
-
 static void celix_dm_getInfoCallback(void *handle, const celix_bundle_t *bnd) {
 	celix_dependency_manager_info_t **out = handle;
 
@@ -128,6 +141,8 @@ static void celix_dm_getInfoCallback(void *handle, const celix_bundle_t *bnd) {
 	celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(context);
 
 	celix_dependency_manager_info_t *info = calloc(1, sizeof(*info));
+    info->bndId = celix_bundle_getId(bnd);
+    info->bndSymbolicName = celix_utils_strdup(celix_bundle_getSymbolicName(bnd));
 	celixThreadMutex_lock(&mng->mutex);
 	if (info != NULL) {
 		info->components = celix_arrayList_create();
@@ -161,6 +176,7 @@ static void celix_dm_getInfosCallback(void *handle, const celix_bundle_t *bnd) {
 	celix_dependency_manager_info_t *info = calloc(1, sizeof(*info));
 	celixThreadMutex_lock(&mng->mutex);
     info->bndId = celix_bundle_getId(bnd);
+    info->bndSymbolicName = celix_utils_strdup(celix_bundle_getSymbolicName(bnd));
     info->components = celix_arrayList_create();
     int size = celix_arrayList_size(mng->components);
     for (int i = 0; i < size; i += 1) {
@@ -236,6 +252,7 @@ void celix_dependencyManager_destroyInfo(celix_dependency_manager_t *manager __a
 		component_destroyComponentInfo(cmpinfo);
 	}
 	arrayList_destroy(info->components);
+	free(info->bndSymbolicName);
 	free(info);
 }
 
@@ -314,4 +331,4 @@ celix_status_t dependencyManager_getInfo(celix_dependency_manager_t *manager, dm
 
 void dependencyManager_destroyInfo(celix_dependency_manager_t *manager, celix_dependency_manager_info_t *info) {
     celix_dependencyManager_destroyInfo(manager, info);
-}
+}
\ No newline at end of file