Repository: celix
Updated Branches:
  refs/heads/develop 02ee6c4e5 -> bcda87f54


CELIX-452: Changes the behaviour of the serviceTracker_close, so that removing 
the service listener is done on a separate thread.

This is needed because the previous commits added sync behaviour to the 
serviceChanged handling. As result a serviceChange event will ensure that 
removeServiceListener call will only returned if it is not used anymore. This 
can introduces a deadlock when removing a service listener from a service 
change event callback. This is specifically the case with service trackers, 
because they remove a service listeners in the sync close call.

The removing of the service listener is now done on a detached thread. During 
bundle stop and framework stop a sync call is used to ensure all detached 
"service tracker shutdown" threads are done. Because the current api support 
stopping and restarted a service tracker, some considerable refactoring was 
needed in the general service tracker internals.


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/bcda87f5
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/bcda87f5
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/bcda87f5

Branch: refs/heads/develop
Commit: bcda87f5431bbb8eab570a75b350971e3753f18a
Parents: 02ee6c4
Author: Pepijn Noltes <[email protected]>
Authored: Tue Jul 17 21:25:26 2018 +0200
Committer: Pepijn Noltes <[email protected]>
Committed: Tue Jul 17 21:25:26 2018 +0200

----------------------------------------------------------------------
 libs/framework/include/celix_framework.h        |   1 +
 libs/framework/include/service_tracker.h        |  11 +
 .../include/service_tracker_customizer.h        |   7 +
 .../test/service_tracker_customizer_test.cpp    |   2 +-
 libs/framework/src/framework.c                  |   7 +-
 libs/framework/src/service_tracker.c            | 743 ++++++++++++-------
 libs/framework/src/service_tracker_customizer.c |   2 +-
 .../src/service_tracker_customizer_private.h    |  49 --
 libs/framework/src/service_tracker_private.h    |  48 +-
 libs/framework/tst/CMakeLists.txt               |   1 +
 .../tst/bundle_context_services_test.cpp        |   3 +
 11 files changed, 552 insertions(+), 322 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/include/celix_framework.h
----------------------------------------------------------------------
diff --git a/libs/framework/include/celix_framework.h 
b/libs/framework/include/celix_framework.h
index ac3193e..39116f6 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -21,6 +21,7 @@
 
 typedef struct framework celix_framework_t;
 
+
 #include "celix_types.h"
 #include "celix_properties.h"
 

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/include/service_tracker.h
----------------------------------------------------------------------
diff --git a/libs/framework/include/service_tracker.h 
b/libs/framework/include/service_tracker.h
index 7fb5f54..40559db 100644
--- a/libs/framework/include/service_tracker.h
+++ b/libs/framework/include/service_tracker.h
@@ -135,6 +135,17 @@ void celix_serviceTracker_useServices(
         void (*useWithOwner)(void *handle, void *svc, const celix_properties_t 
*props, const celix_bundle_t *owner)
 );
 
+/**
+ * blocks until all shutdown threads for the service tracker instances for the 
provided framework are done.
+ */
+void celix_serviceTracker_syncForFramework(void *fw);
+
+/**
+ * blocks until all shutdown threads for the service tracker instances for the 
provided bundle context are done.
+ */
+void celix_serviceTracker_syncForContext(void *ctx);
+
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/include/service_tracker_customizer.h
----------------------------------------------------------------------
diff --git a/libs/framework/include/service_tracker_customizer.h 
b/libs/framework/include/service_tracker_customizer.h
index 19672d8..2ddd437 100644
--- a/libs/framework/include/service_tracker_customizer.h
+++ b/libs/framework/include/service_tracker_customizer.h
@@ -46,6 +46,13 @@ typedef celix_status_t (*removed_callback_pt)(void *handle, 
service_reference_pt
 typedef struct serviceTrackerCustomizer *service_tracker_customizer_pt;
 typedef struct serviceTrackerCustomizer service_tracker_customizer_t;
 
+struct serviceTrackerCustomizer {
+       void * handle;
+       celix_status_t (*addingService)(void * handle, service_reference_pt 
reference, void **service);
+       celix_status_t (*addedService)(void * handle, service_reference_pt 
reference, void * service);
+       celix_status_t (*modifiedService)(void * handle, service_reference_pt 
reference, void * service);
+       celix_status_t (*removedService)(void * handle, service_reference_pt 
reference, void * service);
+};
 
 FRAMEWORK_EXPORT celix_status_t serviceTrackerCustomizer_create(void *handle,
                                                                                
                                                adding_callback_pt 
addingFunction,

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/private/test/service_tracker_customizer_test.cpp
----------------------------------------------------------------------
diff --git a/libs/framework/private/test/service_tracker_customizer_test.cpp 
b/libs/framework/private/test/service_tracker_customizer_test.cpp
index a80cd29..ced8f3c 100644
--- a/libs/framework/private/test/service_tracker_customizer_test.cpp
+++ b/libs/framework/private/test/service_tracker_customizer_test.cpp
@@ -34,7 +34,7 @@
 
 extern "C"
 {
-#include "service_tracker_customizer_private.h"
+#include "service_tracker_customizer.h"
 #include "service_reference.h"
 #include "celix_log.h"
 

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/src/framework.c
----------------------------------------------------------------------
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index fcfe07f..2bd5d84 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -44,6 +44,7 @@
 #include "bundle_private.h"
 #include "celix_bundle_context.h"
 #include "bundle_context_private.h"
+#include "service_tracker.h"
 
 typedef celix_status_t (*create_function_fp)(bundle_context_t *context, void 
**userData);
 typedef celix_status_t (*start_function_fp)(void *userData, bundle_context_t 
*context);
@@ -184,7 +185,7 @@ static inline void 
listener_release(celix_fw_service_listener_entry_t *entry) {
     assert(entry->useCount > 0);
     entry->useCount -= 1;
     if (entry->useCount == 0) {
-        celixThreadCondition_signal(&entry->useCond);
+        celixThreadCondition_broadcast(&entry->useCond);
     }
     celixThreadMutex_unlock(&entry->mutex);
 }
@@ -389,6 +390,7 @@ celix_status_t framework_destroy(framework_pt framework) {
            int i;
            for (i = 0; i < arrayList_size(framework->requests); i++) {
                request_pt request = arrayList_get(framework->requests, i);
+               free(request->bundleSymbolicName);
                free(request);
            }
            arrayList_destroy(framework->requests);
@@ -1057,6 +1059,7 @@ celix_status_t fw_stopBundle(framework_pt framework, 
bundle_pt bundle, bool reco
                }
 
             if (id != 0) {
+                   celix_serviceTracker_syncForContext(bundle->context);
                 status = CELIX_DO_IF(status, 
serviceRegistry_clearServiceRegistrations(framework->registry, bundle));
                 if (status == CELIX_SUCCESS) {
                     module_pt module = NULL;
@@ -1103,6 +1106,8 @@ celix_status_t fw_stopBundle(framework_pt framework, 
bundle_pt bundle, bool reco
         fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED, 
bundle);
        }
 
+       celix_serviceTracker_syncForFramework(framework);
+
        return status;
 }
 

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/src/service_tracker.c
----------------------------------------------------------------------
diff --git a/libs/framework/src/service_tracker.c 
b/libs/framework/src/service_tracker.c
index 4e13275..87dff42 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -28,22 +28,39 @@
 #include "constants.h"
 #include "service_reference.h"
 #include "celix_log.h"
-#include "service_tracker_customizer_private.h"
 #include "bundle_context_private.h"
 #include "celix_array_list.h"
 
-static celix_status_t serviceTracker_track(service_tracker_pt tracker, 
service_reference_pt reference, celix_service_event_t *event);
-static celix_status_t serviceTracker_untrack(service_tracker_pt tracker, 
service_reference_pt reference, celix_service_event_t *event);
-static void serviceTracker_untrackTracked(celix_service_tracker_t *tracker, 
celix_tracked_entry_t *tracked);
-static celix_status_t 
serviceTracker_invokeAddingService(celix_service_tracker_t *tracker, 
service_reference_pt ref, void **svcOut);
-static celix_status_t serviceTracker_invokeAddService(celix_service_tracker_t 
*tracker, celix_tracked_entry_t *tracked);
-static celix_status_t 
serviceTracker_invokeModifiedService(celix_service_tracker_t *tracker, 
celix_tracked_entry_t *tracked);
-static celix_status_t 
serviceTracker_invokeRemovingService(celix_service_tracker_t *tracker, 
celix_tracked_entry_t *tracked);
+static celix_status_t serviceTracker_track(celix_service_tracker_instance_t 
*tracker, service_reference_pt reference, celix_service_event_t *event);
+static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t 
*tracker, service_reference_pt reference, celix_service_event_t *event);
+static void serviceTracker_untrackTracked(celix_service_tracker_instance_t 
*tracker, celix_tracked_entry_t *tracked);
+static celix_status_t 
serviceTracker_invokeAddingService(celix_service_tracker_instance_t *tracker, 
service_reference_pt ref, void **svcOut);
+static celix_status_t 
serviceTracker_invokeAddService(celix_service_tracker_instance_t *tracker, 
celix_tracked_entry_t *tracked);
+static celix_status_t 
serviceTracker_invokeModifiedService(celix_service_tracker_instance_t *tracker, 
celix_tracked_entry_t *tracked);
+static celix_status_t 
serviceTracker_invokeRemovingService(celix_service_tracker_instance_t *tracker, 
celix_tracked_entry_t *tracked);
 static void serviceTracker_checkAndInvokeSetService(void *handle, void 
*highestSvc, const properties_t *props, const bundle_t *bnd);
+static bool 
serviceTracker_useHighestRankingServiceInternal(celix_service_tracker_instance_t
 *instance,
+                                                            const char 
*serviceName /*sanity*/,
+                                                            void 
*callbackHandle,
+                                                            void (*use)(void 
*handle, void *svc),
+                                                            void 
(*useWithProperties)(void *handle, void *svc, const celix_properties_t *props),
+                                                            void 
(*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const 
celix_bundle_t *owner));
+
+static void 
serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t 
*instance);
+static void 
serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t 
*instance);
+
+static celix_thread_once_t g_once = CELIX_THREAD_ONCE_INIT;
+static celix_thread_mutex_t g_mutex;
+static celix_thread_cond_t g_cond;
+static celix_array_list_t *g_shutdownInstances = NULL; //value = 
celix_service_tracker_instance -> used for syncing with shutdown threads
+
+static void serviceTracker_once(void) {
+    celixThreadMutex_create(&g_mutex, NULL);
+    celixThreadCondition_init(&g_cond, NULL);
+}
 
 static inline celix_tracked_entry_t* tracked_create(service_reference_pt ref, 
void *svc, celix_properties_t *props, celix_bundle_t *bnd) {
     celix_tracked_entry_t *tracked = calloc(1, sizeof(*tracked));
-
     tracked->reference = ref;
     tracked->service = svc;
     tracked->properties = props;
@@ -67,7 +84,7 @@ static inline void tracked_release(celix_tracked_entry_t 
*tracked) {
     assert(tracked->useCount > 0);
     tracked->useCount -= 1;
     if (tracked->useCount == 0) {
-        celixThreadCondition_signal(&tracked->useCond);
+        celixThreadCondition_broadcast(&tracked->useCond);
     }
     celixThreadMutex_unlock(&tracked->mutex);
 }
@@ -111,15 +128,7 @@ celix_status_t 
serviceTracker_createWithFilter(bundle_context_pt context, const
        } else {
                (*tracker)->context = context;
                (*tracker)->filter = strdup(filter);
-
-        celixThreadRwlock_create(&(*tracker)->lock, NULL);
-               (*tracker)->trackedServices = NULL;
-               arrayList_create(&(*tracker)->trackedServices);
         (*tracker)->customizer = customizer;
-               (*tracker)->listener = NULL;
-
-               celixThreadMutex_create(&(*tracker)->mutex, NULL);
-        (*tracker)->currentHighestServiceId = -1;
        }
 
        framework_logIfError(logger, status, NULL, "Cannot create service 
tracker [filter=%s]", filter);
@@ -128,24 +137,10 @@ celix_status_t 
serviceTracker_createWithFilter(bundle_context_pt context, const
 }
 
 celix_status_t serviceTracker_destroy(service_tracker_pt tracker) {
-       if (tracker->listener != NULL) {
-               bundleContext_removeServiceListener(tracker->context, 
tracker->listener);
-       }
-       if (tracker->customizer != NULL) {
+    if (tracker->customizer != NULL) {
            serviceTrackerCustomizer_destroy(tracker->customizer);
        }
 
-    celixThreadRwlock_writeLock(&tracker->lock);
-       arrayList_destroy(tracker->trackedServices);
-    celixThreadRwlock_unlock(&tracker->lock);
-
-
-       if (tracker->listener != NULL) {
-               free (tracker->listener);
-       }
-
-    celixThreadRwlock_destroy(&tracker->lock);
-
        free(tracker->filter);
        free(tracker);
 
@@ -153,35 +148,71 @@ celix_status_t serviceTracker_destroy(service_tracker_pt 
tracker) {
 }
 
 celix_status_t serviceTracker_open(service_tracker_pt tracker) {
-       celix_service_listener_t *listener;
-       array_list_pt initial = NULL;
-       celix_status_t status = CELIX_SUCCESS;
-       listener = (celix_service_listener_t *) malloc(sizeof(*listener));
-       
-       status = bundleContext_getServiceReferences(tracker->context, NULL, 
tracker->filter, &initial); //REF COUNT to 1
-       if (status == CELIX_SUCCESS && listener != NULL) {
-               service_reference_pt initial_reference;
-               unsigned int i;
-
-               listener->handle = tracker;
-               listener->serviceChanged = (void *) 
serviceTracker_serviceChanged;
-               status = bundleContext_addServiceListener(tracker->context, 
listener, tracker->filter);
-               if (status == CELIX_SUCCESS) {
-                       tracker->listener = listener;
+    celix_service_listener_t *listener = NULL;
+    celix_service_tracker_instance_t *instance = NULL;
+    array_list_pt initial = NULL;
+    celix_status_t status = CELIX_SUCCESS;
 
-                       for (i = 0; i < arrayList_size(initial); i++) {
-                               initial_reference = (service_reference_pt) 
arrayList_get(initial, i);
-                               serviceTracker_track(tracker, 
initial_reference, NULL); //REF COUNT to 2
-                bundleContext_ungetServiceReference(tracker->context, 
initial_reference); //REF COUNT to 1
-                       }
+    celixThreadRwlock_writeLock(&tracker->instanceLock);
+    if (tracker->instance == NULL) {
+        instance = calloc(1, sizeof(*instance));
+        instance->context = tracker->context;
 
-                       arrayList_destroy(initial);
+        instance->closing = false;
+        instance->activeServiceChangeCalls = 0;
+        celixThreadMutex_create(&instance->closingLock, NULL);
+        celixThreadCondition_init(&instance->activeServiceChangeCallsCond, 
NULL);
 
-                       initial = NULL;
-               }
-       }
 
-       if(status != CELIX_SUCCESS && listener != NULL){
+        celixThreadRwlock_create(&instance->lock, NULL);
+        instance->trackedServices = celix_arrayList_create();
+
+        celixThreadMutex_create(&instance->mutex, NULL);
+        instance->currentHighestServiceId = -1;
+
+        instance->listener.handle = instance;
+        instance->listener.serviceChanged = (void *) 
serviceTracker_serviceChanged;
+        listener = &instance->listener;
+
+        instance->callbackHandle = tracker->callbackHandle;
+        instance->filter = strdup(tracker->filter);
+        if (tracker->customizer != NULL) {
+            memcpy(&instance->customizer, tracker->customizer, 
sizeof(instance->customizer));
+        }
+        instance->add = tracker->add;
+        instance->addWithProperties = tracker->addWithProperties;
+        instance->addWithOwner = tracker->addWithOwner;
+        instance->set = tracker->set;
+        instance->setWithProperties = tracker->setWithProperties;
+        instance->setWithOwner = tracker->setWithOwner;
+        instance->remove = tracker->remove;
+        instance->removeWithProperties = tracker->removeWithProperties;
+        instance->removeWithOwner = tracker->removeWithOwner;
+
+        status = bundleContext_getServiceReferences(tracker->context, NULL, 
tracker->filter, &initial); //REF COUNT to 1
+
+        tracker->instance = instance;
+    } else {
+        //already open
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
+
+    //TODO add fw call which adds a service listener and return the then valid 
service references.
+    if (status == CELIX_SUCCESS && listener != NULL) { //register service 
listener
+        status = bundleContext_addServiceListener(tracker->context, listener, 
tracker->filter);
+    }
+    if (status == CELIX_SUCCESS && initial != NULL) {
+        service_reference_pt initial_reference;
+        unsigned int i;
+        for (i = 0; i < arrayList_size(initial); i++) {
+            initial_reference = (service_reference_pt) arrayList_get(initial, 
i);
+            serviceTracker_track(instance, initial_reference, NULL); //REF 
COUNT to 2
+            bundleContext_ungetServiceReference(tracker->context, 
initial_reference); //REF COUNT to 1
+        }
+        arrayList_destroy(initial);
+    }
+
+       if (status != CELIX_SUCCESS && listener != NULL){
                free(listener);
        }
 
@@ -190,27 +221,75 @@ celix_status_t serviceTracker_open(service_tracker_pt 
tracker) {
        return status;
 }
 
-celix_status_t serviceTracker_close(service_tracker_pt tracker) {
+static void* shutdownServiceTrackerInstanceHandler(void *data) {
+    celix_service_tracker_instance_t *instance = data;
+
+    fw_removeServiceListener(instance->context->framework, 
instance->context->bundle, &instance->listener);
+
+    celixThreadMutex_destroy(&instance->closingLock);
+    celixThreadCondition_destroy(&instance->activeServiceChangeCallsCond);
+    celixThreadMutex_destroy(&instance->mutex);
+    celixThreadRwlock_destroy(&instance->lock);
+    celix_arrayList_destroy(instance->trackedServices);
+    free(instance->filter);
+
+    serviceTracker_remInstanceFromShutdownList(instance);
+    free(instance);
 
+    return NULL;
+}
+
+celix_status_t serviceTracker_close(service_tracker_pt tracker) {
        //put all tracked entries in tmp array list, so that the untrack (etc) 
calls are not blocked.
-       int i;
-    celixThreadRwlock_writeLock(&tracker->lock);
-    fw_removeServiceListener(tracker->context->framework, 
tracker->context->bundle, tracker->listener); //remove in lock, to ensure no 
new tracked entry is added
-    size_t size = celix_arrayList_size(tracker->trackedServices);
-    celix_tracked_entry_t* trackedEntries[size];
-    for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
-        trackedEntries[i] = 
(celix_tracked_entry_t*)arrayList_get(tracker->trackedServices, i);
-    }
-    arrayList_clear(tracker->trackedServices);
-    celixThreadRwlock_unlock(&tracker->lock);
-
-    //loop trough tracked entries an untrack
-    for (i = 0; i < size; i++) {
-        serviceTracker_untrackTracked(tracker, trackedEntries[i]);
-    }
+    //set state to close to prevent service listener events
+
+    celixThreadRwlock_writeLock(&tracker->instanceLock);
+    celix_service_tracker_instance_t *instance = tracker->instance;
+    tracker->instance = NULL;
+    celixThreadRwlock_unlock(&tracker->instanceLock);
+
+    if (instance != NULL) {
+
+        //prevent service listener events
+        celixThreadMutex_lock(&instance->closingLock);
+        instance->closing = true;
+        celixThreadMutex_unlock(&instance->closingLock);
+
+        int i;
+        celixThreadRwlock_writeLock(&instance->lock);
+        size_t size = celix_arrayList_size(instance->trackedServices);
+        celix_tracked_entry_t *trackedEntries[size];
+        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+            trackedEntries[i] = (celix_tracked_entry_t *) 
arrayList_get(instance->trackedServices, i);
+        }
+        arrayList_clear(instance->trackedServices);
+        celixThreadRwlock_unlock(&instance->lock);
 
-    free(tracker->listener);
-    tracker->listener = NULL;
+        //loop trough tracked entries an untrack
+        for (i = 0; i < size; i++) {
+            serviceTracker_untrackTracked(instance, trackedEntries[i]);
+        }
+
+        //sync til all pending serviceChanged event are handled.. (TODO again 
a possible deadlock??)
+        celixThreadMutex_lock(&instance->closingLock);
+        while(instance->activeServiceChangeCalls > 0) {
+            celixThreadCondition_wait(&instance->activeServiceChangeCallsCond, 
&instance->closingLock);
+        }
+        celixThreadMutex_unlock(&instance->closingLock);
+
+
+
+        //NOTE Separate thread is needed to prevent deadlock where closing is 
triggered from a serviceChange event and the
+        // untrack -> removeServiceListener will try to remove a service 
listener which is being invoked and is the
+        // actual thread calling the removeServiceListener.
+        //
+        // This can be detached -> because service listener events are ignored 
(closing=true) and so no callbacks
+        //are made back to the celix framework / tracker owner.
+        serviceTracker_addInstanceFromShutdownList(instance);
+        celix_thread_t localThread;
+        celixThread_create(&localThread, NULL, 
shutdownServiceTrackerInstanceHandler, instance);
+        celixThread_detach(localThread);
+    }
 
        return CELIX_SUCCESS;
 }
@@ -221,13 +300,18 @@ service_reference_pt 
serviceTracker_getServiceReference(service_tracker_pt track
     service_reference_pt result = NULL;
        unsigned int i;
 
-    celixThreadRwlock_readLock(&tracker->lock);
-       for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
-               tracked = (celix_tracked_entry_t*) 
arrayList_get(tracker->trackedServices, i);
-               result = tracked->reference;
-        break;
-       }
-    celixThreadRwlock_unlock(&tracker->lock);
+       celixThreadRwlock_readLock(&tracker->instanceLock);
+       celix_service_tracker_instance_t *instance = tracker->instance;
+       if (instance != NULL) {
+        celixThreadRwlock_readLock(&instance->lock);
+        for (i = 0; i < arrayList_size(instance->trackedServices); ++i) {
+            tracked = (celix_tracked_entry_t *) 
arrayList_get(instance->trackedServices, i);
+            result = tracked->reference;
+            break;
+        }
+        celixThreadRwlock_unlock(&instance->lock);
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
 
        return result;
 }
@@ -239,12 +323,17 @@ array_list_pt 
serviceTracker_getServiceReferences(service_tracker_pt tracker) {
        array_list_pt references = NULL;
        arrayList_create(&references);
 
-    celixThreadRwlock_readLock(&tracker->lock);
-       for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
-               tracked = (celix_tracked_entry_t*) 
arrayList_get(tracker->trackedServices, i);
-               arrayList_add(references, tracked->reference);
-       }
-    celixThreadRwlock_unlock(&tracker->lock);
+    celixThreadRwlock_readLock(&tracker->instanceLock);
+       celix_service_tracker_instance_t *instance = tracker->instance;
+       if (instance != NULL) {
+        celixThreadRwlock_readLock(&instance->lock);
+        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+            tracked = (celix_tracked_entry_t*) 
arrayList_get(instance->trackedServices, i);
+            arrayList_add(references, tracked->reference);
+        }
+        celixThreadRwlock_unlock(&instance->lock);
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
 
        return references;
 }
@@ -255,13 +344,18 @@ void *serviceTracker_getService(service_tracker_pt 
tracker) {
     void *service = NULL;
        unsigned int i;
 
-    celixThreadRwlock_readLock(&tracker->lock);
-    for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
-               tracked = (celix_tracked_entry_t*) 
arrayList_get(tracker->trackedServices, i);
-               service = tracked->service;
-        break;
-       }
-    celixThreadRwlock_unlock(&tracker->lock);
+       celixThreadRwlock_readLock(&tracker->instanceLock);
+       celix_service_tracker_instance_t *instance = tracker->instance;
+       if (instance != NULL) {
+        celixThreadRwlock_readLock(&instance->lock);
+        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+            tracked = (celix_tracked_entry_t*) 
arrayList_get(instance->trackedServices, i);
+            service = tracked->service;
+            break;
+        }
+        celixThreadRwlock_unlock(&instance->lock);
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
 
     return service;
 }
@@ -273,12 +367,17 @@ array_list_pt 
serviceTracker_getServices(service_tracker_pt tracker) {
        array_list_pt references = NULL;
        arrayList_create(&references);
 
-    celixThreadRwlock_readLock(&tracker->lock);
-    for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
-               tracked = (celix_tracked_entry_t*) 
arrayList_get(tracker->trackedServices, i);
-               arrayList_add(references, tracked->service);
-       }
-    celixThreadRwlock_unlock(&tracker->lock);
+    celixThreadRwlock_readLock(&tracker->instanceLock);
+    celix_service_tracker_instance_t *instance = tracker->instance;
+    if (instance != NULL) {
+        celixThreadRwlock_readLock(&instance->lock);
+        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+            tracked = (celix_tracked_entry_t *) 
arrayList_get(instance->trackedServices, i);
+            arrayList_add(references, tracked->service);
+        }
+        celixThreadRwlock_unlock(&instance->lock);
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
 
     return references;
 }
@@ -289,51 +388,73 @@ void 
*serviceTracker_getServiceByReference(service_tracker_pt tracker, service_r
     void *service = NULL;
        unsigned int i;
 
-    celixThreadRwlock_readLock(&tracker->lock);
-       for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
-               bool equals = false;
-               tracked = (celix_tracked_entry_t*) 
arrayList_get(tracker->trackedServices, i);
-               serviceReference_equals(reference, tracked->reference, &equals);
-               if (equals) {
-                       service = tracked->service;
-            break;
-               }
-       }
-    celixThreadRwlock_unlock(&tracker->lock);
+    celixThreadRwlock_readLock(&tracker->instanceLock);
+    celix_service_tracker_instance_t *instance = tracker->instance;
+    if (instance != NULL) {
+        celixThreadRwlock_readLock(&instance->lock);
+        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+            bool equals = false;
+            tracked = (celix_tracked_entry_t *) 
arrayList_get(instance->trackedServices, i);
+            serviceReference_equals(reference, tracked->reference, &equals);
+            if (equals) {
+                service = tracked->service;
+                break;
+            }
+        }
+        celixThreadRwlock_unlock(&instance->lock);
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
 
        return service;
 }
 
 void serviceTracker_serviceChanged(celix_service_listener_t *listener, 
celix_service_event_t *event) {
-       service_tracker_pt tracker = listener->handle;
-       switch (event->type) {
-               case OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED:
-                       serviceTracker_track(tracker, event->reference, event);
-                       break;
-               case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED:
-                       serviceTracker_track(tracker, event->reference, event);
-                       break;
-               case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING:
-                       serviceTracker_untrack(tracker, event->reference, 
event);
-                       break;
-               case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH:
-            //TODO
-                       break;
-       }
+       celix_service_tracker_instance_t *instance = listener->handle;
+
+    celixThreadMutex_lock(&instance->closingLock);
+    bool closing = instance->closing;
+    if (!closing) {
+        instance->activeServiceChangeCalls += 1;
+    }
+    celixThreadMutex_unlock(&instance->closingLock);
+
+    if (!closing) {
+        switch (event->type) {
+            case OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED:
+                serviceTracker_track(instance, event->reference, event);
+                break;
+            case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED:
+                serviceTracker_track(instance, event->reference, event);
+                break;
+            case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING:
+                serviceTracker_untrack(instance, event->reference, event);
+                break;
+            case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH:
+                //TODO
+                break;
+        }
+        celixThreadMutex_lock(&instance->closingLock);
+        assert(instance->activeServiceChangeCalls > 0);
+        instance->activeServiceChangeCalls -= 1;
+        if (instance->activeServiceChangeCalls == 0) {
+            
celixThreadCondition_broadcast(&instance->activeServiceChangeCallsCond);
+        }
+        celixThreadMutex_unlock(&instance->closingLock);
+    }
 }
 
-static celix_status_t serviceTracker_track(service_tracker_pt tracker, 
service_reference_pt reference, celix_service_event_t *event) {
+static celix_status_t serviceTracker_track(celix_service_tracker_instance_t 
*instance, service_reference_pt reference, celix_service_event_t *event) {
        celix_status_t status = CELIX_SUCCESS;
 
     celix_tracked_entry_t *found = NULL;
     unsigned int i;
     
-    bundleContext_retainServiceReference(tracker->context, reference);
+    bundleContext_retainServiceReference(instance->context, reference);
 
-    celixThreadRwlock_readLock(&tracker->lock);
-    for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
+    celixThreadRwlock_readLock(&instance->lock);
+    for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
         bool equals = false;
-        celix_tracked_entry_t *visit = (celix_tracked_entry_t*) 
arrayList_get(tracker->trackedServices, i);
+        celix_tracked_entry_t *visit = (celix_tracked_entry_t*) 
arrayList_get(instance->trackedServices, i);
         serviceReference_equals(reference, visit->reference, &equals);
         if (equals) {
             found = visit;
@@ -341,15 +462,15 @@ static celix_status_t 
serviceTracker_track(service_tracker_pt tracker, service_r
             break;
         }
     }
-    celixThreadRwlock_unlock(&tracker->lock);
+    celixThreadRwlock_unlock(&instance->lock);
 
     if (found != NULL) {
-        status = serviceTracker_invokeModifiedService(tracker, found);
+        status = serviceTracker_invokeModifiedService(instance, found);
         tracked_retain(found);
     } else if (status == CELIX_SUCCESS && found == NULL) {
         //NEW entry
         void *service = NULL;
-        status = serviceTracker_invokeAddingService(tracker, reference, 
&service);
+        status = serviceTracker_invokeAddingService(instance, reference, 
&service);
         if (status == CELIX_SUCCESS && service != NULL) {
             assert(reference != NULL);
 
@@ -365,12 +486,12 @@ static celix_status_t 
serviceTracker_track(service_tracker_pt tracker, service_r
 
             celix_tracked_entry_t *tracked = tracked_create(reference, 
service, props, bnd);
 
-            celixThreadRwlock_writeLock(&tracker->lock);
-            arrayList_add(tracker->trackedServices, tracked);
-            celixThreadRwlock_unlock(&tracker->lock);
+            celixThreadRwlock_writeLock(&instance->lock);
+            arrayList_add(instance->trackedServices, tracked);
+            celixThreadRwlock_unlock(&instance->lock);
 
-            serviceTracker_invokeAddService(tracker, tracked);
-            celix_serviceTracker_useHighestRankingService(tracker, 
tracked->serviceName, tracker, NULL, NULL, 
serviceTracker_checkAndInvokeSetService);
+            serviceTracker_invokeAddService(instance, tracked);
+            serviceTracker_useHighestRankingServiceInternal(instance, 
tracked->serviceName, instance, NULL, NULL, 
serviceTracker_checkAndInvokeSetService);
         }
     }
 
@@ -380,7 +501,7 @@ static celix_status_t 
serviceTracker_track(service_tracker_pt tracker, service_r
 }
 
 static void serviceTracker_checkAndInvokeSetService(void *handle, void 
*highestSvc, const celix_properties_t *props, const celix_bundle_t *bnd) {
-    celix_service_tracker_t *tracker = handle;
+    celix_service_tracker_instance_t *instance = handle;
     bool update = false;
     long svcId = -1;
     if (highestSvc == NULL) {
@@ -390,100 +511,96 @@ static void serviceTracker_checkAndInvokeSetService(void 
*handle, void *highestS
         svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, 
-1);
     }
     if (svcId > 0) {
-        celixThreadMutex_lock(&tracker->mutex);
-        if (tracker->currentHighestServiceId != svcId) {
-            tracker->currentHighestServiceId = svcId;
+        celixThreadMutex_lock(&instance->mutex);
+        if (instance->currentHighestServiceId != svcId) {
+            instance->currentHighestServiceId = svcId;
             update = true;
             //update
         }
-        celixThreadMutex_unlock(&tracker->mutex);
+        celixThreadMutex_unlock(&instance->mutex);
     }
     if (update) {
-        void *h = tracker->callbackHandle;
-        if (tracker->set != NULL) {
-            tracker->set(h, highestSvc);
+        void *h = instance->callbackHandle;
+        if (instance->set != NULL) {
+            instance->set(h, highestSvc);
         }
-        if (tracker->setWithProperties != NULL) {
-            tracker->setWithProperties(h, highestSvc, props);
+        if (instance->setWithProperties != NULL) {
+            instance->setWithProperties(h, highestSvc, props);
         }
-        if (tracker->setWithOwner != NULL) {
-            tracker->setWithOwner(h, highestSvc, props, bnd);
+        if (instance->setWithOwner != NULL) {
+            instance->setWithOwner(h, highestSvc, props, bnd);
         }
     }
 }
 
-static celix_status_t serviceTracker_invokeModifiedService(service_tracker_pt 
tracker, celix_tracked_entry_t *tracked) {
+static celix_status_t 
serviceTracker_invokeModifiedService(celix_service_tracker_instance_t 
*instance, celix_tracked_entry_t *tracked) {
     celix_status_t status = CELIX_SUCCESS;
-    if (tracker->customizer != NULL) {
+    if (&instance->customizer != NULL) {
         void *handle = NULL;
         modified_callback_pt function = NULL;
 
-        serviceTrackerCustomizer_getHandle(tracker->customizer, &handle);
-        serviceTrackerCustomizer_getModifiedFunction(tracker->customizer, 
&function);
+        serviceTrackerCustomizer_getHandle(&instance->customizer, &handle);
+        serviceTrackerCustomizer_getModifiedFunction(&instance->customizer, 
&function);
 
         if (function != NULL) {
             function(handle, tracked->reference, tracked->service);
         }
     }
-    void *handle = tracker->callbackHandle;
-    if (tracker->modified != NULL) {
-        tracker->modified(handle, tracked->service);
+    void *handle = instance->callbackHandle;
+    if (instance->modified != NULL) {
+        instance->modified(handle, tracked->service);
     }
-    if (tracker->modifiedWithProperties != NULL) {
-        tracker->modifiedWithProperties(handle, tracked->service, 
tracked->properties);
+    if (instance->modifiedWithProperties != NULL) {
+        instance->modifiedWithProperties(handle, tracked->service, 
tracked->properties);
     }
-    if (tracker->modifiedWithOwner != NULL) {
-        tracker->modifiedWithOwner(handle, tracked->service, 
tracked->properties, tracked->serviceOwner);
+    if (instance->modifiedWithOwner != NULL) {
+        instance->modifiedWithOwner(handle, tracked->service, 
tracked->properties, tracked->serviceOwner);
     }
     return status;
 }
 
 
-static celix_status_t serviceTracker_invokeAddService(service_tracker_pt 
tracker, celix_tracked_entry_t *tracked) {
+static celix_status_t 
serviceTracker_invokeAddService(celix_service_tracker_instance_t *instance, 
celix_tracked_entry_t *tracked) {
     celix_status_t status = CELIX_SUCCESS;
-    if (tracker->customizer != NULL) {
-        void *handle = NULL;
-        added_callback_pt function = NULL;
 
-        serviceTrackerCustomizer_getHandle(tracker->customizer, &handle);
-        serviceTrackerCustomizer_getAddedFunction(tracker->customizer, 
&function);
-        if (function != NULL) {
-            function(handle, tracked->reference, tracked->service);
-        }
+    void *customizerHandle = NULL;
+    added_callback_pt function = NULL;
+
+    serviceTrackerCustomizer_getHandle(&instance->customizer, 
&customizerHandle);
+    serviceTrackerCustomizer_getAddedFunction(&instance->customizer, 
&function);
+    if (function != NULL) {
+        function(customizerHandle, tracked->reference, tracked->service);
     }
-    void *handle = tracker->callbackHandle;
-    if (tracker->add != NULL) {
-        tracker->add(handle, tracked->service);
+
+    void *handle = instance->callbackHandle;
+    if (instance->add != NULL) {
+        instance->add(handle, tracked->service);
     }
-    if (tracker->addWithProperties != NULL) {
-        tracker->addWithProperties(handle, tracked->service, 
tracked->properties);
+    if (instance->addWithProperties != NULL) {
+        instance->addWithProperties(handle, tracked->service, 
tracked->properties);
     }
-    if (tracker->addWithOwner != NULL) {
-        tracker->addWithOwner(handle, tracked->service, tracked->properties, 
tracked->serviceOwner);
+    if (instance->addWithOwner != NULL) {
+        instance->addWithOwner(handle, tracked->service, tracked->properties, 
tracked->serviceOwner);
     }
     return status;
 }
 
-static celix_status_t 
serviceTracker_invokeAddingService(celix_service_tracker_t *tracker, 
service_reference_pt ref, void **svcOut) {
+static celix_status_t 
serviceTracker_invokeAddingService(celix_service_tracker_instance_t *instance, 
service_reference_pt ref, void **svcOut) {
        celix_status_t status = CELIX_SUCCESS;
 
-    if (tracker->customizer != NULL) {
-        void *handle = NULL;
-        adding_callback_pt function = NULL;
+    void *handle = NULL;
+    adding_callback_pt function = NULL;
 
-        status = serviceTrackerCustomizer_getHandle(tracker->customizer, 
&handle);
+    status = serviceTrackerCustomizer_getHandle(&instance->customizer, 
&handle);
 
-        if (status == CELIX_SUCCESS) {
-            status = 
serviceTrackerCustomizer_getAddingFunction(tracker->customizer, &function);
-        }
+    if (status == CELIX_SUCCESS) {
+        status = 
serviceTrackerCustomizer_getAddingFunction(&instance->customizer, &function);
+    }
 
-        if (status == CELIX_SUCCESS && function != NULL) {
-            status = function(handle, ref, svcOut);
-        } else if (status == CELIX_SUCCESS) {
-            status = bundleContext_getService(tracker->context, ref, svcOut);
-        }
-    } else {
-        status = bundleContext_getService(tracker->context, ref, svcOut);
+    if (status == CELIX_SUCCESS && function != NULL) {
+        status = function(handle, ref, svcOut);
+    } else if (status == CELIX_SUCCESS) {
+        status = bundleContext_getService(instance->context, ref, svcOut);
     }
 
     framework_logIfError(logger, status, NULL, "Cannot handle addingService");
@@ -491,47 +608,47 @@ static celix_status_t 
serviceTracker_invokeAddingService(celix_service_tracker_t
     return status;
 }
 
-static celix_status_t serviceTracker_untrack(service_tracker_pt tracker, 
service_reference_pt reference, celix_service_event_t *event) {
+static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t* 
instance, service_reference_pt reference, celix_service_event_t *event) {
     celix_status_t status = CELIX_SUCCESS;
     celix_tracked_entry_t *remove = NULL;
     unsigned int i;
     unsigned int size;
     const char *serviceName = NULL;
 
-    celixThreadRwlock_writeLock(&tracker->lock);
-    size = arrayList_size(tracker->trackedServices);
+    celixThreadRwlock_writeLock(&instance->lock);
+    size = arrayList_size(instance->trackedServices);
     for (i = 0; i < size; i++) {
         bool equals;
-        celix_tracked_entry_t *tracked = (celix_tracked_entry_t*) 
arrayList_get(tracker->trackedServices, i);
+        celix_tracked_entry_t *tracked = (celix_tracked_entry_t*) 
arrayList_get(instance->trackedServices, i);
         serviceName = tracked->serviceName;
         serviceReference_equals(reference, tracked->reference, &equals);
         if (equals) {
             remove = tracked;
             //remove from trackedServices to prevent getting this service, but 
don't destroy yet, can be in use
-            arrayList_remove(tracker->trackedServices, i);
+            arrayList_remove(instance->trackedServices, i);
             break;
         }
     }
-    size = arrayList_size(tracker->trackedServices); //updated size
-    celixThreadRwlock_unlock(&tracker->lock);
+    size = arrayList_size(instance->trackedServices); //updated size
+    celixThreadRwlock_unlock(&instance->lock);
 
     if (size == 0) {
-        serviceTracker_checkAndInvokeSetService(tracker, NULL, NULL, NULL);
+        serviceTracker_checkAndInvokeSetService(instance, NULL, NULL, NULL);
     } else {
-        celix_serviceTracker_useHighestRankingService(tracker, serviceName, 
tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+        serviceTracker_useHighestRankingServiceInternal(instance, serviceName, 
instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
     }
 
-    serviceTracker_untrackTracked(tracker, remove);
+    serviceTracker_untrackTracked(instance, remove);
 
     framework_logIfError(logger, status, NULL, "Cannot untrack reference");
 
     return status;
 }
 
-static void serviceTracker_untrackTracked(celix_service_tracker_t *tracker, 
celix_tracked_entry_t *tracked) {
+static void serviceTracker_untrackTracked(celix_service_tracker_instance_t 
*instance, celix_tracked_entry_t *tracked) {
     if (tracked != NULL) {
-        serviceTracker_invokeRemovingService(tracker, tracked);
-        bundleContext_ungetServiceReference(tracker->context, 
tracked->reference);
+        serviceTracker_invokeRemovingService(instance, tracked);
+        bundleContext_ungetServiceReference(instance->context, 
tracked->reference);
         tracked_release(tracked);
 
         //Wait till the useCount is 0, because the untrack should only return 
if the service is not used anymore.
@@ -539,34 +656,33 @@ static void 
serviceTracker_untrackTracked(celix_service_tracker_t *tracker, celi
     }
 }
 
-static celix_status_t serviceTracker_invokeRemovingService(service_tracker_pt 
tracker, celix_tracked_entry_t *tracked) {
+static celix_status_t 
serviceTracker_invokeRemovingService(celix_service_tracker_instance_t 
*instance, celix_tracked_entry_t *tracked) {
     celix_status_t status = CELIX_SUCCESS;
     bool ungetSuccess = true;
-    if (tracker->customizer != NULL) {
-        void *handle = NULL;
-        removed_callback_pt function = NULL;
 
-        serviceTrackerCustomizer_getHandle(tracker->customizer, &handle);
-        serviceTrackerCustomizer_getRemovedFunction(tracker->customizer, 
&function);
+    void *customizerHandle = NULL;
+    removed_callback_pt function = NULL;
 
-        if (function != NULL) {
-            status = function(handle, tracked->reference, tracked->service);
-        }
+    serviceTrackerCustomizer_getHandle(&instance->customizer, 
&customizerHandle);
+    serviceTrackerCustomizer_getRemovedFunction(&instance->customizer, 
&function);
+
+    if (function != NULL) {
+        status = function(customizerHandle, tracked->reference, 
tracked->service);
     }
 
-    void *handle = tracker->callbackHandle;
-    if (tracker->remove != NULL) {
-        tracker->remove(handle, tracked->service);
+    void *handle = instance->callbackHandle;
+    if (instance->remove != NULL) {
+        instance->remove(handle, tracked->service);
     }
-    if (tracker->addWithProperties != NULL) {
-        tracker->removeWithProperties(handle, tracked->service, 
tracked->properties);
+    if (instance->addWithProperties != NULL) {
+        instance->removeWithProperties(handle, tracked->service, 
tracked->properties);
     }
-    if (tracker->removeWithOwner != NULL) {
-        tracker->removeWithOwner(handle, tracked->service, 
tracked->properties, tracked->serviceOwner);
+    if (instance->removeWithOwner != NULL) {
+        instance->removeWithOwner(handle, tracked->service, 
tracked->properties, tracked->serviceOwner);
     }
 
     if (status == CELIX_SUCCESS) {
-        status = bundleContext_ungetService(tracker->context, 
tracked->reference, &ungetSuccess);
+        status = bundleContext_ungetService(instance->context, 
tracked->reference, &ungetSuccess);
     }
 
     if (!ungetSuccess) {
@@ -606,9 +722,6 @@ celix_service_tracker_t* 
celix_serviceTracker_createWithOptions(
         tracker = calloc(1, sizeof(*tracker));
         if (tracker != NULL) {
             tracker->context = ctx;
-            celixThreadRwlock_create(&tracker->lock, NULL);
-            tracker->trackedServices = celix_arrayList_create();
-            tracker->listener = NULL;
 
             //setting callbacks
             tracker->callbackHandle = opts->callbackHandle;
@@ -622,9 +735,7 @@ celix_service_tracker_t* 
celix_serviceTracker_createWithOptions(
             tracker->addWithOwner = opts->addWithOwner;
             tracker->removeWithOwner = opts->removeWithOwner;
 
-            //highest service state
-            celixThreadMutex_create(&tracker->mutex, NULL);
-            tracker->currentHighestServiceId = -1;
+            celixThreadRwlock_create(&tracker->instanceLock, NULL);
 
             //setting lang
             const char *lang = opts->filter.serviceLanguage;
@@ -666,14 +777,12 @@ void celix_serviceTracker_destroy(celix_service_tracker_t 
*tracker) {
     }
 }
 
-
-bool celix_serviceTracker_useHighestRankingService(
-        celix_service_tracker_t *tracker,
-        const char *serviceName /*sanity*/,
-        void *callbackHandle,
-        void (*use)(void *handle, void *svc),
-        void (*useWithProperties)(void *handle, void *svc, const 
celix_properties_t *props),
-        void (*useWithOwner)(void *handle, void *svc, const celix_properties_t 
*props, const celix_bundle_t *owner)) {
+static bool 
serviceTracker_useHighestRankingServiceInternal(celix_service_tracker_instance_t
 *instance,
+                                                            const char 
*serviceName /*sanity*/,
+                                                            void 
*callbackHandle,
+                                                            void (*use)(void 
*handle, void *svc),
+                                                            void 
(*useWithProperties)(void *handle, void *svc, const celix_properties_t *props),
+                                                            void 
(*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const 
celix_bundle_t *owner)) {
     bool called = false;
     celix_tracked_entry_t *tracked = NULL;
     celix_tracked_entry_t *highest = NULL;
@@ -681,9 +790,9 @@ bool celix_serviceTracker_useHighestRankingService(
     unsigned int i;
 
     //first lock tracker and get highest tracked entry
-    celixThreadRwlock_readLock(&tracker->lock);
-    for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
-        tracked = (celix_tracked_entry_t *) 
arrayList_get(tracker->trackedServices, i);
+    celixThreadRwlock_readLock(&instance->lock);
+    for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+        tracked = (celix_tracked_entry_t *) 
arrayList_get(instance->trackedServices, i);
         if (serviceName != NULL && tracked->serviceName != NULL && 
strncmp(tracked->serviceName, serviceName, 10*1024) == 0) {
             const char *val = properties_getWithDefault(tracked->properties, 
OSGI_FRAMEWORK_SERVICE_RANKING, "0");
             long rank = strtol(val, NULL, 10);
@@ -697,7 +806,7 @@ bool celix_serviceTracker_useHighestRankingService(
         tracked_retain(highest);
     }
     //unlock tracker so that the tracked entry can be removed from the 
trackedServices list if unregistered.
-    celixThreadRwlock_unlock(&tracker->lock);
+    celixThreadRwlock_unlock(&instance->lock);
 
     if (highest != NULL) {
         //got service, call, decrease use count an signal useCond after.
@@ -717,6 +826,25 @@ bool celix_serviceTracker_useHighestRankingService(
     return called;
 }
 
+
+bool celix_serviceTracker_useHighestRankingService(
+        celix_service_tracker_t *tracker,
+        const char *serviceName /*sanity*/,
+        void *callbackHandle,
+        void (*use)(void *handle, void *svc),
+        void (*useWithProperties)(void *handle, void *svc, const 
celix_properties_t *props),
+        void (*useWithOwner)(void *handle, void *svc, const celix_properties_t 
*props, const celix_bundle_t *owner)) {
+    celixThreadRwlock_readLock(&tracker->instanceLock);
+    celix_service_tracker_instance_t *instance = tracker->instance;
+    bool called = false;
+    if (instance != NULL) {
+        called = serviceTracker_useHighestRankingServiceInternal(instance, 
serviceName, callbackHandle, use,
+                                                                 
useWithProperties, useWithOwner);
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
+    return called;
+}
+
 void celix_serviceTracker_useServices(
         service_tracker_t *tracker,
         const char* serviceName /*sanity*/,
@@ -726,32 +854,119 @@ void celix_serviceTracker_useServices(
         void (*useWithOwner)(void *handle, void *svc, const celix_properties_t 
*props, const celix_bundle_t *owner)) {
     int i;
 
-    //first lock tracker, get tracked entries and increase use count
-    celixThreadRwlock_readLock(&tracker->lock);
-    size_t size = celix_arrayList_size(tracker->trackedServices);
-    celix_tracked_entry_t* entries[size];
-    for (i = 0; i < size; i++) {
-        celix_tracked_entry_t *tracked = (celix_tracked_entry_t *) 
arrayList_get(tracker->trackedServices, i);
-        tracked_retain(tracked);
-        entries[i] = tracked;
+    celixThreadRwlock_readLock(&tracker->instanceLock);
+    celix_service_tracker_instance_t *instance = tracker->instance;
+    if (instance != NULL) {
+        //first lock tracker, get tracked entries and increase use count
+        celixThreadRwlock_readLock(&instance->lock);
+        size_t size = celix_arrayList_size(instance->trackedServices);
+        celix_tracked_entry_t *entries[size];
+        for (i = 0; i < size; i++) {
+            celix_tracked_entry_t *tracked = (celix_tracked_entry_t *) 
arrayList_get(instance->trackedServices, i);
+            tracked_retain(tracked);
+            entries[i] = tracked;
+        }
+        //unlock tracker so that the tracked entry can be removed from the 
trackedServices list if unregistered.
+        celixThreadRwlock_unlock(&instance->lock);
+
+        //then use entries and decrease use count
+        for (i = 0; i < size; i++) {
+            celix_tracked_entry_t *entry = entries[i];
+            //got service, call, decrease use count an signal useCond after.
+            if (use != NULL) {
+                use(callbackHandle, entry->service);
+            }
+            if (useWithProperties != NULL) {
+                useWithProperties(callbackHandle, entry->service, 
entry->properties);
+            }
+            if (useWithOwner != NULL) {
+                useWithOwner(callbackHandle, entry->service, 
entry->properties, entry->serviceOwner);
+            }
+
+            tracked_release(entry);
+        }
     }
-    //unlock tracker so that the tracked entry can be removed from the 
trackedServices list if unregistered.
-    celixThreadRwlock_unlock(&tracker->lock);
+    celixThreadRwlock_unlock(&tracker->instanceLock);
+}
 
-    //then use entries and decrease use count
-    for (i = 0; i < size; i++) {
-        celix_tracked_entry_t *entry = entries[i];
-        //got service, call, decrease use count an signal useCond after.
-        if (use != NULL) {
-            use(callbackHandle, entry->service);
+void celix_serviceTracker_syncForFramework(void *fw) {
+    celixThread_once(&g_once, serviceTracker_once);
+    celixThreadMutex_lock(&g_mutex);
+    size_t count = 0;
+    do {
+        count = 0;
+        if (g_shutdownInstances != NULL) {
+            for (int i = 0; i < celix_arrayList_size(g_shutdownInstances); 
++i) {
+                celix_service_tracker_instance_t *instance = 
celix_arrayList_get(g_shutdownInstances, i);
+                if (instance->context->framework == fw) {
+                    count += 1;
+                }
+            }
         }
-        if (useWithProperties != NULL) {
-            useWithProperties(callbackHandle, entry->service, 
entry->properties);
+        if (count > 0) {
+            pthread_cond_wait(&g_cond, &g_mutex);
         }
-        if (useWithOwner != NULL) {
-            useWithOwner(callbackHandle, entry->service, entry->properties, 
entry->serviceOwner);
+    } while (count > 0);
+
+    if (g_shutdownInstances != NULL && 
celix_arrayList_size(g_shutdownInstances) == 0) {
+        celix_arrayList_destroy(g_shutdownInstances);
+        g_shutdownInstances = NULL;
+    }
+    celixThreadMutex_unlock(&g_mutex);
+}
+
+void celix_serviceTracker_syncForContext(void *ctx) {
+    celixThread_once(&g_once, serviceTracker_once);
+    celixThreadMutex_lock(&g_mutex);
+    size_t count;
+    do {
+        count = 0;
+        if (g_shutdownInstances != NULL) {
+            for (int i = 0; i < celix_arrayList_size(g_shutdownInstances); 
++i) {
+                celix_service_tracker_instance_t *instance = 
celix_arrayList_get(g_shutdownInstances, i);
+                if (instance->context == ctx) {
+                    count += 1;
+                }
+            }
+        }
+        if (count > 0) {
+            pthread_cond_wait(&g_cond, &g_mutex);
         }
+    } while (count > 0);
 
-        tracked_release(entry);
+    if (g_shutdownInstances != NULL && 
celix_arrayList_size(g_shutdownInstances) == 0) {
+        celix_arrayList_destroy(g_shutdownInstances);
+        g_shutdownInstances = NULL;
+    }
+    celixThreadMutex_unlock(&g_mutex);
+}
+
+static void 
serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t 
*instance) {
+    celixThread_once(&g_once, serviceTracker_once);
+    celixThreadMutex_lock(&g_mutex);
+    if (g_shutdownInstances == NULL) {
+        g_shutdownInstances = celix_arrayList_create();
+    }
+    celix_arrayList_add(g_shutdownInstances, instance);
+    celixThreadMutex_unlock(&g_mutex);
+}
+
+static void 
serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t 
*instance) {
+    celixThread_once(&g_once, serviceTracker_once);
+    celixThreadMutex_lock(&g_mutex);
+    if (g_shutdownInstances != NULL) {
+        size_t size = celix_arrayList_size(g_shutdownInstances);
+        for (size_t i = 0; i < size; ++i) {
+            celix_array_list_entry_t entry;
+            memset(&entry, 0, sizeof(entry));
+            entry.voidPtrVal = instance;
+            celix_arrayList_removeEntry(g_shutdownInstances, entry);
+        }
+        if (celix_arrayList_size(g_shutdownInstances) == 0) {
+            celix_arrayList_destroy(g_shutdownInstances);
+            g_shutdownInstances = NULL;
+        }
+        celixThreadCondition_broadcast(&g_cond);
     }
+    celixThreadMutex_unlock(&g_mutex);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/src/service_tracker_customizer.c
----------------------------------------------------------------------
diff --git a/libs/framework/src/service_tracker_customizer.c 
b/libs/framework/src/service_tracker_customizer.c
index b62a23a..d4763cb 100644
--- a/libs/framework/src/service_tracker_customizer.c
+++ b/libs/framework/src/service_tracker_customizer.c
@@ -25,8 +25,8 @@
  */
 
 #include <stdlib.h>
+#include "service_tracker_customizer.h"
 
-#include "service_tracker_customizer_private.h"
 #include "celix_log.h"
 
 celix_status_t serviceTrackerCustomizer_create(void *handle,

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/src/service_tracker_customizer_private.h
----------------------------------------------------------------------
diff --git a/libs/framework/src/service_tracker_customizer_private.h 
b/libs/framework/src/service_tracker_customizer_private.h
deleted file mode 100644
index 61fb52f..0000000
--- a/libs/framework/src/service_tracker_customizer_private.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- *Licensed to the Apache Software Foundation (ASF) under one
- *or more contributor license agreements.  See the NOTICE file
- *distributed with this work for additional information
- *regarding copyright ownership.  The ASF licenses this file
- *to you under the Apache License, Version 2.0 (the
- *"License"); you may not use this file except in compliance
- *with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *Unless required by applicable law or agreed to in writing,
- *software distributed under the License is distributed on an
- *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- *specific language governing permissions and limitations
- *under the License.
- */
-/*
- * service_tracker_customizer_private.h
- *
- *  \date       Feb 7, 2013
- *  \author     <a href="mailto:[email protected]";>Apache Celix Project 
Team</a>
- *  \copyright  Apache License, Version 2.0
- */
-
-
-#ifndef SERVICE_TRACKER_CUSTOMIZER_PRIVATE_H_
-#define SERVICE_TRACKER_CUSTOMIZER_PRIVATE_H_
-
-#include "service_reference.h"
-
-#include "service_tracker_customizer.h"
-
-
-struct serviceTrackerCustomizer {
-       void * handle;
-       celix_status_t (*addingService)(void * handle, service_reference_pt 
reference, void **service);
-       celix_status_t (*addedService)(void * handle, service_reference_pt 
reference, void * service);
-       celix_status_t (*modifiedService)(void * handle, service_reference_pt 
reference, void * service);
-
-       /*TODO rename to removingService. because it is invoke during remove 
not after!*/
-       celix_status_t (*removedService)(void * handle, service_reference_pt 
reference, void * service);
-
-       /*TODO add removed function ? invoked after the remove ?? */
-};
-
-
-#endif /* SERVICE_TRACKER_CUSTOMIZER_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/src/service_tracker_private.h
----------------------------------------------------------------------
diff --git a/libs/framework/src/service_tracker_private.h 
b/libs/framework/src/service_tracker_private.h
index d772dc1..171b1a4 100644
--- a/libs/framework/src/service_tracker_private.h
+++ b/libs/framework/src/service_tracker_private.h
@@ -29,13 +29,20 @@
 #define SERVICE_TRACKER_PRIVATE_H_
 
 #include "service_tracker.h"
+#include "celix_types.h"
+
+//instance for an active per open statement and removed per close statement
+typedef struct celix_service_tracker_instance {
+       celix_thread_mutex_t closingLock; //projects closing and 
activeServiceChangeCalls
+       bool closing; //when true the service tracker instance is being closed 
and all calls from the service listener are ignored
+       size_t activeServiceChangeCalls;
+       celix_thread_cond_t activeServiceChangeCallsCond;
 
-struct celix_serviceTracker {
        bundle_context_t *context;
        char * filter;
 
-       service_tracker_customizer_t *customizer;
-       celix_service_listener_t *listener;
+       service_tracker_customizer_t customizer;
+       celix_service_listener_t listener;
 
        void *callbackHandle;
 
@@ -59,9 +66,39 @@ struct celix_serviceTracker {
 
        celix_thread_mutex_t mutex; //protect current highest service id
        long currentHighestServiceId;
+
+       celix_thread_t shutdownThread; //will be created when this instance is 
shutdown
+} celix_service_tracker_instance_t;
+
+struct celix_serviceTracker {
+       bundle_context_t *context;
+
+       char * filter;
+       service_tracker_customizer_t *customizer;
+
+       void *callbackHandle;
+
+       void (*set)(void *handle, void *svc); //highest ranking
+       void (*add)(void *handle, void *svc);
+       void (*remove)(void *handle, void *svc);
+       void (*modified)(void *handle, void *svc);
+
+       void (*setWithProperties)(void *handle, void *svc, const properties_t 
*props); //highest ranking
+       void (*addWithProperties)(void *handle, void *svc, const properties_t 
*props);
+       void (*removeWithProperties)(void *handle, void *svc, const 
properties_t *props);
+       void (*modifiedWithProperties)(void *handle, void *svc, const 
properties_t *props);
+
+       void (*setWithOwner)(void *handle, void *svc, const properties_t 
*props, const bundle_t *owner); //highest ranking
+       void (*addWithOwner)(void *handle, void *svc, const properties_t 
*props, const bundle_t *owner);
+       void (*removeWithOwner)(void *handle, void *svc, const properties_t 
*props, const bundle_t *owner);
+       void (*modifiedWithOwner)(void *handle, void *svc, const properties_t 
*props, const bundle_t *owner);
+
+       celix_thread_rwlock_t instanceLock;
+       celix_service_tracker_instance_t *instance; /*NULL -> close, 
!NULL->open*/
+
 };
 
-struct celix_tracked_entry {
+typedef struct celix_tracked_entry {
        service_reference_pt reference;
        void *service;
        const char *serviceName;
@@ -71,8 +108,7 @@ struct celix_tracked_entry {
     celix_thread_mutex_t mutex; //protects useCount
        celix_thread_cond_t useCond;
     size_t useCount;
-};
+} celix_tracked_entry_t;
 
-typedef struct celix_tracked_entry celix_tracked_entry_t;
 
 #endif /* SERVICE_TRACKER_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/tst/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/libs/framework/tst/CMakeLists.txt 
b/libs/framework/tst/CMakeLists.txt
index 014eb2a..38d0ed8 100644
--- a/libs/framework/tst/CMakeLists.txt
+++ b/libs/framework/tst/CMakeLists.txt
@@ -29,6 +29,7 @@ add_executable(test_framework
 )
 target_link_libraries(test_framework Celix::framework ${CURL_LIBRARIES} 
${CPPUTEST_LIBRARY})
 add_dependencies(test_framework simple_test_bundle1_bundle 
simple_test_bundle2_bundle simple_test_bundle3_bundle)
+target_include_directories(test_framework PRIVATE ../src)
 
 configure_file(config.properties.in config.properties @ONLY)
 configure_file(framework1.properties.in framework1.properties @ONLY)

http://git-wip-us.apache.org/repos/asf/celix/blob/bcda87f5/libs/framework/tst/bundle_context_services_test.cpp
----------------------------------------------------------------------
diff --git a/libs/framework/tst/bundle_context_services_test.cpp 
b/libs/framework/tst/bundle_context_services_test.cpp
index 5e1792a..892fab4 100644
--- a/libs/framework/tst/bundle_context_services_test.cpp
+++ b/libs/framework/tst/bundle_context_services_test.cpp
@@ -28,6 +28,7 @@
 #include "celix_api.h"
 #include "celix_framework_factory.h"
 #include "celix_service_factory.h"
+#include "service_tracker_private.h"
 
 
 #include <CppUTest/TestHarness.h>
@@ -684,8 +685,10 @@ TEST(CelixBundleContextServicesTests, 
trackServiceTrackerTest) {
     CHECK_EQUAL(2, count);
 
     celix_bundleContext_stopTracker(ctx, tracker2);
+    celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on 
separate track -> need sync
     CHECK_EQUAL(1, count);
     celix_bundleContext_stopTracker(ctx, tracker3);
+    celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on 
separate track -> need sync
     CHECK_EQUAL(0, count);
 
     celix_bundleContext_stopTracker(ctx, trackerId);

Reply via email to