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

pnoltes pushed a commit to branch feature/pubsub_custom_serializers
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to 
refs/heads/feature/pubsub_custom_serializers by this push:
     new c391ffa  Add a sync call to the framework, so that tests can wait till 
an event queue is empty (preventing need for sleeps)
c391ffa is described below

commit c391ffa6330656ed320b2fcac2059cd3750dc141
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sun Apr 19 11:56:25 2020 +0200

    Add a sync call to the framework, so that tests can wait till an event 
queue is empty (preventing need for sleeps)
---
 .github/workflows/build.yml                        |   4 +
 .../gtest/src/bundle_context_bundles_tests.cpp     | 105 +++++++--------------
 libs/framework/include/celix_framework.h           |  10 ++
 libs/framework/include/framework.h                 |   7 --
 libs/framework/src/framework.c                     |  16 +++-
 libs/framework/src/framework_private.h             |   1 +
 6 files changed, 62 insertions(+), 81 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 66d0e5d..224975e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,11 +14,14 @@ jobs:
         include:
           - os: ubuntu-18.04
             compiler: clang
+            cxx_compiler: clang++
           - os: ubuntu-18.04
             compiler: gcc
+            cxx_compiler: g++
           - os: ubuntu-18.04
             name: only v3 api
             compiler: gcc
+            cxx_compiler: g++
             v3_api: true
     timeout-minutes: 120
     steps:
@@ -51,6 +54,7 @@ jobs:
     - name: Build
       env:
         CC: ${{ matrix.compiler }}
+        CXX: ${{ matric.cxx_compiler }}
         BUILD_OPTIONS: |
           -DENABLE_TESTING=ON
           -DENABLE_ADDRESS_SANITIZER=ON
diff --git a/libs/framework/gtest/src/bundle_context_bundles_tests.cpp 
b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
index cd9298c..27dcd74 100644
--- a/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
+++ b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
@@ -296,41 +296,29 @@ TEST_F(CelixBundleContextBundlesTests, DoubleStopTest) {
 }
 
 TEST_F(CelixBundleContextBundlesTests, trackBundlesTest) {
-    const std::chrono::seconds waitTime{3};
-
     struct data {
-        int installedCount{0};
-        int startedCount{0};
-        int stoppedCount{0};
-        std::mutex mutex{};
-        std:: condition_variable cond{};
+        std::atomic<int> installedCount{0};
+        std::atomic<int> startedCount{0};
+        std::atomic<int> stoppedCount{0};
     };
     struct data data;
 
     auto installed = [](void *handle, const bundle_t *bnd) {
         auto *d = static_cast<struct data*>(handle);
         ASSERT_TRUE(bnd != nullptr);
-        d->mutex.lock();
-        d->installedCount += 1;
-        d->cond.notify_all();
-        d->mutex.unlock();
+        d->installedCount.fetch_add(1);
     };
 
     auto started = [](void *handle, const bundle_t *bnd) {
         auto *d = static_cast<struct data*>(handle);
         ASSERT_TRUE(bnd != nullptr);
-        d->mutex.lock();
-        d->startedCount += 1;
-        d->cond.notify_all();
-        d->mutex.unlock();
+        d->startedCount.fetch_add(1);
     };
+
     auto stopped = [](void *handle, const bundle_t *bnd) {
         auto *d = static_cast<struct data*>(handle);
         ASSERT_TRUE(bnd != nullptr);
-        d->mutex.lock();
-        d->stoppedCount += 1;
-        d->cond.notify_all();
-        d->mutex.unlock();
+        d->stoppedCount.fetch_add(1);
     };
 
     celix_bundle_tracking_options_t opts{};
@@ -339,74 +327,47 @@ TEST_F(CelixBundleContextBundlesTests, trackBundlesTest) {
     opts.onStarted = started;
     opts.onStopped = stopped;
 
-    long trackerId = celix_bundleContext_trackBundlesWithOptions(ctx, &opts);
-    ASSERT_EQ(0, data.startedCount); //note default framework bundle is not 
tracked
-
-
     long bundleId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, 
true);
     ASSERT_TRUE(bundleId1 >= 0);
 
-    {
-        std::unique_lock<std::mutex> lock{data.mutex};
-        data.cond.wait_for(lock, waitTime, [&]{return data.startedCount == 
1;});
+    /*
+     * NOTE for bundles already installed (TEST_BND1) the callbacks are called 
on the
+     * thread of celix_bundleContext_trackBundlesWithOptions.
+     * For Bundles installed after the 
celix_bundleContext_trackBundlesWithOptions function
+     * the called are called on the Celix framework event queue thread.
+     */
+    long trackerId = celix_bundleContext_trackBundlesWithOptions(ctx, &opts);
+    ASSERT_EQ(1, data.installedCount.load());
+    ASSERT_EQ(1, data.startedCount.load());
+    ASSERT_EQ(0, data.stoppedCount.load());
 
-    }
-    {
-        std::lock_guard<std::mutex> lock{data.mutex};
-        ASSERT_EQ(1, data.startedCount);
-        ASSERT_EQ(1, data.installedCount);
-    }
 
     long bundleId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, 
true);
+    celix_framework_waitForEmptyEventQueue(fw);
     ASSERT_TRUE(bundleId2 >= 0);
-    {
-        std::unique_lock<std::mutex> lock{data.mutex};
-        data.cond.wait_for(lock, waitTime, [&]{return data.startedCount == 
2;});
-
-    }
-    {
-        std::lock_guard<std::mutex> lock{data.mutex};
-        ASSERT_EQ(2, data.startedCount);
-        ASSERT_EQ(2, data.installedCount);
-    }
+    ASSERT_EQ(2, data.installedCount.load());
+    ASSERT_EQ(2, data.startedCount.load());
+    ASSERT_EQ(0, data.stoppedCount.load());
 
     celix_bundleContext_uninstallBundle(ctx, bundleId2);
-    {
-        std::unique_lock<std::mutex> lock{data.mutex};
-        data.cond.wait_for(lock, waitTime, [&]{return data.stoppedCount == 
1;});
-
-    }
-    {
-        std::lock_guard<std::mutex> lock{data.mutex};
-        ASSERT_EQ(1, data.stoppedCount);
-        ASSERT_EQ(2, data.installedCount);
-    }
+    celix_framework_waitForEmptyEventQueue(fw);
+    ASSERT_EQ(2, data.installedCount.load());
+    ASSERT_EQ(2, data.startedCount.load());
+    ASSERT_EQ(1, data.stoppedCount.load());
 
     long bundleId3 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, 
true);
     ASSERT_TRUE(bundleId3 >= 0);
-    {
-        std::unique_lock<std::mutex> lock{data.mutex};
-        data.cond.wait_for(lock, waitTime, [&]{return data.startedCount == 
3;});
-
-    }
-    {
-        std::lock_guard<std::mutex> lock{data.mutex};
-        ASSERT_EQ(3, data.startedCount);
-        ASSERT_EQ(3, data.installedCount);
-    }
+    celix_framework_waitForEmptyEventQueue(fw);
+    ASSERT_EQ(3, data.installedCount.load());
+    ASSERT_EQ(3, data.startedCount.load());
+    ASSERT_EQ(1, data.stoppedCount.load());
 
     bundleId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, true);
+    celix_framework_waitForEmptyEventQueue(fw);
     ASSERT_TRUE(bundleId2 >= 0);
-    {
-        std::unique_lock<std::mutex> lock{data.mutex};
-        data.cond.wait_for(lock, waitTime, [&]{return data.startedCount == 
4;});
-
-    }
-    {
-        std::lock_guard<std::mutex> lock{data.mutex};
-        ASSERT_EQ(4, data.startedCount);
-        ASSERT_EQ(4, data.installedCount);
-    }
+    ASSERT_EQ(4, data.installedCount.load());
+    ASSERT_EQ(4, data.startedCount.load());
+    ASSERT_EQ(1, data.stoppedCount.load());
 
     celix_bundleContext_stopTracker(ctx, trackerId);
 };
diff --git a/libs/framework/include/celix_framework.h 
b/libs/framework/include/celix_framework.h
index c3ba650..e06639c 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -134,6 +134,16 @@ bool celix_framework_stopBundle(celix_framework_t *fw, 
long bndId);
  */
 bool celix_framework_startBundle(celix_framework_t *fw, long bndId);
 
+/**
+ * Wait till the framework event queue is empty.
+ *
+ * The Celix framework has an event queue which (among others) handles bundle 
events.
+ * This function can be used to ensure that all queue event are handled, 
mainly useful
+ * for testing.
+ *
+ * @param fw The Celix Framework
+ */
+void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw);
 
 
 #ifdef __cplusplus
diff --git a/libs/framework/include/framework.h 
b/libs/framework/include/framework.h
index d5cc853..6ffa859 100644
--- a/libs/framework/include/framework.h
+++ b/libs/framework/include/framework.h
@@ -16,13 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * framework.h
- *
- *  \date       Mar 23, 2010
- *  \author            <a href="mailto:[email protected]";>Apache Celix 
Project Team</a>
- *  \copyright Apache License, Version 2.0
- */
 
 #ifndef FRAMEWORK_H_
 #define FRAMEWORK_H_
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 9056e74..f965508 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -297,6 +297,7 @@ celix_status_t framework_create(framework_pt *framework, 
properties_pt config) {
             (*framework)->bundleListeners = NULL;
             (*framework)->frameworkListeners = NULL;
             (*framework)->dispatcher.requests = NULL;
+            (*framework)->dispatcher.nrOfLocalRequest = 0;
             (*framework)->configurationMap = config;
             (*framework)->logger = logger;
 
@@ -1946,7 +1947,7 @@ celix_status_t fw_fireBundleEvent(framework_pt framework, 
bundle_event_type_e ev
         }
 
         celixThreadMutex_lock(&framework->dispatcher.mutex);
-        arrayList_add(framework->dispatcher.requests, request);
+        celix_arrayList_add(framework->dispatcher.requests, request);
         celixThreadCondition_broadcast(&framework->dispatcher.cond);
         celixThreadMutex_unlock(&framework->dispatcher.mutex);
 
@@ -2005,7 +2006,7 @@ celix_status_t fw_fireFrameworkEvent(framework_pt 
framework, framework_event_typ
         }
 
         celixThreadMutex_lock(&framework->dispatcher.mutex);
-        arrayList_add(framework->dispatcher.requests, request);
+        celix_arrayList_add(framework->dispatcher.requests, request);
         celixThreadCondition_broadcast(&framework->dispatcher.cond);
         celixThreadMutex_unlock(&framework->dispatcher.mutex);
     }
@@ -2077,6 +2078,7 @@ static void *fw_eventDispatcher(void *fw) {
             celix_arrayList_add(localRequests, r);
         }
         celix_arrayList_clear(framework->dispatcher.requests);
+        framework->dispatcher.nrOfLocalRequest = 
celix_arrayList_size(localRequests);
         celixThreadMutex_unlock(&framework->dispatcher.mutex);
 
         for (int i = 0; i < celix_arrayList_size(localRequests); ++i) {
@@ -2088,6 +2090,8 @@ static void *fw_eventDispatcher(void *fw) {
         celix_arrayList_clear(localRequests);
 
         celixThreadMutex_lock(&framework->dispatcher.mutex);
+        framework->dispatcher.nrOfLocalRequest = 0;
+        celixThreadCondition_broadcast(&framework->dispatcher.cond); //trigger 
threads waiting for an empty event queue (after local events are handled)
         active = framework->dispatcher.active;
         celixThreadMutex_unlock(&framework->dispatcher.mutex);
     }
@@ -2514,3 +2518,11 @@ bool celix_framework_startBundle(celix_framework_t *fw, 
long bndId) {
     }
     return started;
 }
+
+void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw) {
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    while ((celix_arrayList_size(fw->dispatcher.requests) + 
fw->dispatcher.nrOfLocalRequest) != 0) {
+        celixThreadCondition_wait(&fw->dispatcher.cond, &fw->dispatcher.mutex);
+    }
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
\ No newline at end of file
diff --git a/libs/framework/src/framework_private.h 
b/libs/framework/src/framework_private.h
index fdd0132..2af6014 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -83,6 +83,7 @@ struct celix_framework {
         celix_thread_mutex_t mutex; //protect active and requests
         bool active;
         celix_array_list_t *requests;
+        size_t nrOfLocalRequest;
     } dispatcher;
 
     framework_logger_pt logger;

Reply via email to