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;