celix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pnol...@apache.org
Subject celix git commit: CELIX-452: Changes the behaviour of the serviceTracker_close, so that removing the service listener is done on a separate thread.
Date Tue, 17 Jul 2018 19:41:43 GMT
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 <pepijnnoltes@gmail.com>
Authored: Tue Jul 17 21:25:26 2018 +0200
Committer: Pepijn Noltes <pepijnnoltes@gmail.com>
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:dev@celix.apache.org">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);


Mime
View raw message