PengZheng commented on a change in pull request #399:
URL: https://github.com/apache/celix/pull/399#discussion_r816607673



##########
File path: libs/framework/src/bundle_context.c
##########
@@ -1181,78 +1182,70 @@ static void 
celix_bundleContext_useServiceWithOptions_2_UseServiceTracker(void *
     celix_bundle_context_use_service_data_t* d = data;
     assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
 
-    d->called = celix_serviceTracker_useHighestRankingService(d->svcTracker, 
d->opts->filter.serviceName, d->opts->callbackHandle, d->opts->use, 
d->opts->useWithProperties, d->opts->useWithOwner);
-}
-
-static void 
celix_bundleContext_useServiceWithOptions_3_CloseServiceTracker(void *data) {
-    celix_bundle_context_use_service_data_t* d = data;
-    assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
-
-    celix_service_tracker_t *tracker = d->svcTracker;
-    d->svcTracker = NULL;
-
-    celix_serviceTracker_destroy(tracker);
+    d->called = celix_serviceTracker_useHighestRankingService(d->svcTracker, 
d->opts->filter.serviceName, 0, d->opts->callbackHandle, d->opts->use, 
d->opts->useWithProperties, d->opts->useWithOwner);
 }
 
 bool celix_bundleContext_useServiceWithOptions(
         celix_bundle_context_t *ctx,
         const celix_service_use_options_t *opts) {
-    if (opts == NULL) {
+    if (opts == NULL || opts->filter.serviceName == NULL) {
         return false;
     }
 
     celix_bundle_context_use_service_data_t data = {0};
     data.ctx = ctx;
     data.opts = opts;
+    bool called = false;
 
     if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
         // Ignore timeout: blocking the event loop prevents any progress to be 
made
         
celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(&data);
         celix_bundleContext_useServiceWithOptions_2_UseServiceTracker(&data);
-        celix_bundleContext_useServiceWithOptions_3_CloseServiceTracker(&data);
+        celix_serviceTracker_destroy(data.svcTracker);
         return data.called;
     }
 
     long eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "create service tracker for 
celix_bundleContext_useServiceWithOptions", &data, 
celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker, NULL, NULL);
     celix_framework_waitForGenericEvent(ctx->framework, eventId);
 
-    celix_framework_waitForEmptyEventQueue(ctx->framework); //ensure that a 
useService wait if a listener hooks concept, which triggers an async service 
registration
 
-    struct timespec startTime = celix_gettime(CLOCK_MONOTONIC);
-    bool useServiceIsDone = false;
-    bool called = false;
-    do {
-        eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "use service tracker for 
celix_bundleContext_useServiceWithOptions", &data, 
celix_bundleContext_useServiceWithOptions_2_UseServiceTracker, NULL, NULL);
-        celix_framework_waitForGenericEvent(ctx->framework, eventId);
+    if(opts->flags & CELIX_SERVICE_USE_DIRECT) {
+        celix_framework_waitUntilNoPendingRegistration(ctx->framework); // 
TL;DR make "service on demand" pattern work. Try comment it out and run 
CelixBundleContextServicesTests.UseServiceOnDemandDirectlyWithAsyncRegisterTest

Review comment:
       Now `CELIX_SERVICE_USE_DIRECT` will not support SOD by default, unless 
explicitly requested by user.
   
   Since last mails, I've thought about this. I see one potential problem with 
direct registry usage: global lock contention, i.e. users interested in 
different services will affect each other. I have the following scenario in 
mind:
   
   1. Create one tracker (on bundle start maybe).
   2. Use service via the same tracker concurrently from multiple threads.
   3. Destroy the tracker (on bundle stop maybe).
   
   By design, users of different services use different trackers, global lock 
contention is reduced into per tracker lock contention. Furthermore, 
performance of concurrent use of the same tracker can be further improved by 
using read-write lock instead of the tracker lock. 
   
   However, current tracker implementation is sub-optimal: currently there is 
no way to obtain opaque tracker pointer, only the tracker id is returned. The 
translation between tracker id and opaque tracker pointer involves bundle 
context lock. Thus our design only reduces global lock contention into per 
bundle lock contention, not the optimal per tracker lock contention. If we can 
get opaque tracker pointer from tracker id (service tracker is still created on 
the event loop), then 
`celix_serviceTracker_useHighestRankingService`/`celix_serviceTracker_useHighestRankingService`
 can help us achieving optimal performance. Since no event loop is involved in 
`celix_serviceTracker_useHighestRankingService`, its recursive usage (using a 
service itself calling useService) together with async API may not hurt us any 
more.  IIRC, the intention of original OSGi service tracker is to avoid 
external synchronization implemented by user.  By re-exposing 
`celix_serviceTracker_useHighestRankingService`
  as public API, we can recovery its original design purpose.
   
   I planed to discuss it with you after the release happens, since it involves 
public API change bigger than this PR. 
   
   PS: Currently I'm working on conan support. Hopefully, a PR will arrive this 
week. @pnoltes 




-- 
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