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: dev-unsubscr...@celix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to