This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch
feature/87-create-service-tracker-inside-useTrackedService-call
in repository https://gitbox.apache.org/repos/asf/celix.git
commit e665364e8dfa02db26b130d1f17bd87acc63e2dc
Author: Pepijn Noltes
AuthorDate: Sun Mar 3 11:24:47 2024 +0100
gh-87: Support creating service tracker inside a useTrackedService call
---
.../src/CelixBundleContextServicesTestSuite.cc | 23 +
libs/framework/src/bundle_context.c| 111 ++---
libs/framework/src/bundle_context_private.h| 3 +
3 files changed, 99 insertions(+), 38 deletions(-)
diff --git a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
index 607cb208..12ffcd94 100644
--- a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
@@ -2045,3 +2045,26 @@ TEST_F(CelixBundleContextServicesTestSuite,
UseTrackedServiceOnTheCelixEventThre
nullptr);
celix_framework_waitForGenericEvent(fw, eventId);
}
+
+TEST_F(CelixBundleContextServicesTestSuite,
CreateServiceTrackedOnUseServiceTrackerCall) {
+//Given a registered service with a service registration guard
+long svcId = celix_bundleContext_registerService(ctx, (void*)0x42, "test",
nullptr);
+celix_auto(celix_service_registration_guard_t) svcGuard =
celix_serviceRegistrationGuard_init(ctx, svcId);
+
+//And a service tracker for the "test" service with a service tracker
guard
+long trkId = celix_bundleContext_trackServices(ctx, "test");
+celix_auto(celix_tracker_guard_t) trkGuard = celix_trackerGuard_init(ctx,
trkId);
+
+//When all events are processed
+celix_bundleContext_waitForEvents(ctx);
+
+//Then I can create and destroy an additional service tracker on the
callback of the useTrackedService function
+auto useCallback = [](void *data, void* /*svc*/) {
+auto c = static_cast(data);
+long additionalTrkId = celix_bundleContext_trackServices(c, "foo");
+EXPECT_GT(additionalTrkId, 0);
+celix_bundleContext_stopTracker(c, additionalTrkId);
+};
+bool called = celix_bundleContext_useTrackedService(ctx, trkId, ctx,
useCallback);
+EXPECT_TRUE(called);
+}
diff --git a/libs/framework/src/bundle_context.c
b/libs/framework/src/bundle_context.c
index ee890648..99624cae 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -43,6 +43,8 @@
#include "celix_array_list.h"
#include "celix_convert_utils.h"
+#define TRACKER_WARN_THRESHOLD_SEC 5
+
static celix_status_t bundleContext_bundleChanged(void* listenerSvc,
bundle_event_t* event);
static void bundleContext_cleanupBundleTrackers(bundle_context_t *ct);
static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx);
@@ -839,7 +841,28 @@ static void
celix_bundleContext_removeServiceTrackerTracker(void *data) {
free(tracker);
}
-static void celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx,
long trackerId, bool async, void *doneData, void (*doneCallback)(void*
doneData)) {
+static void
celix_bundleContext_waitForUnusedServiceTracker(celix_bundle_context_t* ctx,
+
celix_bundle_context_service_tracker_entry_t* trkEntry) {
+// busy wait till the tracker is not used anymore
+// note that the use count cannot be increased anymore, because the
tracker is removed from the map
+struct timespec start = celix_gettime(CLOCK_MONOTONIC);
+int logCount = 0;
+while (__atomic_load_n(>useCount, __ATOMIC_RELAXED) > 0) {
+if (celix_elapsedtime(CLOCK_MONOTONIC, start) >
TRACKER_WARN_THRESHOLD_SEC) {
+fw_log(ctx->framework->logger,
+ CELIX_LOG_LEVEL_WARNING,
+ "Service tracker with trk id %li is still in use after %i
seconds. "
+ "This might indicate a programming error.",
+ trkEntry->trackerId,
+ logCount * TRACKER_WARN_THRESHOLD_SEC);
+start = celix_gettime(CLOCK_MONOTONIC);
+logCount++;
+}
+usleep(1);
+}
+}
+
+static void celix_bundleContext_stopTrackerInternal(celix_bundle_context_t*
ctx, long trackerId, bool async, void *doneData, void (*doneCallback)(void*
doneData)) {
if (ctx == NULL || trackerId <= 0) {
return;
}
@@ -888,6 +911,7 @@ static void
celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long
fw_removeBundleListener(ctx->framework, ctx->bundle,
>listener);
free(bundleTracker);
} else if (serviceTracker != NULL) {
+celix_bundleContext_waitForUnusedServiceTracker(ctx,
serviceTracker);
celix_serviceTracker_destroy(serviceTracker->tracker);
if