PengZheng commented on code in PR #734:
URL: https://github.com/apache/celix/pull/734#discussion_r1510524927
##########
libs/framework/src/bundle_context.c:
##########
@@ -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(&trkEntry->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);
Review Comment:
With high resolution timer enabled for linux kernel, this will lead to high
CPU usage. Is 1ms/10ms acceptable? I think they may be better.
##########
libs/framework/src/bundle_context.c:
##########
@@ -1058,11 +1082,10 @@ bool celix_bundleContext_useServiceWithId(
const char *serviceName,
void *callbackHandle,
void (*use)(void *handle, void *svc)) {
- celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-
- char filter[64];
- snprintf(filter, 64, "(%s=%li)", CELIX_FRAMEWORK_SERVICE_ID, serviceId);
+ char filter[32]; //20 is max long length
+ (void)snprintf(filter, sizeof(filter), "(%s=%li)",
CELIX_FRAMEWORK_SERVICE_ID, serviceId);
Review Comment:
A long can take value `INT64_MIN`, which need 20 bytes(including `-`). The
total length of the buffer needs to be 1 (`(`) + 10
(CELIX_FRAMEWORK_SERVICE_ID) + 1 (`=`) + 20 (`%li`) + 1 (`)`) + 1 ('\0') = 34
bytes. This modification will lead to gcc warning complaining string truncation.
##########
libs/framework/src/bundle_context.c:
##########
@@ -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(&trkEntry->useCount, __ATOMIC_RELAXED) > 0) {
Review Comment:
This needs to be `__ATOMIC_ACQUIRE`, otherwise the destroying of tracker may
seems like happen before this from the service user's point of view.
##########
libs/framework/src/bundle_context.c:
##########
@@ -1396,40 +1420,46 @@ static celix_service_tracker_t*
celix_bundleContext_findServiceTracker(celix_bun
}
if (!entry->tracker && entry->createEventId >= 0) { // tracker not yet
created (async creation)
- if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
- fw_log(
- ctx->framework->logger,
- CELIX_LOG_LEVEL_DEBUG,
- "Tracker with id %li is not yet created.",
- entry->trackerId);
- }
+ fw_log(
+ ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Tracker with id
%li is not yet created.", entry->trackerId);
+ return NULL;
}
- return entry->tracker;
+ return entry;
}
static size_t
celix_bundleContext_useTrackedServiceWithOptionsInternal(celix_bundle_context_t*
ctx,
long
trackerId,
const
celix_tracked_service_use_options_t* opts,
bool
singleUse) {
- celix_auto(celix_rwlock_rlock_guard_t) lck =
celixRwlockRlockGuard_init(&ctx->lock);
- celix_service_tracker_t* trk = celix_bundleContext_findServiceTracker(ctx,
trackerId);
- if (!trk) {
+ celixThreadRwlock_readLock(&ctx->lock);
+ celix_bundle_context_service_tracker_entry_t* trkEntry =
celix_bundleContext_findServiceTracker(ctx, trackerId);
+ if (trkEntry) {
+ // note use count is only increased inside a read (shared) lock and
ensures that the trkEntry is not freed and
+ // the trkEntry->tracker is not destroyed until the use count drops
back to 0.
+ (void)__atomic_fetch_add(&trkEntry->useCount, 1, __ATOMIC_RELAXED);
+ }
+ celixThreadRwlock_unlock(&ctx->lock);
+
+ if (!trkEntry) {
return 0;
}
+ size_t callCount;
if (singleUse) {
- bool called = celix_serviceTracker_useHighestRankingService(trk,
- NULL,
- 0,
-
opts->callbackHandle,
- opts->use,
-
opts->useWithProperties,
-
opts->useWithOwner);
- return called ? 1 : 0;
+ callCount =
celix_serviceTracker_useHighestRankingService(trkEntry->tracker,
+ NULL,
+ 0,
+
opts->callbackHandle,
+ opts->use,
+
opts->useWithProperties,
+
opts->useWithOwner);
} else {
- return celix_serviceTracker_useServices(
- trk, NULL, opts->callbackHandle, opts->use,
opts->useWithProperties, opts->useWithOwner);
+ callCount = celix_serviceTracker_useServices(
+ trkEntry->tracker, NULL, opts->callbackHandle, opts->use,
opts->useWithProperties, opts->useWithOwner);
}
+
+ (void)__atomic_fetch_sub(&trkEntry->useCount, 1, __ATOMIC_RELAXED);
Review Comment:
This has to be `__ATOMIC_RELEASE`, otherwise use of service may seem like
happen after this from the service stopper's point of view.
##########
libs/framework/src/bundle_context.c:
##########
@@ -1396,40 +1420,46 @@ static celix_service_tracker_t*
celix_bundleContext_findServiceTracker(celix_bun
}
if (!entry->tracker && entry->createEventId >= 0) { // tracker not yet
created (async creation)
- if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
- fw_log(
- ctx->framework->logger,
- CELIX_LOG_LEVEL_DEBUG,
- "Tracker with id %li is not yet created.",
- entry->trackerId);
- }
+ fw_log(
+ ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Tracker with id
%li is not yet created.", entry->trackerId);
+ return NULL;
}
- return entry->tracker;
+ return entry;
}
static size_t
celix_bundleContext_useTrackedServiceWithOptionsInternal(celix_bundle_context_t*
ctx,
long
trackerId,
const
celix_tracked_service_use_options_t* opts,
bool
singleUse) {
- celix_auto(celix_rwlock_rlock_guard_t) lck =
celixRwlockRlockGuard_init(&ctx->lock);
- celix_service_tracker_t* trk = celix_bundleContext_findServiceTracker(ctx,
trackerId);
- if (!trk) {
+ celixThreadRwlock_readLock(&ctx->lock);
+ celix_bundle_context_service_tracker_entry_t* trkEntry =
celix_bundleContext_findServiceTracker(ctx, trackerId);
+ if (trkEntry) {
+ // note use count is only increased inside a read (shared) lock and
ensures that the trkEntry is not freed and
+ // the trkEntry->tracker is not destroyed until the use count drops
back to 0.
+ (void)__atomic_fetch_add(&trkEntry->useCount, 1, __ATOMIC_RELAXED);
Review Comment:
This use of `__ATOMIC_RELAXED` is indeed correct.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]