You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2020/03/08 20:08:12 UTC

[celix] branch feature/framework_racecondition created (now f4671e0)

This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a change to branch feature/framework_racecondition
in repository https://gitbox.apache.org/repos/asf/celix.git.


      at f4671e0  Refactors the handling of service listeners. This is moved to the service registry and the service listener is now retroactively creating events.

This branch includes the following new commits:

     new aad0ecd  Refactors some celix framework test from cpputest to gtest.
     new f4671e0  Refactors the handling of service listeners. This is moved to the service registry and the service listener is now retroactively creating events.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[celix] 02/02: Refactors the handling of service listeners. This is moved to the service registry and the service listener is now retroactively creating events.

Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/framework_racecondition
in repository https://gitbox.apache.org/repos/asf/celix.git

commit f4671e0fa3a00da28bc1279a9375677b0ade2615
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Mar 8 21:07:45 2020 +0100

    Refactors the handling of service listeners. This is moved to the service registry and the service listener is now retroactively creating events.
    
    This is done because there was a race condition in the service trackers when adding service listener and getting a list of already registered services.
    This was done with two calls and as result introduced a race condition.
    Because the service listeners are changed in behaviour (now retroactively), the direct use if also  deprecated; use the service tracker instead.
---
 .../example/refining_driver/CMakeLists.txt         |   2 +
 .../example/refining_driver/src/refining_driver.c  |   4 +-
 .../topology_manager/CMakeLists.txt                |   1 -
 .../topology_manager/src/activator.c               |  72 ++--
 .../topology_manager/src/topology_manager.c        | 168 +++-----
 .../topology_manager/src/topology_manager.h        |   4 +-
 libs/framework/CMakeLists.txt                      |   2 +
 .../gtest/src/bundle_context_services_test.cpp     |  80 ++--
 libs/framework/include/bundle_context.h            |   2 +-
 libs/framework/include/celix_bundle_context.h      |   6 +-
 libs/framework/include/service_reference.h         |   3 +
 libs/framework/include/service_registry.h          |  15 +-
 libs/framework/include/service_tracker.h           |   5 +-
 libs/framework/private/mock/bundle_context_mock.c  |   3 +-
 .../private/mock/service_reference_mock.c          |   6 +
 .../framework/private/mock/service_registry_mock.c |  22 +-
 .../private/test/service_registration_test.cpp     |  24 --
 .../private/test/service_registry_test.cpp         | 161 +++-----
 libs/framework/src/bundle.c                        |   8 +-
 libs/framework/src/bundle_context.c                |  13 +-
 libs/framework/src/framework.c                     | 282 +------------
 libs/framework/src/framework_private.h             |   3 -
 libs/framework/src/registry_callback_private.h     |   1 -
 libs/framework/src/service_reference.c             |  12 +
 libs/framework/src/service_registration.c          |   9 -
 libs/framework/src/service_registration_private.h  |   8 +-
 libs/framework/src/service_registry.c              | 439 +++++++++++++++++----
 libs/framework/src/service_registry_private.h      |  38 +-
 libs/framework/src/service_tracker.c               | 168 +++-----
 29 files changed, 737 insertions(+), 824 deletions(-)

diff --git a/bundles/device_access/example/refining_driver/CMakeLists.txt b/bundles/device_access/example/refining_driver/CMakeLists.txt
index ba0469c..5f55828 100644
--- a/bundles/device_access/example/refining_driver/CMakeLists.txt
+++ b/bundles/device_access/example/refining_driver/CMakeLists.txt
@@ -27,3 +27,5 @@ add_celix_bundle(char_refiningdriver
 target_include_directories(char_refiningdriver PRIVATE src)
 target_include_directories(char_refiningdriver PUBLIC include)
 target_link_libraries(char_refiningdriver PRIVATE Celix::device_access_api base_driver)
+target_compile_options(char_refiningdriver PRIVATE -Wno-deprecated-declarations) #char_refiningdriver still uses service listeners, refactor this
+
diff --git a/bundles/device_access/example/refining_driver/src/refining_driver.c b/bundles/device_access/example/refining_driver/src/refining_driver.c
index cafcd63..0af416d 100644
--- a/bundles/device_access/example/refining_driver/src/refining_driver.c
+++ b/bundles/device_access/example/refining_driver/src/refining_driver.c
@@ -110,9 +110,9 @@ static celix_status_t refiningDriver_stopDevice(refining_driver_device_pt device
 }
 
 
-static celix_status_t refiningDriver_serviceChanged(celix_service_listener_t *listener, celix_service_event_t *event) {
+static celix_status_t refiningDriver_serviceChanged(void *handle, celix_service_event_t *event) {
 	celix_status_t status =  CELIX_SUCCESS;
-	refining_driver_device_pt device = listener->handle;
+	refining_driver_device_pt device = handle;
 	if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
 		bool equal = false;
 		status = serviceReference_equals(device->baseServiceReference, event->reference, &equal);
diff --git a/bundles/remote_services/topology_manager/CMakeLists.txt b/bundles/remote_services/topology_manager/CMakeLists.txt
index 189d2a1..ad4c574 100644
--- a/bundles/remote_services/topology_manager/CMakeLists.txt
+++ b/bundles/remote_services/topology_manager/CMakeLists.txt
@@ -31,7 +31,6 @@ if (RSA_TOPOLOGY_MANAGER)
     target_include_directories(rsa_topology_manager PRIVATE include)
     target_link_libraries(rsa_topology_manager PRIVATE Celix::log_helper Celix::rsa_spi)
 
-
     if (ENABLE_TESTING)
         find_package(CppUTest REQUIRED)
 	    find_package(Jansson REQUIRED)
diff --git a/bundles/remote_services/topology_manager/src/activator.c b/bundles/remote_services/topology_manager/src/activator.c
index 4a4a6df..4aa28f1 100644
--- a/bundles/remote_services/topology_manager/src/activator.c
+++ b/bundles/remote_services/topology_manager/src/activator.c
@@ -50,7 +50,7 @@ struct activator {
 
 	service_tracker_t *endpointListenerTracker;
 	service_tracker_t *remoteServiceAdminTracker;
-	celix_service_listener_t *serviceListener;
+	service_tracker_t *exportedServicesTracker;
 
 	endpoint_listener_t *endpointListener;
 	service_registration_t *endpointListenerService;
@@ -67,7 +67,7 @@ struct activator {
 
 static celix_status_t bundleActivator_createEPLTracker(struct activator *activator, service_tracker_t **tracker);
 static celix_status_t bundleActivator_createRSATracker(struct activator *activator, service_tracker_t **tracker);
-static celix_status_t bundleActivator_createServiceListener(struct activator *activator, celix_service_listener_t **listener);
+static celix_status_t bundleActivator_createExportedServicesTracker(struct activator *activator, service_tracker_t **tracker);
 
 celix_status_t bundleActivator_create(celix_bundle_context_t *context, void **userData) {
 	celix_status_t status = CELIX_SUCCESS;
@@ -86,7 +86,7 @@ celix_status_t bundleActivator_create(celix_bundle_context_t *context, void **us
 	activator->hook = NULL;
 	activator->manager = NULL;
 	activator->remoteServiceAdminTracker = NULL;
-	activator->serviceListener = NULL;
+	activator->exportedServicesTracker = NULL;
 	activator->scopeService = calloc(1, sizeof(*(activator->scopeService)));
 	if (activator->scopeService == NULL)
 	{
@@ -111,7 +111,7 @@ celix_status_t bundleActivator_create(celix_bundle_context_t *context, void **us
 		if (status == CELIX_SUCCESS) {
 			status = bundleActivator_createRSATracker(activator, &activator->remoteServiceAdminTracker);
 			if (status == CELIX_SUCCESS) {
-				status = bundleActivator_createServiceListener(activator, &activator->serviceListener);
+				status = bundleActivator_createExportedServicesTracker(activator, &activator->exportedServicesTracker);
 				if (status == CELIX_SUCCESS) {
 					*userData = activator;
 				}
@@ -128,45 +128,33 @@ celix_status_t bundleActivator_create(celix_bundle_context_t *context, void **us
 
 static celix_status_t bundleActivator_createEPLTracker(struct activator *activator, service_tracker_t **tracker) {
 	celix_status_t status;
-
 	service_tracker_customizer_t *customizer = NULL;
-
 	status = serviceTrackerCustomizer_create(activator->manager, topologyManager_endpointListenerAdding, topologyManager_endpointListenerAdded, topologyManager_endpointListenerModified,
 			topologyManager_endpointListenerRemoved, &customizer);
-
 	if (status == CELIX_SUCCESS) {
 		status = serviceTracker_create(activator->context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, customizer, tracker);
 	}
-
 	return status;
 }
 
 static celix_status_t bundleActivator_createRSATracker(struct activator *activator, service_tracker_t **tracker) {
 	celix_status_t status;
-
 	service_tracker_customizer_t *customizer = NULL;
-
 	status = serviceTrackerCustomizer_create(activator->manager, topologyManager_rsaAdding, topologyManager_rsaAdded, topologyManager_rsaModified, topologyManager_rsaRemoved, &customizer);
-
 	if (status == CELIX_SUCCESS) {
 		status = serviceTracker_create(activator->context, OSGI_RSA_REMOTE_SERVICE_ADMIN, customizer, tracker);
 	}
-
 	return status;
 }
 
-static celix_status_t bundleActivator_createServiceListener(struct activator *activator, celix_service_listener_t **listener) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	*listener = malloc(sizeof(**listener));
-	if (!*listener) {
-		return CELIX_ENOMEM;
-	}
-
-	(*listener)->handle = activator->manager;
-	(*listener)->serviceChanged = topologyManager_serviceChanged;
-
-	return status;
+static celix_status_t bundleActivator_createExportedServicesTracker(struct activator *activator, service_tracker_t **tracker) {
+    celix_status_t status;
+    service_tracker_customizer_t *customizer = NULL;
+    status = serviceTrackerCustomizer_create(activator->manager, NULL, topologyManager_addExportedService, NULL, topologyManager_removeExportedService, &customizer);
+    if (status == CELIX_SUCCESS) {
+        status = serviceTracker_createWithFilter(activator->context, "(service.exported.interfaces=*)", customizer, tracker);
+    }
+    return status;
 }
 
 celix_status_t bundleActivator_start(void * userData, celix_bundle_context_t *context) {
@@ -210,30 +198,21 @@ celix_status_t bundleActivator_start(void * userData, celix_bundle_context_t *co
 	hookService->removed = topologyManager_listenerRemoved;
 	activator->hookService = hookService;
 
-	bundleContext_registerService(context, (char *) OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, hookService, NULL, &activator->hook);
-	bundleContext_addServiceListener(context, activator->serviceListener, "(service.exported.interfaces=*)");
-
-	if (status == CELIX_SUCCESS) {
-		serviceTracker_open(activator->remoteServiceAdminTracker);
-	}
+	bundleContext_registerService(context, (char *) TOPOLOGYMANAGER_SCOPE_SERVICE, activator->scopeService, NULL, &activator->scopeReg);
 
-	if (status == CELIX_SUCCESS) {
-		status = serviceTracker_open(activator->endpointListenerTracker);
-	}
+    bundleContext_registerService(context, (char *) OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, hookService, NULL, &activator->hook);
 
-	bundleContext_registerService(context, (char *) TOPOLOGYMANAGER_SCOPE_SERVICE, activator->scopeService, NULL, &activator->scopeReg);
+    if (status == CELIX_SUCCESS) {
+        status = serviceTracker_open(activator->exportedServicesTracker);
+    }
 
-	array_list_pt references = NULL;
-	bundleContext_getServiceReferences(context, NULL, "(service.exported.interfaces=*)", &references);
-	int i;
-	for (i = 0; i < arrayList_size(references); i++) {
-		service_reference_pt reference = arrayList_get(references, i);
-		const char* serviceId = NULL;
-		status = CELIX_DO_IF(status, serviceReference_getProperty(reference, OSGI_FRAMEWORK_SERVICE_ID, &serviceId));
+    if (status == CELIX_SUCCESS) {
+        serviceTracker_open(activator->remoteServiceAdminTracker);
+    }
 
-		CELIX_DO_IF(status, topologyManager_addExportedService(activator->manager, reference, (char*)serviceId));
-	}
-	arrayList_destroy(references);
+    if (status == CELIX_SUCCESS) {
+        status = serviceTracker_open(activator->endpointListenerTracker);
+    }
 
 	return status;
 }
@@ -250,8 +229,9 @@ celix_status_t bundleActivator_stop(void * userData, celix_bundle_context_t *con
 		serviceTracker_destroy(activator->endpointListenerTracker);
 	}
 
-	bundleContext_removeServiceListener(context, activator->serviceListener);
-	free(activator->serviceListener);
+    if (serviceTracker_close(activator->exportedServicesTracker) == CELIX_SUCCESS) {
+        serviceTracker_destroy(activator->exportedServicesTracker);
+    }
 
 	serviceRegistration_unregister(activator->hook);
 	free(activator->hookService);
diff --git a/bundles/remote_services/topology_manager/src/topology_manager.c b/bundles/remote_services/topology_manager/src/topology_manager.c
index 82c12d1..193b882 100644
--- a/bundles/remote_services/topology_manager/src/topology_manager.c
+++ b/bundles/remote_services/topology_manager/src/topology_manager.c
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 
 #include "celixbool.h"
 #include "topology_manager.h"
@@ -201,91 +202,75 @@ celix_status_t topologyManager_rsaAdding(void * handle, service_reference_pt ref
 	return status;
 }
 
-celix_status_t topologyManager_rsaAdded(void * handle, service_reference_pt reference, void * service) {
-	celix_status_t status;
+celix_status_t topologyManager_rsaAdded(void * handle, service_reference_pt unusedRef __attribute__((unused)), void * service) {
 	topology_manager_pt manager = (topology_manager_pt) handle;
 	celix_properties_t *serviceProperties = NULL;
 	remote_service_admin_service_t *rsa = (remote_service_admin_service_t *) service;
 	logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Added RSA");
 
-	status = celixThreadMutex_lock(&manager->rsaListLock);
-
-	if (status == CELIX_SUCCESS) {
-		arrayList_add(manager->rsaList, rsa);
-		status = celixThreadMutex_unlock(&manager->rsaListLock);
-	}
+	celixThreadMutex_lock(&manager->rsaListLock);
+	arrayList_add(manager->rsaList, rsa);
+    celixThreadMutex_unlock(&manager->rsaListLock);
 
 	// add already imported services to new rsa
-	if (status == CELIX_SUCCESS) {
-		status = celixThreadMutex_lock(&manager->importedServicesLock);
+    celixThreadMutex_lock(&manager->importedServicesLock);
+    hash_map_iterator_pt importedServicesIterator = hashMapIterator_create(manager->importedServices);
 
-		if (status == CELIX_SUCCESS) {
-			hash_map_iterator_pt importedServicesIterator = hashMapIterator_create(manager->importedServices);
+    while (hashMapIterator_hasNext(importedServicesIterator)) {
+        hash_map_entry_pt entry = hashMapIterator_nextEntry(importedServicesIterator);
+        endpoint_description_t *endpoint = hashMapEntry_getKey(entry);
+        if (scope_allowImport(manager->scope, endpoint)) {
+            import_registration_t *import = NULL;
+            celix_status_t status = rsa->importService(rsa->admin, endpoint, &import);
 
-			while (hashMapIterator_hasNext(importedServicesIterator)) {
-				hash_map_entry_pt entry = hashMapIterator_nextEntry(importedServicesIterator);
-				endpoint_description_t *endpoint = hashMapEntry_getKey(entry);
-				if (scope_allowImport(manager->scope, endpoint)) {
-					import_registration_t *import = NULL;
-					status = rsa->importService(rsa->admin, endpoint, &import);
-
-					if (status == CELIX_SUCCESS) {
-						hash_map_pt imports = hashMapEntry_getValue(entry);
-
-						if (imports == NULL) {
-							imports = hashMap_create(NULL, NULL, NULL, NULL);
-							hashMap_put(manager->importedServices,endpoint,imports);
-						}
+            if (status == CELIX_SUCCESS) {
+                hash_map_pt imports = hashMapEntry_getValue(entry);
 
-						hashMap_put(imports, service, import);
-					}
-				}
-			}
+                if (imports == NULL) {
+                    imports = hashMap_create(NULL, NULL, NULL, NULL);
+                    hashMap_put(manager->importedServices, endpoint, imports);
+                }
 
-			hashMapIterator_destroy(importedServicesIterator);
+                hashMap_put(imports, service, import);
+            }
+        }
+    }
 
-			celixThreadMutex_unlock(&manager->importedServicesLock);
-		}
-	}
+    hashMapIterator_destroy(importedServicesIterator);
+    celixThreadMutex_unlock(&manager->importedServicesLock);
 
 	// add already exported services to new rsa
-	if (status == CELIX_SUCCESS) {
-		status = celixThreadMutex_lock(&manager->exportedServicesLock);
+    celixThreadMutex_lock(&manager->exportedServicesLock);
+    hash_map_iterator_pt exportedServicesIterator = hashMapIterator_create(manager->exportedServices);
 
-		if (status == CELIX_SUCCESS) {
-			hash_map_iterator_pt exportedServicesIterator = hashMapIterator_create(manager->exportedServices);
+    while (hashMapIterator_hasNext(exportedServicesIterator)) {
+        hash_map_entry_pt entry = hashMapIterator_nextEntry(exportedServicesIterator);
+        service_reference_pt reference = hashMapEntry_getKey(entry);
+        const char* serviceId = NULL;
 
-			while (hashMapIterator_hasNext(exportedServicesIterator)) {
-				hash_map_entry_pt entry = hashMapIterator_nextEntry(exportedServicesIterator);
-				service_reference_pt reference = hashMapEntry_getKey(entry);
-				const char* serviceId = NULL;
+        serviceReference_getProperty(reference, OSGI_FRAMEWORK_SERVICE_ID, &serviceId);
 
-				serviceReference_getProperty(reference, OSGI_FRAMEWORK_SERVICE_ID, &serviceId);
+        scope_getExportProperties(manager->scope, reference, &serviceProperties);
 
-				scope_getExportProperties(manager->scope, reference, &serviceProperties);
+        array_list_pt endpoints = NULL;
+        celix_status_t status = rsa->exportService(rsa->admin, (char*)serviceId, serviceProperties, &endpoints);
 
-				array_list_pt endpoints = NULL;
-				status = rsa->exportService(rsa->admin, (char*)serviceId, serviceProperties, &endpoints);
+        if (status == CELIX_SUCCESS) {
+            hash_map_pt exports = hashMapEntry_getValue(entry);
 
-				if (status == CELIX_SUCCESS) {
-					hash_map_pt exports = hashMapEntry_getValue(entry);
+            if (exports == NULL) {
+                exports = hashMap_create(NULL, NULL, NULL, NULL);
+                hashMap_put(manager->exportedServices,reference,exports);
+            }
 
-					if (exports == NULL) {
-						exports = hashMap_create(NULL, NULL, NULL, NULL);
-						hashMap_put(manager->exportedServices,reference,exports);
-					}
+            hashMap_put(exports, rsa, endpoints);
+            topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints);
+        }
+    }
 
-					hashMap_put(exports, rsa, endpoints);
-					status = topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints);
-				}
-			}
-
-			hashMapIterator_destroy(exportedServicesIterator);
-
-			celixThreadMutex_unlock(&manager->exportedServicesLock);
-		}
-	}
-	return status;
+    hashMapIterator_destroy(exportedServicesIterator);
+    celixThreadMutex_unlock(&manager->exportedServicesLock);
+	return CELIX_SUCCESS;
 }
 
 celix_status_t topologyManager_rsaModified(void * handle, service_reference_pt reference, void * service) {
@@ -376,43 +361,6 @@ celix_status_t topologyManager_rsaRemoved(void * handle, service_reference_pt re
 	return status;
 }
 
-
-celix_status_t topologyManager_serviceChanged(void *listener, celix_service_event_t *event) {
-	celix_status_t status = CELIX_SUCCESS;
-	celix_service_listener_t *listen = listener;
-	topology_manager_pt manager = listen->handle;
-
-	const char* export = NULL;
-	const char* serviceId = NULL;
-	serviceReference_getProperty(event->reference, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &export);
-	serviceReference_getProperty(event->reference, OSGI_FRAMEWORK_SERVICE_ID, &serviceId);
-
-	if (!export) {
-		// Nothing needs to be done: we're not interested...
-		return status;
-	}
-
-	switch (event->type) {
-	case OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED:
-		status = topologyManager_addExportedService(manager, event->reference, (char*)serviceId);
-		break;
-	case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED:
-		status = topologyManager_removeExportedService(manager, event->reference, (char*)serviceId);
-
-		if (status == CELIX_SUCCESS) {
-			status = topologyManager_addExportedService(manager, event->reference, (char*)serviceId);
-		}
-		break;
-	case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING:
-		status = topologyManager_removeExportedService(manager, event->reference, (char*)serviceId);
-		break;
-	case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH:
-		break;
-	}
-
-	return status;
-}
-
 celix_status_t topologyManager_exportScopeChanged(void *handle, char *filterStr) {
 	celix_status_t status = CELIX_SUCCESS;
 	topology_manager_pt manager = (topology_manager_pt) handle;
@@ -602,11 +550,19 @@ celix_status_t topologyManager_removeImportedService(void *handle, endpoint_desc
 	return status;
 }
 
-celix_status_t topologyManager_addExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId) {
+celix_status_t topologyManager_addExportedService(void * handle, service_reference_pt reference, void * service __attribute__((unused))) {
+    topology_manager_pt manager = handle;
 	celix_status_t status = CELIX_SUCCESS;
+    long serviceId = serviceReference_getServiceId(reference);
+    char serviceIdStr[64];
+    snprintf(serviceIdStr, 64, "%li", serviceId);
 	celix_properties_t *serviceProperties = NULL;
 
-	logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Add exported service (%s).", serviceId);
+	const char *export = NULL;
+    serviceReference_getProperty(reference, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &export);
+    assert(export != NULL);
+
+	logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Add exported service (%li).", serviceId);
 
 	if (celixThreadMutex_lock(&manager->exportedServicesLock) == CELIX_SUCCESS) {
 		scope_getExportProperties(manager->scope, reference, &serviceProperties);
@@ -624,7 +580,7 @@ celix_status_t topologyManager_addExportedService(topology_manager_pt manager, s
 				remote_service_admin_service_t *rsa = arrayList_get(manager->rsaList, iter);
 
 				array_list_pt endpoints = NULL;
-				celix_status_t substatus = rsa->exportService(rsa->admin, serviceId, serviceProperties, &endpoints);
+				celix_status_t substatus = rsa->exportService(rsa->admin, serviceIdStr, serviceProperties, &endpoints);
 
 				if (substatus == CELIX_SUCCESS) {
 					hashMap_put(exports, rsa, endpoints);
@@ -641,10 +597,12 @@ celix_status_t topologyManager_addExportedService(topology_manager_pt manager, s
 	return status;
 }
 
-celix_status_t topologyManager_removeExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId) {
+celix_status_t topologyManager_removeExportedService(void * handle, service_reference_pt reference, void * service  __attribute__((unused))) {
+    topology_manager_pt manager = handle;
 	celix_status_t status = CELIX_SUCCESS;
+	long serviceId = serviceReference_getServiceId(reference);
 
-	logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Remove exported service (%s).", serviceId);
+	logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Remove exported service (%li).", serviceId);
 
 	if (celixThreadMutex_lock(&manager->exportedServicesLock) == CELIX_SUCCESS) {
 		hash_map_pt exports = hashMap_get(manager->exportedServices, reference);
diff --git a/bundles/remote_services/topology_manager/src/topology_manager.h b/bundles/remote_services/topology_manager/src/topology_manager.h
index 5f66ccd..8845214 100644
--- a/bundles/remote_services/topology_manager/src/topology_manager.h
+++ b/bundles/remote_services/topology_manager/src/topology_manager.h
@@ -57,8 +57,8 @@ celix_status_t topologyManager_serviceChanged(void *listener, celix_service_even
 celix_status_t topologyManager_addImportedService(void *handle, endpoint_description_t *endpoint, char *matchedFilter);
 celix_status_t topologyManager_removeImportedService(void *handle, endpoint_description_t *endpoint, char *matchedFilter);
 
-celix_status_t topologyManager_addExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId);
-celix_status_t topologyManager_removeExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId);
+celix_status_t topologyManager_addExportedService(void * handle, service_reference_pt reference, void * service);
+celix_status_t topologyManager_removeExportedService(void * handle, service_reference_pt reference, void * service);
 
 celix_status_t topologyManager_listenerAdded(void *handle, array_list_pt listeners);
 celix_status_t topologyManager_listenerRemoved(void *handle, array_list_pt listeners);
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index a8d551a..70dc025 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -39,6 +39,7 @@ target_include_directories(framework PUBLIC
         $<INSTALL_INTERFACE:include/celix>
 )
 target_compile_options(framework PRIVATE -DUSE_FILE32API)
+target_compile_options(framework PRIVATE -Wno-deprecated-declarations) #note part of the api is deprecated, ignore this warning on own api
 set_target_properties(framework PROPERTIES "SOVERSION" 2)
 
 target_link_libraries(framework PUBLIC Celix::utils Celix::dfi ${CELIX_OPTIONAL_EXTRA_LIBS})
@@ -112,6 +113,7 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
         private/mock/bundle_mock.c
         private/mock/celix_log_mock.c)
     target_link_libraries(bundle_context_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
+    target_compile_options(bundle_context_test PRIVATE -Wno-deprecated-declarations)
 
     add_executable(bundle_revision_test
         private/test/bundle_revision_test.cpp
diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index fa650a4..17e0d89 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -111,13 +111,15 @@ TEST_F(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
     };
 
     int total = 0;
-    celix_bundleContext_useServices(ctx, "calc", &total, use);
+    auto count = celix_bundleContext_useServices(ctx, "calc", &total, use);
+    ASSERT_EQ(3, count);
     ASSERT_EQ(42 * 3, total);
 
 
     celix_bundleContext_unregisterService(ctx, svcId3);
     total = 0;
-    celix_bundleContext_useServices(ctx, "calc", &total, use);
+    count = celix_bundleContext_useServices(ctx, "calc", &total, use);
+    ASSERT_EQ(2, count);
     ASSERT_EQ(42 * 2, total);
 
     total = 0;
@@ -127,6 +129,10 @@ TEST_F(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
 
     celix_bundleContext_unregisterService(ctx, svcId1);
     celix_bundleContext_unregisterService(ctx, svcId2);
+
+    //NOTE superfluous (note prints errors)
+    celix_bundleContext_unregisterService(ctx, svcId1);
+    celix_bundleContext_unregisterService(ctx, svcId2);
 };
 
 TEST_F(CelixBundleContextServicesTests, registerAndUseService) {
@@ -169,50 +175,52 @@ TEST_F(CelixBundleContextServicesTests, registerAndUseService) {
 };
 
 TEST_F(CelixBundleContextServicesTests, registerAndUseServiceWithTimeout) {
-    struct calc {
-        int (*calc)(int);
-    };
+    const int NR_ITERATIONS = 5; //NOTE this test is sensitive for triggering race condition in the celix framework, therefore is used a few times.
+    for (int i = 0; i < NR_ITERATIONS; ++i) {
+        printf("Iter %i\n", i);
+        struct calc {
+            int (*calc)(int);
+        };
 
-    const char *calcName = "calc";
-    struct calc svc;
-    svc.calc = [](int n) -> int {
-        return n * 42;
-    };
-
-    celix_service_use_options_t opts{};
-    opts.filter.serviceName = "calc";
+        const char *calcName = "calc";
+        struct calc svc;
+        svc.calc = [](int n) -> int {
+            return n * 42;
+        };
 
-    bool called = celix_bundleContext_useServiceWithOptions(ctx, &opts);
-    ASSERT_TRUE(!called); //service not avail.
+        celix_service_use_options_t opts{};
+        opts.filter.serviceName = "calc";
 
-    std::future<bool> result{std::async([&]{
-        opts.waitTimeoutInSeconds = 5.0;
-        printf("Trying to call calc with timeout of %f\n", opts.waitTimeoutInSeconds);
-        bool calledAsync = celix_bundleContext_useServiceWithOptions(ctx, &opts);
-        printf("returned from use service with timeout. calc called %s.\n", calledAsync ? "true" : "false");
-        return calledAsync;
-    })};
-    long svcId = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    ASSERT_TRUE(svcId >= 0);
+        bool called = celix_bundleContext_useServiceWithOptions(ctx, &opts);
+        EXPECT_FALSE(called); //service not avail.
 
+        std::future<bool> result{std::async([&] {
+            opts.waitTimeoutInSeconds = 2.0;
+            //printf("Trying to call calc with timeout of %f\n", opts.waitTimeoutInSeconds);
+            bool calledAsync = celix_bundleContext_useServiceWithOptions(ctx, &opts);
+            //printf("returned from use service with timeout. calc called %s.\n", calledAsync ? "true" : "false");
+            return calledAsync;
+        })};
+        long svcId = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
+        EXPECT_TRUE(svcId >= 0);
 
-    ASSERT_TRUE(result.get()); //should return true after waiting for the registered service.
 
+        EXPECT_TRUE(result.get()); //should return true after waiting for the registered service.
 
-    celix_bundleContext_unregisterService(ctx, svcId);
 
+        celix_bundleContext_unregisterService(ctx, svcId);
 
-    //check if timeout is triggered
-    std::future<bool> result2{std::async([&]{
-        opts.waitTimeoutInSeconds = 0.5;
-        printf("Trying to call calc with timeout of %f\n", opts.waitTimeoutInSeconds);
-        bool calledAsync = celix_bundleContext_useServiceWithOptions(ctx, &opts);
-        printf("returned from use service with timeout. calc called %s.\n", calledAsync ? "true" : "false");
-        return calledAsync;
-    })};
-    ASSERT_TRUE(!result2.get());
 
-    celix_bundleContext_unregisterService(ctx, svcId);
+        //check if timeout is triggered
+        std::future<bool> result2{std::async([&] {
+            opts.waitTimeoutInSeconds = 0.1;
+            //printf("Trying to call calc with timeout of %f\n", opts.waitTimeoutInSeconds);
+            bool calledAsync = celix_bundleContext_useServiceWithOptions(ctx, &opts);
+            //printf("returned from use service with timeout. calc called %s.\n", calledAsync ? "true" : "false");
+            return calledAsync;
+        })};
+        EXPECT_FALSE(result2.get()); //note service is away, so even with a wait the service is not found.
+    }
 }
 
 TEST_F(CelixBundleContextServicesTests, registerAndUseServiceWithCorrectVersion) {
diff --git a/libs/framework/include/bundle_context.h b/libs/framework/include/bundle_context.h
index 77fbd1c..8bdda05 100644
--- a/libs/framework/include/bundle_context.h
+++ b/libs/framework/include/bundle_context.h
@@ -125,7 +125,7 @@ FRAMEWORK_EXPORT celix_status_t bundleContext_getBundles(celix_bundle_context_t
 FRAMEWORK_EXPORT celix_status_t bundleContext_getBundleById(celix_bundle_context_t *context, long id, celix_bundle_t **bundle);
 
 FRAMEWORK_EXPORT celix_status_t
-bundleContext_addServiceListener(celix_bundle_context_t *context, celix_service_listener_t *listener, const char *filter);
+bundleContext_addServiceListener(celix_bundle_context_t *context, celix_service_listener_t *listener, const char *filter) __attribute__((deprecated("using service listeners directly is deprecated, use a service tracker instead!")));
 
 FRAMEWORK_EXPORT celix_status_t
 bundleContext_removeServiceListener(celix_bundle_context_t *context, celix_service_listener_t *listener);
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index db513c7..559b2a8 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -471,8 +471,9 @@ bool celix_bundleContext_useService(
  * @param   serviceName the required service name.
  * @param   callbackHandle The data pointer, which will be used in the callbacks
  * @param   use The callback, which will be called for every service found.
+ * @return  The number of services found and called
  */
-void celix_bundleContext_useServices(
+size_t celix_bundleContext_useServices(
         celix_bundle_context_t *ctx,
         const char* serviceName,
         void *callbackHandle,
@@ -568,8 +569,9 @@ bool celix_bundleContext_useServiceWithOptions(
  *
  * @param   ctx The bundle context.
  * @param   opts The required options. Note that the serviceName is required.
+ * @return  The number of services found and called
  */
-void celix_bundleContext_useServicesWithOptions(
+size_t celix_bundleContext_useServicesWithOptions(
         celix_bundle_context_t *ctx,
         const celix_service_use_options_t *opts);
 
diff --git a/libs/framework/include/service_reference.h b/libs/framework/include/service_reference.h
index a734909..0ec54a0 100644
--- a/libs/framework/include/service_reference.h
+++ b/libs/framework/include/service_reference.h
@@ -48,6 +48,9 @@ serviceReference_getPropertyKeys(service_reference_pt reference, char **keys[],
 FRAMEWORK_EXPORT celix_status_t
 serviceReference_getServiceRegistration(service_reference_pt reference, service_registration_pt *registration);
 
+FRAMEWORK_EXPORT
+long serviceReference_getServiceId(service_reference_pt reference);
+
 FRAMEWORK_EXPORT celix_status_t
 serviceReference_equals(service_reference_pt reference, service_reference_pt compareTo, bool *equal);
 
diff --git a/libs/framework/include/service_registry.h b/libs/framework/include/service_registry.h
index 9f06f8a..28d8afd 100644
--- a/libs/framework/include/service_registry.h
+++ b/libs/framework/include/service_registry.h
@@ -38,8 +38,7 @@ extern "C" {
 
 typedef void (*serviceChanged_function_pt)(celix_framework_t*, celix_service_event_type_t, service_registration_pt, celix_properties_t*);
 
-celix_status_t serviceRegistry_create(celix_framework_t *framework, serviceChanged_function_pt serviceChanged,
-                                      service_registry_pt *registry);
+celix_status_t serviceRegistry_create(celix_framework_t *framework, service_registry_pt *registry);
 
 celix_status_t serviceRegistry_destroy(service_registry_pt registry);
 
@@ -87,13 +86,15 @@ serviceRegistry_ungetService(service_registry_pt registry, celix_bundle_t *bundl
 
 celix_status_t serviceRegistry_clearReferencesFor(service_registry_pt registry, celix_bundle_t *bundle);
 
-void serviceRegistry_callHooksForListenerFilter(service_registry_pt registry, celix_bundle_t *owner, const char *filter, bool removed);
-
 size_t serviceRegistry_nrOfHooks(service_registry_pt registry);
 
-celix_status_t
-serviceRegistry_servicePropertiesModified(service_registry_pt registry, service_registration_pt registration,
-                                          celix_properties_t *oldprops);
+/**
+ * Register a service listener. Will also retroactively call the listener with register events for already registered services.
+ */
+celix_status_t celix_serviceRegistry_addServiceListener(celix_service_registry_t *reg, celix_bundle_t *bundle, const char *filter, celix_service_listener_t *listener);
+
+celix_status_t celix_serviceRegistry_removeServiceListener(celix_service_registry_t *reg, celix_service_listener_t *listener);
+
 
 celix_status_t
 celix_serviceRegistry_registerServiceFactory(
diff --git a/libs/framework/include/service_tracker.h b/libs/framework/include/service_tracker.h
index 4b58e10..4e69621 100644
--- a/libs/framework/include/service_tracker.h
+++ b/libs/framework/include/service_tracker.h
@@ -61,8 +61,6 @@ FRAMEWORK_EXPORT celix_array_list_t *serviceTracker_getServices(service_tracker_
 
 FRAMEWORK_EXPORT void *serviceTracker_getServiceByReference(service_tracker_t *tracker, service_reference_pt reference);
 
-FRAMEWORK_EXPORT void serviceTracker_serviceChanged(celix_service_listener_t *listener, celix_service_event_t *event);
-
 FRAMEWORK_EXPORT size_t serviceTracker_nrOfTrackedServices(service_tracker_t *tracker);
 
 
@@ -125,8 +123,9 @@ bool celix_serviceTracker_useHighestRankingService(
 
 /**
  * Calls the use callback for every services found by this tracker.
+ * Returns the number of called services
  */
-void celix_serviceTracker_useServices(
+size_t celix_serviceTracker_useServices(
         service_tracker_t *tracker,
         const char* serviceName /*sanity*/,
         void *callbackHandle,
diff --git a/libs/framework/private/mock/bundle_context_mock.c b/libs/framework/private/mock/bundle_context_mock.c
index 61642c2..873981d 100644
--- a/libs/framework/private/mock/bundle_context_mock.c
+++ b/libs/framework/private/mock/bundle_context_mock.c
@@ -317,12 +317,13 @@ bool celix_bundleContext_useServiceWithOptions(
 }
 
 
-void celix_bundleContext_useServicesWithOptions(
+size_t celix_bundleContext_useServicesWithOptions(
 		celix_bundle_context_t *ctx,
 		const celix_service_use_options_t *opts) {
 	mock_c()->actualCall("celix_bundleContext_useServicesWithOptions")
 			->withPointerParameters("ctx", ctx)
 			->withConstPointerParameters("opts", opts);
+	return mock_c()->returnValue().value.unsignedLongIntValue;
 }
 
 long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props) {
diff --git a/libs/framework/private/mock/service_reference_mock.c b/libs/framework/private/mock/service_reference_mock.c
index e9248c0..e2753fe 100644
--- a/libs/framework/private/mock/service_reference_mock.c
+++ b/libs/framework/private/mock/service_reference_mock.c
@@ -184,3 +184,9 @@ unsigned int serviceReference_hashCode(const void *referenceP) {
 	mock_c()->actualCall("serviceReference_hashCode");
 	return mock_c()->returnValue().value.intValue;
 }
+
+long serviceReference_getServiceId(service_reference_pt reference) {
+    mock_c()->actualCall("serviceReference_getServiceId")
+            ->withPointerParameters("reference", reference);
+    return mock_c()->returnValue().value.longIntValue;
+}
\ No newline at end of file
diff --git a/libs/framework/private/mock/service_registry_mock.c b/libs/framework/private/mock/service_registry_mock.c
index 767e507..8df72e9 100644
--- a/libs/framework/private/mock/service_registry_mock.c
+++ b/libs/framework/private/mock/service_registry_mock.c
@@ -29,10 +29,9 @@
 
 #include "service_registry.h"
 
-celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_function_pt serviceChanged, service_registry_pt *registry) {
+celix_status_t serviceRegistry_create(framework_pt framework, service_registry_pt *registry) {
 	mock_c()->actualCall("serviceRegistry_create")
 			->withPointerParameters("framework", framework)
-			->withPointerParameters("serviceChanged", serviceChanged)
 			->withOutputParameter("registry", registry);
 	return mock_c()->returnValue().value.intValue;
 }
@@ -219,4 +218,21 @@ celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_r
         ->withPointerParameters("registry", registry)
         ->withLongIntParameters("bndId", bndId);
     return mock_c()->returnValue().value.pointerValue;
-}
\ No newline at end of file
+}
+
+celix_status_t celix_serviceRegistry_addServiceListener(celix_service_registry_t *registry, celix_bundle_t *bundle, const char *stringFilter, celix_service_listener_t *listener) {
+    mock_c()->actualCall("celix_serviceRegistry_addServiceListener")
+            ->withPointerParameters("registry", registry)
+            ->withPointerParameters("bundle", bundle)
+            ->withConstPointerParameters("stringFilter", stringFilter)
+            ->withPointerParameters("listener", listener);
+    return mock_c()->returnValue().value.intValue;
+}
+
+celix_status_t celix_serviceRegistry_removeServiceListener(celix_service_registry_t *registry, celix_service_listener_t *listener) {
+    mock_c()->actualCall("celix_serviceRegistry_removeServiceListener")
+            ->withPointerParameters("registry", registry)
+            ->withPointerParameters("listener", listener);
+    return mock_c()->returnValue().value.intValue;
+}
+
diff --git a/libs/framework/private/test/service_registration_test.cpp b/libs/framework/private/test/service_registration_test.cpp
index b1c560e..d31f692 100644
--- a/libs/framework/private/test/service_registration_test.cpp
+++ b/libs/framework/private/test/service_registration_test.cpp
@@ -344,30 +344,6 @@ TEST(service_registration, getProperties) {
 	free(name);
 }
 
-TEST(service_registration, setProperties){
-	registry_callback_t callback;
-	callback.modified = (callback_modified_signature) serviceRegistry_servicePropertiesModified;
-	service_registry_pt registry = (service_registry_pt) 0x10;
-	callback.handle = registry;
-	char * name = my_strdup("service_name");
-	service_registration_pt registration = serviceRegistration_create(callback, NULL, name, 0, NULL, NULL);
-
-	properties_pt properties = properties_create();
-	properties_pt old_properties = registration->properties;
-
-	mock().expectOneCall("serviceRegistry_servicePropertiesModified")
-			.withParameter("registry", registry)
-			.withParameter("registration", registration)
-			.withParameter("oldprops", old_properties);
-
-	serviceRegistration_setProperties(registration, properties);
-
-	POINTERS_EQUAL(properties, registration->properties);
-
-	properties_destroy(old_properties);
-	serviceRegistration_release(registration);
-	free(name);
-}
 
 TEST(service_registration, getServiceName) {
 	registry_callback_t callback;
diff --git a/libs/framework/private/test/service_registry_test.cpp b/libs/framework/private/test/service_registry_test.cpp
index ee2ae88..67c25f0 100644
--- a/libs/framework/private/test/service_registry_test.cpp
+++ b/libs/framework/private/test/service_registry_test.cpp
@@ -44,14 +44,6 @@ extern "C" {
 
 framework_logger_pt logger = (framework_logger_pt) 0x42;
 
-void serviceRegistryTest_serviceChanged(framework_pt framework, celix_service_event_type_t eventType, service_registration_pt registration, properties_pt oldprops) {
-	mock_c()->actualCall("serviceRegistryTest_serviceChanged")
-			->withPointerParameters("framework", framework)
-			->withIntParameters("eventType", eventType)
-			->withPointerParameters("registration", registration)
-			->withPointerParameters("oldprops", oldprops);
-}
-
 static char* my_strdup(const char* s) {
 	if (s == NULL) {
 		return NULL;
@@ -75,7 +67,6 @@ static int registry_callback_t_isEqual(const void* object1, const void* object2)
 	registry_callback_t callback2 = *(registry_callback_t*) object2;
 	return 	callback1.getUsingBundles == callback2.getUsingBundles &&
        		callback1.handle == callback2.handle &&
-       		callback1.modified == callback2.modified &&
        		callback1.unregister == callback2.unregister;
 }
 
@@ -83,7 +74,7 @@ static const char * registry_callback_t_toString(const void* object)
 {
 	char buff[512];
 	registry_callback_t callback = *(registry_callback_t*) object;
-	snprintf(buff, 512, "getUsingBundles: %p, handle: %p, modified: %p, unregister: %p", callback.getUsingBundles, callback.handle, callback.modified, callback.unregister);
+	snprintf(buff, 512, "getUsingBundles: %p, handle: %p, unregister: %p", callback.getUsingBundles, callback.handle, callback.unregister);
 
 	return my_strdup(buff);
 }
@@ -110,10 +101,9 @@ TEST(service_registry, create) {
 	framework_pt framework = (framework_pt) 0x10;
 	service_registry_pt registry = NULL;
 
-	serviceRegistry_create(framework, serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	POINTERS_EQUAL(framework, registry->framework);
-	POINTERS_EQUAL(serviceRegistryTest_serviceChanged, registry->serviceChanged);
 	UNSIGNED_LONGS_EQUAL(1UL, registry->currentServiceId);
 	CHECK(registry->listenerHooks != NULL);
 	CHECK(registry->serviceReferences != NULL);
@@ -125,7 +115,7 @@ TEST(service_registry, create) {
 TEST(service_registry, getRegisteredServices) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 	array_list_pt registrations = NULL;
 	arrayList_create(&registrations);
 	service_registration_pt reg = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
@@ -139,6 +129,8 @@ TEST(service_registry, getRegisteredServices) {
 	hashMap_put(usages, (void*)reg->serviceId, ref);
 	hashMap_put(registry->serviceReferences, bundle, usages);
 
+    mock().expectNCalls(1,"framework_log");
+
 	mock()
 		.expectOneCall("serviceRegistration_isValid")
 		.withParameter("registration", reg)
@@ -163,7 +155,7 @@ TEST(service_registry, getRegisteredServices) {
 TEST(service_registry, getServicesInUse) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	hash_map_pt usages = hashMap_create(NULL, NULL, NULL, NULL);
 	bundle_pt bundle = (bundle_pt) 0x10;
@@ -172,6 +164,8 @@ TEST(service_registry, getServicesInUse) {
 	hashMap_put(usages, reg, ref);
 	hashMap_put(registry->serviceReferences, bundle, usages);
 
+    mock().expectNCalls(1,"framework_log");
+
 	array_list_pt inUse = NULL;
 	serviceRegistry_getServicesInUse(registry, bundle, &inUse);
 	LONGS_EQUAL(1, arrayList_size(inUse));
@@ -185,7 +179,7 @@ TEST(service_registry, getServicesInUse) {
 TEST(service_registry, registerServiceNoProps) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	char * serviceName = my_strdup("service");
@@ -202,11 +196,9 @@ TEST(service_registry, registerServiceNoProps) {
 		.withParameter("dictionary", (void *) NULL)
 		.andReturnValue(reg);
 
-	mock().expectOneCall("serviceRegistryTest_serviceChanged")
-			.withParameter("framework", framework)
-			.withParameter("eventType", OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED)
-			.withParameter("registration", reg)
-			.withParameter("oldprops", (void*)NULL);
+    mock().expectNCalls(1,"serviceRegistration_getServiceId")
+            .withParameter("registration", reg)
+            .andReturnValue(42);
 
 	service_registration_pt registration = NULL;
 	serviceRegistry_registerService(registry, bundle, serviceName, service, NULL, &registration);
@@ -221,7 +213,7 @@ TEST(service_registry, registerServiceNoProps) {
 TEST(service_registry, registerServiceFactoryNoProps) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	char * serviceName = my_strdup("service");
@@ -239,11 +231,9 @@ TEST(service_registry, registerServiceFactoryNoProps) {
 		.withParameter("dictionary", (void *) NULL)
 		.andReturnValue(reg);
 
-	mock().expectOneCall("serviceRegistryTest_serviceChanged")
-		.withParameter("framework", framework)
-		.withParameter("eventType", OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED)
-		.withParameter("registration", reg)
-		.withParameter("oldprops", (void*)NULL);
+    mock().expectNCalls(1,"serviceRegistration_getServiceId")
+            .withParameter("registration", reg)
+            .andReturnValue(42);
 
 	service_registration_pt registration = NULL;
 	serviceRegistry_registerServiceFactory(registry, bundle, serviceName, factory, NULL, &registration);
@@ -259,7 +249,7 @@ TEST(service_registry, registerServiceFactoryNoProps) {
 TEST(service_registry, registerServiceListenerHook) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	char * serviceName = my_strdup(OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME);
@@ -277,13 +267,7 @@ TEST(service_registry, registerServiceListenerHook) {
 		.withParameter("dictionary", (void *) NULL)
 		.andReturnValue(reg);
 
-	mock().expectOneCall("serviceRegistryTest_serviceChanged")
-			.withParameter("framework", framework)
-			.withParameter("eventType", OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED)
-			.withParameter("registration", reg)
-			.withParameter("oldprops", (void*)NULL);
-
-    mock().expectOneCall("serviceRegistration_getServiceId")
+    mock().expectNCalls(2,"serviceRegistration_getServiceId")
             .withParameter("registration", reg)
             .andReturnValue(svcId);
 
@@ -306,7 +290,7 @@ TEST(service_registry, registerServiceListenerHook) {
 TEST(service_registry, unregisterService) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
 	registration->serviceId = 20UL;
@@ -323,6 +307,17 @@ TEST(service_registry, unregisterService) {
 	properties_pt properties = (properties_pt) 0x40;
 	long svcId = 12;
 
+    mock().expectNCalls(1,"framework_log");
+
+    char *serviceName = (char *) OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME;
+
+
+    mock()
+        .expectOneCall("serviceRegistration_getServiceName")
+        .withParameter("registration", registration)
+            .withOutputParameterReturning("serviceName", &serviceName, sizeof(serviceName))
+        .andReturnValue(CELIX_SUCCESS);
+
 	mock()
 		.expectOneCall("serviceRegistration_getProperties")
 		.withParameter("registration", registration)
@@ -334,18 +329,11 @@ TEST(service_registry, unregisterService) {
 		.withParameter("key", (char *)OSGI_FRAMEWORK_OBJECTCLASS)
 		.andReturnValue((char*)OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME);
 
-    mock().expectOneCall("serviceRegistration_getServiceId")
+    mock().expectNCalls(2,"serviceRegistration_getServiceId")
             .withParameter("registration", registration)
             .andReturnValue(svcId);
 
 	mock()
-		.expectOneCall("serviceRegistryTest_serviceChanged")
-		.withParameter("framework", framework)
-		.withParameter("eventType", OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING)
-		.withParameter("registration", registration)
-		.withParameter("oldprops", (void*) NULL);
-
-	mock()
 		.expectOneCall("serviceReference_invalidate")
 		.withParameter("reference", reference);
 
@@ -368,7 +356,7 @@ TEST(service_registry, unregisterService) {
 TEST(service_registry, clearServiceRegistrations){
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 	array_list_pt registrations = NULL;
 	arrayList_create(&registrations);
 	service_registration_pt reg = (service_registration_pt) 0x10;
@@ -424,7 +412,7 @@ TEST(service_registry, clearServiceRegistrations){
 TEST(service_registry, getServiceReference){
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
@@ -435,6 +423,8 @@ TEST(service_registry, getServiceReference){
 	hashMap_put(references, (void*)registration->serviceId, reference);
 	hashMap_put(registry->serviceReferences, bundle, references);
 
+    mock().expectNCalls(1,"framework_log");
+
 	mock().expectOneCall("serviceReference_retain")
 			.withParameter("ref", reference);
 
@@ -451,7 +441,7 @@ TEST(service_registry, getServiceReference){
 TEST(service_registry, getServiceReference_unknownRef){
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
@@ -485,7 +475,7 @@ TEST(service_registry, getServiceReference_unknownRef){
 TEST(service_registry, getServiceReferences) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
@@ -504,6 +494,8 @@ TEST(service_registry, getServiceReferences) {
 	hashMap_put(references, (void*)registration->serviceId, reference);
 	hashMap_put(registry->serviceReferences, bundle, references);
 
+    mock().expectNCalls(1,"framework_log");
+
 	mock()
 		.expectOneCall("serviceRegistration_retain")
 		.withParameter("registration", registration);
@@ -554,7 +546,7 @@ TEST(service_registry, getServiceReferences) {
 TEST(service_registry, getServiceReferences_noFilterOrName) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
@@ -572,7 +564,9 @@ TEST(service_registry, getServiceReferences_noFilterOrName) {
 	hashMap_put(references, (void*)registration->serviceId, reference);
 	hashMap_put(registry->serviceReferences, bundle, references);
 
-	mock()
+    mock().expectNCalls(1,"framework_log");
+
+    mock()
 		.expectOneCall("serviceRegistration_retain")
 		.withParameter("registration", registration);
 
@@ -611,7 +605,7 @@ TEST(service_registry, getServiceReferences_noFilterOrName) {
 TEST(service_registry, retainServiceReference){
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	service_reference_pt reference = (service_reference_pt) 0x10;
 	bundle_pt bundle = (bundle_pt) 0x20;
@@ -651,7 +645,7 @@ TEST(service_registry, retainServiceReference){
 TEST(service_registry, ungetServiceReference){
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	service_registration_pt registration = (service_registration_pt) 0x10;
 	service_registration_pt registration2 = (service_registration_pt) 0x20;
@@ -661,7 +655,6 @@ TEST(service_registry, ungetServiceReference){
 	service_reference_pt reference3 = (service_reference_pt) 0x60;
 	bundle_pt bundle = (bundle_pt) 0x70;
 	bundle_pt bundle2 = (bundle_pt) 0x80;
-    module_pt module = (module_pt) 0x90;
 
 	hash_map_pt references = hashMap_create(NULL, NULL, NULL, NULL);
 	hashMap_put(references, registration, reference);
@@ -671,9 +664,9 @@ TEST(service_registry, ungetServiceReference){
 	hashMap_put(references2, registration3, reference3);
 	hashMap_put(registry->serviceReferences, bundle2, references2);
 
-	//test unknown reference (reference not present in registry->deletedServiceReferences)
-	mock().expectOneCall("framework_log");
+    mock().expectNCalls(5,"framework_log");
 
+    //test unknown reference (reference not present in registry->deletedServiceReferences)
 	serviceRegistry_ungetServiceReference(registry, bundle, reference);
 
 	//test known reference, but destroyed == false
@@ -699,7 +692,6 @@ TEST(service_registry, ungetServiceReference){
 	mock().expectOneCall("serviceReference_release")
 			.withParameter("ref", reference)
 			.withOutputParameterReturning("destroyed", &destroyed, sizeof(destroyed));
-	mock().expectOneCall("framework_log");
 
 	serviceRegistry_ungetServiceReference(registry, bundle2, reference);
 
@@ -707,7 +699,6 @@ TEST(service_registry, ungetServiceReference){
 	destroyed = true;
 	count = 5;
 
-    const char* mod_name = "mod name";
     //const char* srv_name = "srv name";
 	mock().expectOneCall("serviceReference_getUsageCount")
 			.withParameter("reference", reference)
@@ -715,13 +706,9 @@ TEST(service_registry, ungetServiceReference){
 	mock().expectOneCall("serviceReference_release")
 			.withParameter("ref", reference)
 			.withOutputParameterReturning("destroyed", &destroyed, sizeof(destroyed));
-    mock().expectNCalls(1, "bundle_getCurrentModule")
-            .withParameter("bundle", bundle)
-			.withOutputParameterReturning("module", &module, sizeof(module));
-    mock().expectNCalls(1, "module_getSymbolicName")
-            .withParameter("module", module)
-			.withOutputParameterReturning("symbolicName", &mod_name, sizeof(mod_name));
-	mock().expectNCalls(2, "framework_log");
+    mock().expectNCalls(1, "celix_bundle_getSymbolicName")
+            .withConstPointerParameter("bnd", bundle)
+            .andReturnValue("mod name");
 
 	serviceRegistry_ungetServiceReference(registry, bundle, reference);
 
@@ -758,7 +745,7 @@ TEST(service_registry, ungetServiceReference){
 TEST(service_registry, clearReferencesFor_1){
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	service_registration_pt registration = (service_registration_pt) 0x10;
 	service_reference_pt reference = (service_reference_pt) 0x40;
@@ -794,13 +781,11 @@ TEST(service_registry, clearReferencesFor_1){
 TEST(service_registry, clearReferencesFor_2){
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	service_registration_pt registration = (service_registration_pt) 0x10;
 	service_reference_pt reference = (service_reference_pt) 0x40;
 	bundle_pt bundle = (bundle_pt) 0x70;
-	module_pt module = (module_pt) 0x80;
-	const char* modName = "mod name";
     const char* srvName = "srv name";
 
 	hash_map_pt references = hashMap_create(NULL, NULL, NULL, NULL);
@@ -825,12 +810,9 @@ TEST(service_registry, clearReferencesFor_2){
 	mock().expectNCalls(1, "serviceReference_release")
 			.withParameter("ref", reference)
 			.withOutputParameterReturning("destroyed", &destroyed, sizeof(destroyed));
-	mock().expectNCalls(2, "bundle_getCurrentModule")
-			.withParameter("bundle", bundle)
-			.withOutputParameterReturning("module", &module, sizeof(module));
-	mock().expectNCalls(2, "module_getSymbolicName")
-			.withParameter("module", module)
-			.withOutputParameterReturning("symbolicName", &modName, sizeof(modName));
+	mock().expectNCalls(2, "celix_bundle_getSymbolicName")
+			.withConstPointerParameter("bnd", bundle)
+			.andReturnValue("mod name");
     mock().expectOneCall("serviceReference_getProperty")
             .withParameter("reference", reference)
             .withParameter("key", OSGI_FRAMEWORK_OBJECTCLASS)
@@ -852,7 +834,7 @@ TEST(service_registry, clearReferencesFor_2){
 TEST(service_registry, getService) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) 0x20;
@@ -941,7 +923,7 @@ TEST(service_registry, getService) {
 TEST(service_registry, ungetService) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) 0x20;
@@ -990,8 +972,7 @@ TEST(service_registry, ungetService) {
 	hashMap_remove(registry->deletedServiceReferences, reference);
 	hashMap_put(registry->deletedServiceReferences, reference, (void*) true);
 
-	mock()
-		.expectOneCall("framework_log");
+	mock().expectNCalls(2,"framework_log");
 
 	status = serviceRegistry_ungetService(registry, bundle, reference, &result);
 	LONGS_EQUAL(CELIX_BUNDLE_EXCEPTION, status);
@@ -1006,7 +987,7 @@ TEST(service_registry, ungetService) {
 TEST(service_registry, getListenerHooks) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 	bundle_pt bundle = (bundle_pt) 0x10;
 	service_registration_pt registration = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
 	registration->serviceId = 20UL;
@@ -1017,6 +998,8 @@ TEST(service_registry, getListenerHooks) {
 	hashMap_put(usages, (void*)registration->serviceId, reference);
 	hashMap_put(registry->serviceReferences, bundle, usages);
 
+    mock().ignoreOtherCalls();
+
     size_t nrOfHooks = serviceRegistry_nrOfHooks(registry);
 	LONGS_EQUAL(1, nrOfHooks);
 
@@ -1026,28 +1009,10 @@ TEST(service_registry, getListenerHooks) {
 	serviceRegistry_destroy(registry);
 }
 
-TEST(service_registry, servicePropertiesModified) {
-	service_registry_pt registry = NULL;
-	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
-	service_registration_pt registration = (service_registration_pt) 0x02;
-	properties_pt properties = (properties_pt) 0x03;
-
-	mock().expectOneCall("serviceRegistryTest_serviceChanged")
-		.withParameter("framework", registry->framework)
-		.withParameter("eventType", OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED)
-		.withParameter("registration", registration)
-		.withParameter("oldprops", properties);
-
-	serviceRegistry_servicePropertiesModified(registry, registration, properties);
-
-	serviceRegistry_destroy(registry);
-}
-
 TEST(service_registry, getUsingBundles) {
 	service_registry_pt registry = NULL;
 	framework_pt framework = (framework_pt) 0x01;
-	serviceRegistry_create(framework,serviceRegistryTest_serviceChanged, &registry);
+	serviceRegistry_create(framework, &registry);
 
 	service_registration_pt registration  = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
 	service_registration_pt registration2 = (service_registration_pt) calloc(1,sizeof(struct serviceRegistration));
@@ -1086,6 +1051,8 @@ TEST(service_registry, getUsingBundles) {
 	hashMap_put(references3, (void*)registration4->serviceId, reference5);
 	hashMap_put(registry->serviceReferences, bundle3, references3);
 
+    mock().ignoreOtherCalls();
+
 	//call to getUsingBundles
 	array_list_pt get_bundles_list = NULL;
 	registry->callback.getUsingBundles(registry, registration, &get_bundles_list);
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c
index cd7db9f..f59e86a 100644
--- a/libs/framework/src/bundle.c
+++ b/libs/framework/src/bundle.c
@@ -637,13 +637,7 @@ const char* celix_bundle_getGroup(const celix_bundle_t *bnd) {
 }
 
 const char* celix_bundle_getSymbolicName(const celix_bundle_t *bnd) {
-	const char *result = NULL;
-	module_pt mod = NULL;
-	bundle_getCurrentModule((bundle_pt)bnd, &mod);
-	if (mod != NULL) {
-		module_getSymbolicName(mod, &result);
-	}
-	return result;
+	return bnd->symbolicName;
 }
 
 celix_array_list_t* celix_bundle_listRegisteredServices(const celix_bundle_t *bnd) {
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 5122e30..7588970 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -502,7 +502,7 @@ void celix_bundleContext_unregisterService(bundle_context_t *ctx, long serviceId
         if (found != NULL) {
             serviceRegistration_unregister(found);
         } else {
-            framework_logIfError(logger, CELIX_ILLEGAL_ARGUMENT, NULL, "Provided service id (%li) is not used to registered using celix_bundleContext_registerCService/celix_registerServiceForLang". serviceId);
+            framework_logIfError(logger, CELIX_ILLEGAL_ARGUMENT, NULL, "No service registered with svc id %li for bundle %s (bundle id: %li)!", serviceId, celix_bundle_getSymbolicName(ctx->bundle), celix_bundle_getId(ctx->bundle));
         }
     }
 }
@@ -754,7 +754,7 @@ bool celix_bundleContext_useService(
 }
 
 
-void celix_bundleContext_useServices(
+size_t celix_bundleContext_useServices(
         bundle_context_t *ctx,
         const char* serviceName,
         void *callbackHandle,
@@ -763,7 +763,7 @@ void celix_bundleContext_useServices(
     opts.filter.serviceName = serviceName;
     opts.callbackHandle = callbackHandle;
     opts.use = use;
-    celix_bundleContext_useServicesWithOptions(ctx, &opts);
+    return celix_bundleContext_useServicesWithOptions(ctx, &opts);
 }
 
 
@@ -800,11 +800,11 @@ bool celix_bundleContext_useServiceWithOptions(
 
 
 
-void celix_bundleContext_useServicesWithOptions(
+size_t celix_bundleContext_useServicesWithOptions(
         celix_bundle_context_t *ctx,
         const celix_service_use_options_t *opts) {
+    size_t count = 0;
     celix_service_tracking_options_t trkOpts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
-
     if (opts != NULL) {
         trkOpts.filter.serviceName = opts->filter.serviceName;
         trkOpts.filter.filter = opts->filter.filter;
@@ -813,10 +813,11 @@ void celix_bundleContext_useServicesWithOptions(
 
         service_tracker_t *trk = celix_serviceTracker_createWithOptions(ctx, &trkOpts);
         if (trk != NULL) {
-            celix_serviceTracker_useServices(trk, opts->filter.serviceName, opts->callbackHandle, opts->use, opts->useWithProperties, opts->useWithOwner);
+            count = celix_serviceTracker_useServices(trk, opts->filter.serviceName, opts->callbackHandle, opts->use, opts->useWithProperties, opts->useWithOwner);
             celix_serviceTracker_destroy(trk);
         }
     }
+    return count;
 }
 
 
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index c3aef4d..be328be 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -32,7 +32,6 @@
 #include "utils.h"
 #include "linked_list_iterator.h"
 #include "service_reference_private.h"
-#include "listener_hook_service.h"
 #include "service_registration_private.h"
 #include "bundle_private.h"
 #include "celix_bundle_context.h"
@@ -222,71 +221,6 @@ struct request {
 
 typedef struct request *request_pt;
 
-typedef struct celix_fw_service_listener_entry {
-    //only set during creating
-    celix_bundle_t *bundle;
-	celix_service_listener_t *listener;
-	celix_filter_t *filter;
-
-    celix_thread_mutex_t mutex; //protects retainedReferences and useCount
-	celix_array_list_t* retainedReferences;
-	celix_thread_cond_t useCond;
-    size_t useCount;
-} celix_fw_service_listener_entry_t;
-
-static inline celix_fw_service_listener_entry_t* listener_create(celix_bundle_t *bnd, const char *filter, celix_service_listener_t *listener) {
-    celix_fw_service_listener_entry_t *entry = calloc(1, sizeof(*entry));
-    entry->retainedReferences = celix_arrayList_create();
-    entry->listener = listener;
-    entry->bundle = bnd;
-    if (filter != NULL) {
-        entry->filter = celix_filter_create(filter);
-    }
-
-    entry->useCount = 1;
-    celixThreadMutex_create(&entry->mutex, NULL);
-    celixThreadCondition_init(&entry->useCond, NULL);
-    return entry;
-}
-
-static inline void listener_retain(celix_fw_service_listener_entry_t *entry) {
-    celixThreadMutex_lock(&entry->mutex);
-    entry->useCount += 1;
-    celixThreadMutex_unlock(&entry->mutex);
-}
-
-static inline void listener_release(celix_fw_service_listener_entry_t *entry) {
-    celixThreadMutex_lock(&entry->mutex);
-    assert(entry->useCount > 0);
-    entry->useCount -= 1;
-    celixThreadCondition_broadcast(&entry->useCond);
-    celixThreadMutex_unlock(&entry->mutex);
-}
-
-static inline void listener_waitAndDestroy(celix_framework_t *framework, celix_fw_service_listener_entry_t *entry) {
-    celixThreadMutex_lock(&entry->mutex);
-    while (entry->useCount != 0) {
-        celixThreadCondition_wait(&entry->useCond, &entry->mutex);
-    }
-    celixThreadMutex_unlock(&entry->mutex);
-
-
-    //use count == 0 -> safe to destroy.
-    //destroy
-    int rSize = arrayList_size(entry->retainedReferences);
-    for (int i = 0; i < rSize; i += 1) {
-        service_reference_pt ref = arrayList_get(entry->retainedReferences, i);
-        if (ref != NULL) {
-            serviceRegistry_ungetServiceReference(framework->registry, entry->bundle, ref); // decrease retain counter
-        }
-    }
-    celix_filter_destroy(entry->filter);
-    celix_arrayList_destroy(entry->retainedReferences);
-    celixThreadMutex_destroy(&entry->mutex);
-    celixThreadCondition_destroy(&entry->useCond);
-    free(entry);
-}
-
 framework_logger_pt logger;
 
 static celix_thread_once_t loggerInit = CELIX_THREAD_ONCE_INIT;
@@ -312,7 +246,6 @@ celix_status_t framework_create(framework_pt *framework, properties_pt config) {
         status = CELIX_DO_IF(status, celixThreadCondition_init(&(*framework)->shutdown.cond, NULL));
         status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->shutdown.mutex, NULL));
         status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->dispatcher.mutex, NULL));
-        status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->serviceListenersLock, &attr));
         status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->frameworkListenersLock, &attr));
         status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->bundleListenerLock, NULL));
         status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->installedBundles.mutex, NULL));
@@ -327,7 +260,6 @@ celix_status_t framework_create(framework_pt *framework, properties_pt config) {
             (*framework)->cache = NULL;
             (*framework)->installRequestMap = hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals);
             (*framework)->installedBundles.entries = celix_arrayList_create();
-            (*framework)->serviceListeners = NULL;
             (*framework)->bundleListeners = NULL;
             (*framework)->frameworkListeners = NULL;
             (*framework)->dispatcher.requests = NULL;
@@ -415,15 +347,6 @@ celix_status_t framework_destroy(framework_pt framework) {
 
 	serviceRegistry_destroy(framework->registry);
 
-    if (framework->serviceListeners != NULL) {
-        int size = celix_arrayList_size(framework->serviceListeners);
-        for (int i = 0; i < size; ++i) {
-            celix_fw_service_listener_entry_t *entry = celix_arrayList_get(framework->serviceListeners, i);
-            listener_release(entry);
-            listener_waitAndDestroy(framework, entry);
-        }
-        arrayList_destroy(framework->serviceListeners);
-    }
     if (framework->bundleListeners) {
         arrayList_destroy(framework->bundleListeners);
     }
@@ -444,7 +367,6 @@ celix_status_t framework_destroy(framework_pt framework) {
 	bundleCache_destroy(&framework->cache);
 
 	celixThreadCondition_destroy(&framework->dispatcher.cond);
-    celixThreadMutex_destroy(&framework->serviceListenersLock);
     celixThreadMutex_destroy(&framework->frameworkListenersLock);
 	celixThreadMutex_destroy(&framework->bundleListenerLock);
 	celixThreadMutex_destroy(&framework->dispatcher.mutex);
@@ -481,7 +403,6 @@ celix_status_t fw_init(framework_pt framework) {
     properties_set(framework->configurationMap, (char*) OSGI_FRAMEWORK_FRAMEWORK_UUID, uuid);
 
 	celix_status_t status = CELIX_SUCCESS;
-	status = CELIX_DO_IF(status, arrayList_create(&framework->serviceListeners)); //entry is celix_fw_service_listener_entry_t
 	status = CELIX_DO_IF(status, arrayList_create(&framework->bundleListeners));
 	status = CELIX_DO_IF(status, arrayList_create(&framework->frameworkListeners));
 	status = CELIX_DO_IF(status, arrayList_create(&framework->dispatcher.requests));
@@ -547,7 +468,7 @@ celix_status_t fw_init(framework_pt framework) {
         arrayList_destroy(archives);
     }
 
-    status = CELIX_DO_IF(status, serviceRegistry_create(framework, fw_serviceChanged, &framework->registry));
+    status = CELIX_DO_IF(status, serviceRegistry_create(framework, &framework->registry));
     status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_STARTING));
 
     bundle_context_t *context = NULL;
@@ -803,9 +724,9 @@ celix_status_t fw_installBundle2(framework_pt framework, bundle_pt * bundle, lon
         if (status == CELIX_SUCCESS) {
             long bndId = -1L;
             bundle_getBundleId(*bundle, &bndId);
-            celix_framework_bundle_entry_t *entry = fw_bundleEntry_create(*bundle);
+            celix_framework_bundle_entry_t *bEntry = fw_bundleEntry_create(*bundle);
             celixThreadMutex_lock(&framework->installedBundles.mutex);
-            celix_arrayList_add(framework->installedBundles.entries, entry);
+            celix_arrayList_add(framework->installedBundles.entries, bEntry);
             celixThreadMutex_unlock(&framework->installedBundles.mutex);
 
         } else {
@@ -1445,7 +1366,7 @@ celix_status_t fw_populateDependentGraph(framework_pt framework, bundle_pt expor
     return status;
 }
 
-celix_status_t fw_registerService(framework_pt framework, service_registration_pt *registration, long bndId, const char* serviceName, const void* svcObj, properties_pt properties) {
+celix_status_t fw_registerService(framework_pt framework, service_registration_pt *registration, long bndId, const char* serviceName, const void* svcObj, celix_properties_t *properties) {
 	celix_status_t status = CELIX_SUCCESS;
 	char *error = NULL;
 	if (serviceName == NULL || svcObj == NULL) {
@@ -1454,79 +1375,9 @@ celix_status_t fw_registerService(framework_pt framework, service_registration_p
 	}
 
     celix_framework_bundle_entry_t *entry = fw_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, bndId);
-
-
-
     status = CELIX_DO_IF(status, serviceRegistry_registerService(framework->registry, entry->bnd, serviceName, svcObj, properties, registration));
-
-	if (status == CELIX_SUCCESS) {
-	    // If this is a listener hook, invoke the callback with all current listeners
-        if (strcmp(serviceName, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME) == 0) {
-            unsigned int i;
-            array_list_pt infos = NULL;
-            service_reference_pt ref = NULL;
-            listener_hook_service_pt hook = NULL;
-
-            status = CELIX_DO_IF(status, arrayList_create(&infos));
-
-            if (status == CELIX_SUCCESS) {
-                celix_status_t subs = CELIX_SUCCESS;
-
-                celixThreadMutex_lock(&framework->serviceListenersLock);
-                for (i = 0; i < arrayList_size(framework->serviceListeners); i++) {
-                    celix_fw_service_listener_entry_t *listener = arrayList_get(framework->serviceListeners, i);
-                    bundle_context_t *context = NULL;
-                    listener_hook_info_pt info = NULL;
-                    bundle_context_pt lContext = NULL;
-
-                    subs = CELIX_DO_IF(subs, bundle_getContext(entry->bnd, &context));
-                    if (subs == CELIX_SUCCESS) {
-                        info = (listener_hook_info_pt) malloc(sizeof(*info));
-                        if (info == NULL) {
-                            subs = CELIX_ENOMEM;
-                        }
-                    }
-
-                    subs = CELIX_DO_IF(subs, bundle_getContext(listener->bundle, &lContext));
-                    if (subs == CELIX_SUCCESS) {
-                        info->context = lContext;
-                        info->removed = false;
-                    }
-                    subs = CELIX_DO_IF(subs, filter_getString(listener->filter, &info->filter));
-
-                    if (subs == CELIX_SUCCESS) {
-                        arrayList_add(infos, info);
-                    }
-                    else{
-                        fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not pass all listeners to the hook: %s", serviceName);
-                        free(info);
-                    }
-                }
-                celixThreadMutex_unlock(&framework->serviceListenersLock);
-
-                status = CELIX_DO_IF(status, serviceRegistry_getServiceReference(framework->registry, framework->bundle,
-                                                                                 *registration, &ref));
-                status = CELIX_DO_IF(status, fw_getService(framework,framework->bundle, ref, (const void **) &hook));
-                if (status == CELIX_SUCCESS) {
-                    hook->added(hook->handle, infos);
-                }
-                status = CELIX_DO_IF(status, serviceRegistry_ungetService(framework->registry, framework->bundle, ref, NULL));
-                status = CELIX_DO_IF(status, serviceRegistry_ungetServiceReference(framework->registry, framework->bundle, ref));
-
-                for (int j = 0; j < arrayList_size(infos); j++) {
-                    listener_hook_info_pt info = arrayList_get(infos, j);
-                    free(info);
-                }
-                arrayList_destroy(infos);
-             }
-        }
-	}
-
-
 	fw_bundleEntry_decreaseUseCount(entry);
-
     framework_logIfError(framework->logger, status, error, "Cannot register service: %s", serviceName);
-
 	return status;
 }
 
@@ -1611,45 +1462,11 @@ celix_status_t framework_ungetService(framework_pt framework, bundle_pt bundle,
 }
 
 void fw_addServiceListener(framework_pt framework, bundle_pt bundle, celix_service_listener_t *listener, const char* sfilter) {
-    celix_fw_service_listener_entry_t *fwListener = listener_create(bundle, sfilter, listener);
-
-    celixThreadMutex_lock(&framework->serviceListenersLock);
-	arrayList_add(framework->serviceListeners, fwListener);
-    celixThreadMutex_unlock(&framework->serviceListenersLock);
-
-    serviceRegistry_callHooksForListenerFilter(framework->registry, bundle, sfilter, false);
+    celix_serviceRegistry_addServiceListener(framework->registry, bundle, sfilter, listener);
 }
 
-void fw_removeServiceListener(framework_pt framework, bundle_pt bundle, celix_service_listener_t *listener) {
-    celix_fw_service_listener_entry_t *match = NULL;
-
-    bundle_context_t *context;
-    bundle_getContext(bundle, &context);
-
-    int i;
-    celixThreadMutex_lock(&framework->serviceListenersLock);
-    for (i = 0; i < arrayList_size(framework->serviceListeners); i++) {
-        celix_fw_service_listener_entry_t *visit = (celix_fw_service_listener_entry_t*) arrayList_get(framework->serviceListeners, i);
-        if (visit->listener == listener && visit->bundle == bundle) {
-            match = visit;
-            arrayList_remove(framework->serviceListeners, i);
-            break;
-        }
-    }
-    celixThreadMutex_unlock(&framework->serviceListenersLock);
-
-
-    if (match != NULL) {
-        //invoke listener hooks
-        const char *filter;
-        filter_getString(match->filter, &filter);
-        serviceRegistry_callHooksForListenerFilter(framework->registry, bundle, filter, true);
-    }
-
-    if (match != NULL) {
-        listener_release(match);
-        listener_waitAndDestroy(framework, match);
-    }
+void fw_removeServiceListener(framework_pt framework, bundle_pt bundle __attribute__((unused)), celix_service_listener_t *listener) {
+    celix_serviceRegistry_removeServiceListener(framework->registry, listener);
 }
 
 celix_status_t fw_addBundleListener(framework_pt framework, bundle_pt bundle, bundle_listener_pt listener) {
@@ -1754,91 +1571,6 @@ celix_status_t fw_removeFrameworkListener(framework_pt framework, bundle_pt bund
     return status;
 }
 
-void fw_serviceChanged(framework_pt framework, celix_service_event_type_t eventType, service_registration_pt registration, properties_pt oldprops) {
-    unsigned int i;
-    celix_fw_service_listener_entry_t *entry;
-
-    celix_array_list_t* retainedEntries = celix_arrayList_create();
-    celix_array_list_t* matchedEntries = celix_arrayList_create();
-
-    celixThreadMutex_lock(&framework->serviceListenersLock);
-    for (i = 0; i < celix_arrayList_size(framework->serviceListeners); i++) {
-        entry = (celix_fw_service_listener_entry_t *) celix_arrayList_get(framework->serviceListeners, i);
-        celix_arrayList_add(retainedEntries, entry);
-        listener_retain(entry); //ensure that use count > 0, so that the listener cannot be destroyed until all pending event are handled.
-    }
-    celixThreadMutex_unlock(&framework->serviceListenersLock);
-
-    for (i = 0; i < celix_arrayList_size(retainedEntries); ++i) {
-        entry = (celix_fw_service_listener_entry_t *) celix_arrayList_get(retainedEntries, i);
-        int matched = 0;
-        properties_pt props = NULL;
-        bool matchResult = false;
-        serviceRegistration_getProperties(registration, &props);
-        if (entry->filter != NULL) {
-            filter_match(entry->filter, props, &matchResult);
-        }
-        matched = (entry->filter == NULL) || matchResult;
-        if (matched) {
-            celix_arrayList_add(matchedEntries, entry);
-        } else {
-            listener_release(entry); //Not a match -> release entry
-        }
-    }
-    celix_arrayList_destroy(retainedEntries);
-
-    /*
-     * TODO FIXME, A deadlock can happen when (e.g.) a service is deregistered, triggering this fw_serviceChanged and
-     * one of the matching service listener callback tries to remove an other matched service listener.
-     * The remove service listener will call the listener_waitForDestroy and the fw_serviceChanged part keeps the
-     * usageCount on > 0.
-     *
-     * Not sure how to prevent/handle this.
-     */
-    for (i = 0; i < celix_arrayList_size(matchedEntries); ++i) {
-        entry = (celix_fw_service_listener_entry_t *) celix_arrayList_get(matchedEntries, i);
-
-        service_reference_pt reference = NULL;
-        celix_service_event_t event;
-
-        serviceRegistry_getServiceReference(framework->registry, entry->bundle, registration, &reference);
-
-        //NOTE: that you are never sure that the UNREGISTERED event will by handle by an service_listener. listener could be gone
-        //Every reference retained is therefore stored and called when a service listener is removed from the framework.
-        if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) {
-            serviceRegistry_retainServiceReference(framework->registry, entry->bundle, reference);
-            celixThreadMutex_lock(&entry->mutex);
-            arrayList_add(entry->retainedReferences, reference); //TODO improve by using set (or hashmap) instead of list
-            celixThreadMutex_unlock(&entry->mutex);
-        }
-
-        event.type = eventType;
-        event.reference = reference;
-
-        entry->listener->serviceChanged(entry->listener, &event);
-
-        serviceRegistry_ungetServiceReference(framework->registry, entry->bundle, reference);
-
-        if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
-            //if service listener was active when service was registered, release the retained reference
-            celixThreadMutex_lock(&entry->mutex);
-            bool removed = arrayList_removeElement(entry->retainedReferences, reference);
-            celixThreadMutex_unlock(&entry->mutex);
-            if (removed) {
-                serviceRegistry_ungetServiceReference(framework->registry, entry->bundle,
-                                                      reference); // decrease retain counter
-            }
-
-        }
-
-        if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED) {
-            entry->listener->serviceChanged(entry->listener, &event);
-        }
-        listener_release(entry); //decrease usage, so that the listener can be destroyed (if use count is now 0)
-    }
-    celix_arrayList_destroy(matchedEntries);
-}
-
 //celix_status_t fw_isServiceAssignable(framework_pt fw, bundle_pt requester, service_reference_pt reference, bool *assignable) {
 //	celix_status_t status = CELIX_SUCCESS;
 //
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index 537a040..fdd0132 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -49,9 +49,6 @@ struct celix_framework {
     long bundleId; //the bundle id of the framework (normally 0)
     hash_map_pt installRequestMap;
 
-    celix_thread_mutex_t serviceListenersLock;
-    array_list_pt serviceListeners;
-
     array_list_pt frameworkListeners;
     celix_thread_mutex_t frameworkListenersLock;
 
diff --git a/libs/framework/src/registry_callback_private.h b/libs/framework/src/registry_callback_private.h
index f286a07..ff030bb 100644
--- a/libs/framework/src/registry_callback_private.h
+++ b/libs/framework/src/registry_callback_private.h
@@ -35,7 +35,6 @@ typedef struct registry_callback_struct {
 	void *handle;
     celix_status_t (*getUsingBundles)(void *handle, service_registration_pt reg, array_list_pt *bundles);
 	celix_status_t (*unregister)(void *handle, bundle_pt bundle, service_registration_pt reg);
-	celix_status_t (*modified)(void *handle, service_registration_pt registration, properties_pt oldProperties);
 } registry_callback_t;
 
 #endif /* REGISTRY_CALLBACK_H_ */
diff --git a/libs/framework/src/service_reference.c b/libs/framework/src/service_reference.c
index 2394634..f7d6879 100644
--- a/libs/framework/src/service_reference.c
+++ b/libs/framework/src/service_reference.c
@@ -204,6 +204,18 @@ celix_status_t serviceReference_getServiceRegistration(service_reference_pt ref,
     }
 }
 
+long serviceReference_getServiceId(service_reference_pt ref) {
+    long svcId = -1L;
+    if (ref != NULL) {
+        celixThreadRwlock_readLock(&ref->lock);
+        svcId = ref->registration->serviceId;
+        celixThreadRwlock_unlock(&ref->lock);
+    }
+    return svcId;
+}
+
+
+
 FRAMEWORK_EXPORT celix_status_t
 serviceReference_getPropertyWithDefault(service_reference_pt ref, const char *key, const char* def, const char **value) {
     celix_status_t status = CELIX_SUCCESS;
diff --git a/libs/framework/src/service_registration.c b/libs/framework/src/service_registration.c
index 3400134..745148e 100644
--- a/libs/framework/src/service_registration.c
+++ b/libs/framework/src/service_registration.c
@@ -231,19 +231,10 @@ celix_status_t serviceRegistration_getProperties(service_registration_pt registr
 celix_status_t serviceRegistration_setProperties(service_registration_pt registration, properties_pt properties) {
     celix_status_t status;
 
-    properties_pt oldProperties = NULL;
-    registry_callback_t callback;
-
     celixThreadRwlock_writeLock(&registration->lock);
-    oldProperties = registration->properties;
     status = serviceRegistration_initializeProperties(registration, properties);
-    callback = registration->callback;
     celixThreadRwlock_unlock(&registration->lock);
 
-    if (status == CELIX_SUCCESS && callback.modified != NULL) {
-        callback.modified(callback.handle, registration, oldProperties);
-    }
-
 	return status;
 }
 
diff --git a/libs/framework/src/service_registration_private.h b/libs/framework/src/service_registration_private.h
index 6040f24..9ecb760 100644
--- a/libs/framework/src/service_registration_private.h
+++ b/libs/framework/src/service_registration_private.h
@@ -16,13 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * service_registration_private.h
- *
- *  \date       Feb 11, 2013
- *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright  Apache License, Version 2.0
- */
+
 
 #ifndef SERVICE_REGISTRATION_PRIVATE_H_
 #define SERVICE_REGISTRATION_PRIVATE_H_
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index 135a636..7ffa0eb 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -49,13 +49,23 @@ static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt reg
                                                   bool deleted);
 static celix_status_t serviceRegistry_getUsingBundles(service_registry_pt registry, service_registration_pt reg, array_list_pt *bundles);
 static celix_status_t serviceRegistry_getServiceReference_internal(service_registry_pt registry, bundle_pt owner, service_registration_pt registration, service_reference_pt *out);
+static void celix_serviceRegistry_serviceChanged(celix_service_registry_t *registry, celix_service_event_type_t eventType, service_registration_pt registration);
+static void serviceRegistry_callHooksForListenerFilter(service_registry_pt registry, celix_bundle_t *owner, const celix_filter_t *filter, bool removed);
 
-static celix_service_registry_listener_hook_entry_t* celix_createHookEntry(long svcId, celix_listener_hook_service_t*);
+    static celix_service_registry_listener_hook_entry_t* celix_createHookEntry(long svcId, celix_listener_hook_service_t*);
 static void celix_waitAndDestroyHookEntry(celix_service_registry_listener_hook_entry_t *entry);
 static void celix_increaseCountHook(celix_service_registry_listener_hook_entry_t *entry);
 static void celix_decreaseCountHook(celix_service_registry_listener_hook_entry_t *entry);
 
-celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_function_pt serviceChanged, service_registry_pt *out) {
+static void celix_increaseCountServiceListener(celix_service_registry_service_listener_entry_t *entry);
+static void celix_decreaseCountServiceListener(celix_service_registry_service_listener_entry_t *entry);
+static void celix_waitAndDestroyServiceListener(celix_service_registry_service_listener_entry_t *entry);
+
+static void celix_increasePendingRegisteredEvent(celix_service_registry_t *registry, long svcId);
+static void celix_decreasePendingRegisteredEvent(celix_service_registry_t *registry, long svcId);
+static void celix_waitForPendingRegisteredEvents(celix_service_registry_t *registry, long svcId);
+
+celix_status_t serviceRegistry_create(framework_pt framework, service_registry_pt *out) {
 	celix_status_t status;
 
 	service_registry_pt reg = calloc(1, sizeof(*reg));
@@ -66,9 +76,7 @@ celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_fun
         reg->callback.handle = reg;
         reg->callback.getUsingBundles = (void *)serviceRegistry_getUsingBundles;
         reg->callback.unregister = (void *) serviceRegistry_unregisterService;
-        reg->callback.modified = (void *) serviceRegistry_servicePropertiesModified;
 
-        reg->serviceChanged = serviceChanged;
 		reg->serviceRegistrations = hashMap_create(NULL, NULL, NULL, NULL);
 		reg->framework = framework;
 		reg->currentServiceId = 1UL;
@@ -77,7 +85,12 @@ celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_fun
         reg->checkDeletedReferences = CHECK_DELETED_REFERENCES;
         reg->deletedServiceReferences = hashMap_create(NULL, NULL, NULL, NULL);
 
-		arrayList_create(&reg->listenerHooks);
+		reg->listenerHooks = celix_arrayList_create();
+		reg->serviceListeners = celix_arrayList_create();
+
+		celixThreadMutex_create(&reg->pendingRegisterEvents.mutex, NULL);
+		celixThreadCondition_init(&reg->pendingRegisterEvents.cond, NULL);
+		reg->pendingRegisterEvents.map = hashMap_create(NULL, NULL, NULL, NULL);
 
 		status = celixThreadRwlock_create(&reg->lock, NULL);
 	}
@@ -94,36 +107,44 @@ celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_fun
 celix_status_t serviceRegistry_destroy(service_registry_pt registry) {
     celixThreadRwlock_writeLock(&registry->lock);
 
+    //remove service listeners
+    int size = celix_arrayList_size(registry->serviceListeners);
+    if (size > 0) {
+        fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "%i dangling service listeners\n", size);
+    }
+    for (int i = 0; i < size; ++i) {
+        celix_service_registry_service_listener_entry_t *entry = celix_arrayList_get(registry->serviceListeners, i);
+        celix_decreaseCountServiceListener(entry);
+        celix_waitAndDestroyServiceListener(entry);
+    }
+    arrayList_destroy(registry->serviceListeners);
+
     //destroy service registration map
-    int size = hashMap_size(registry->serviceRegistrations);
+    size = hashMap_size(registry->serviceRegistrations);
     if (size > 0) {
         fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "%i bundles with dangling service registration\n", size);
-        hash_map_iterator_t iter = hashMapIterator_construct(registry->serviceRegistrations);
-        while (hashMapIterator_hasNext(&iter)) {
-            hash_map_entry_t *entry = hashMapIterator_nextEntry(&iter);
-            bundle_t *bnd = hashMapEntry_getKey(entry);
-            celix_array_list_t *registrations = hashMapEntry_getValue(entry);
-            module_pt mod = NULL;
-            const char *name = NULL;
-            bundle_getCurrentModule(bnd, &mod);
-            if (mod != NULL) {
-                module_getSymbolicName(mod, &name);
-            }
-            for (int i = 0; i < celix_arrayList_size(registrations); ++i) {
-                service_registration_pt reg = celix_arrayList_get(registrations, i);
-                const char *svcName = NULL;
-                serviceRegistration_getServiceName(reg, &svcName);
-                fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Bundle %s still has a %s service registered\n", name, svcName);
-            }
+    }
+    hash_map_iterator_t iter = hashMapIterator_construct(registry->serviceRegistrations);
+    while (hashMapIterator_hasNext(&iter)) {
+        hash_map_entry_t *entry = hashMapIterator_nextEntry(&iter);
+        celix_bundle_t *bnd = hashMapEntry_getKey(entry);
+        celix_array_list_t *registrations = hashMapEntry_getValue(entry);
+        for (int i = 0; i < celix_arrayList_size(registrations); ++i) {
+            service_registration_pt reg = celix_arrayList_get(registrations, i);
+            const char *svcName = NULL;
+            serviceRegistration_getServiceName(reg, &svcName);
+            fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Bundle %s (bundle id: %li) still has a %s service registered\n", celix_bundle_getSymbolicName(bnd), celix_bundle_getId(bnd), svcName);
         }
     }
+
     assert(size == 0);
     hashMap_destroy(registry->serviceRegistrations, false, false);
 
     //destroy service references (double) map);
-    //FIXME. The framework bundle does not (yet) call clearReferences, as result the size could be > 0 for test code.
-    //size = hashMap_size(registry->serviceReferences);
-    //assert(size == 0);
+    size = hashMap_size(registry->serviceReferences);
+    if (size > 0) {
+        fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unexpected service references left in the service registry! Nr of references: %i", size);
+    }
     hashMap_destroy(registry->serviceReferences, false, false);
 
     //destroy listener hooks
@@ -136,6 +157,12 @@ celix_status_t serviceRegistry_destroy(service_registry_pt registry) {
 
     hashMap_destroy(registry->deletedServiceReferences, false, false);
 
+    size = hashMap_size(registry->pendingRegisterEvents.map);
+    assert(size == 0);
+    celixThreadMutex_destroy(&registry->pendingRegisterEvents.mutex);
+    celixThreadCondition_destroy(&registry->pendingRegisterEvents.cond);
+    hashMap_destroy(registry->pendingRegisterEvents.map, false, false);
+
     free(registry);
 
     return CELIX_SUCCESS;
@@ -190,11 +217,8 @@ static celix_status_t serviceRegistry_registerServiceInternal(service_registry_p
 	} else { //plain
 	    *registration = serviceRegistration_create(registry->callback, bundle, serviceName, ++registry->currentServiceId, serviceObject, dictionary);
 	}
-
-    //long id;
-    //bundle_getBundleId(bundle, &id);
-    //fprintf(stderr, "REG: Registering service '%s' for bundle id %li with reg pointer %p\n", serviceName, id, *registration);
-
+    long svcId = serviceRegistration_getServiceId(*registration);
+	//printf("Registering service %li with name %s\n", svcId, serviceName);
 
     serviceRegistry_addHooks(registry, serviceName, serviceObject, *registration);
 
@@ -206,41 +230,56 @@ static celix_status_t serviceRegistry_registerServiceInternal(service_registry_p
         hashMap_put(registry->serviceRegistrations, bundle, regs);
     }
 	arrayList_add(regs, *registration);
-	celixThreadRwlock_unlock(&registry->lock);
 
-	if (registry->serviceChanged != NULL) {
-		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED, *registration, NULL);
-	}
+    //update pending register event
+    celix_increasePendingRegisteredEvent(registry, svcId);
+    celixThreadRwlock_unlock(&registry->lock);
+
+
+    //NOTE there is a race condition with celix_serviceRegistry_addServiceListener, as result
+    //a REGISTERED event can be triggered twice instead of once. The service tracker can deal with this.
+    //The handling of pending registered events is to ensure that the UNREGISTERING event is always
+    //after the 1 or 2 REGISTERED events.
+
+	celix_serviceRegistry_serviceChanged(registry, OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED, *registration);
+    //update pending register event count
+    celix_decreasePendingRegisteredEvent(registry, svcId);
 
 	return CELIX_SUCCESS;
 }
 
 celix_status_t serviceRegistry_unregisterService(service_registry_pt registry, bundle_pt bundle, service_registration_pt registration) {
 	// array_list_t clients;
-	array_list_pt regs;
+	celix_array_list_t *regs;
 
     //fprintf(stderr, "REG: Unregistering service registration with pointer %p\n", registration);
 
+    long svcId = serviceRegistration_getServiceId(registration);
+    const char *svcName = NULL;
+    serviceRegistration_getServiceName(registration, &svcName);
+    //printf("Unregistering service %li with name %s\n", svcId, svcName);
+
 	serviceRegistry_removeHook(registry, registration);
 
 	celixThreadRwlock_writeLock(&registry->lock);
-	regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle);
+	regs = (celix_array_list_t*) hashMap_get(registry->serviceRegistrations, bundle);
 	if (regs != NULL) {
 		arrayList_removeElement(regs, registration);
         int size = arrayList_size(regs);
         if (size == 0) {
-            arrayList_destroy(regs);
+            celix_arrayList_destroy(regs);
             hashMap_remove(registry->serviceRegistrations, bundle);
         }
 	}
 	celixThreadRwlock_unlock(&registry->lock);
 
-	if (registry->serviceChanged != NULL) {
-		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING, registration, NULL);
-	}
 
+    //check and wait for pending register events
+    celix_waitForPendingRegisteredEvents(registry, svcId);
+
+    celix_serviceRegistry_serviceChanged(registry, OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING, registration);
 
-	celixThreadRwlock_readLock(&registry->lock);
+    celixThreadRwlock_readLock(&registry->lock);
     //invalidate service references
     hash_map_iterator_pt iter = hashMapIterator_create(registry->serviceReferences);
     while (hashMapIterator_hasNext(iter)) {
@@ -308,7 +347,7 @@ celix_status_t serviceRegistry_getServiceReference(service_registry_pt registry,
                                                    service_registration_pt registration, service_reference_pt *out) {
 	celix_status_t status = CELIX_SUCCESS;
 
-	if(celixThreadRwlock_writeLock(&registry->lock) == CELIX_SUCCESS) {
+	if (celixThreadRwlock_writeLock(&registry->lock) == CELIX_SUCCESS) {
 	    status = serviceRegistry_getServiceReference_internal(registry, owner, registration, out);
 	    celixThreadRwlock_unlock(&registry->lock);
 	}
@@ -566,22 +605,16 @@ static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registr
     }
 
     if(usageCount > 0 || refCount > 0) {
-        module_pt module_ptr = NULL;
-        bundle_getCurrentModule(bundle, &module_ptr);
-        const char* bundle_name = NULL;
-        module_getSymbolicName(module_ptr, &bundle_name);
-
+        const char* bundle_name = celix_bundle_getSymbolicName(bundle);
         const char* service_name = "unknown";
         const char* bundle_provider_name = "unknown";
         if (refCount > 0 && ref != NULL) {
             serviceReference_getProperty(ref, OSGI_FRAMEWORK_OBJECTCLASS, &service_name);
             service_registration_pt reg = NULL;
-            bundle_pt bundle = NULL;
-            module_pt mod = NULL;
+            bundle_pt providedBnd = NULL;
             serviceReference_getServiceRegistration(ref, &reg);
-            serviceRegistration_getBundle(reg, &bundle);
-            bundle_getCurrentModule(bundle, &mod);
-            module_getSymbolicName(mod, &bundle_provider_name);
+            serviceRegistration_getBundle(reg, &providedBnd);
+            bundle_provider_name = celix_bundle_getSymbolicName(providedBnd);
         }
 
         fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Previous Dangling service reference warnings caused by bundle '%s', for service '%s', provided by bundle '%s'", bundle_name, service_name, bundle_provider_name);
@@ -779,14 +812,14 @@ static celix_status_t serviceRegistry_removeHook(service_registry_pt registry, s
 	return status;
 }
 
-void serviceRegistry_callHooksForListenerFilter(service_registry_pt registry, celix_bundle_t *owner, const char *filter, bool removed) {
+static void serviceRegistry_callHooksForListenerFilter(service_registry_pt registry, celix_bundle_t *owner, const celix_filter_t *filter, bool removed) {
     celix_bundle_context_t *ctx;
     bundle_getContext(owner, &ctx);
 
     struct listener_hook_info info;
     info.context = ctx;
     info.removed = removed;
-    info.filter = filter;
+    info.filter = celix_filter_getFilterString(filter);
     celix_array_list_t *infos = celix_arrayList_create();
     celix_arrayList_add(infos, &info);
 
@@ -823,13 +856,6 @@ size_t serviceRegistry_nrOfHooks(service_registry_pt registry) {
     return (size_t) size;
 }
 
-celix_status_t serviceRegistry_servicePropertiesModified(service_registry_pt registry, service_registration_pt registration, properties_pt oldprops) {
-	if (registry->serviceChanged != NULL) {
-		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED, registration, oldprops);
-	}
-	return CELIX_SUCCESS;
-}
-
 static celix_status_t serviceRegistry_getUsingBundles(service_registry_pt registry, service_registration_pt registration, array_list_pt *out) {
     celix_status_t status;
     array_list_pt bundles = NULL;
@@ -886,12 +912,12 @@ static void celix_waitAndDestroyHookEntry(celix_service_registry_listener_hook_e
     if (entry != NULL) {
         celixThreadMutex_lock(&entry->mutex);
         int waitCount = 0;
-        while (entry->count > 0) {
+        while (entry->useCount > 0) {
             celixThreadCondition_timedwaitRelative(&entry->cond, &entry->mutex, 1, 0); //wait for 1 second
             waitCount += 1;
             if (waitCount >= 5) {
                 fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING,
-                        "Still waiting for service listener hook use count to become zero. Waiting for %i seconds. Use Count is %i, svc id is %li", waitCount, (int)entry->count, entry->svcId);
+                        "Still waiting for service listener hook use count to become zero. Waiting for %i seconds. Use Count is %i, svc id is %li", waitCount, (int)entry->useCount, entry->svcId);
             }
         }
         celixThreadMutex_unlock(&entry->mutex);
@@ -905,7 +931,7 @@ static void celix_waitAndDestroyHookEntry(celix_service_registry_listener_hook_e
 static void celix_increaseCountHook(celix_service_registry_listener_hook_entry_t *entry) {
     if (entry != NULL) {
         celixThreadMutex_lock(&entry->mutex);
-        entry->count += 1;
+        entry->useCount += 1;
         celixThreadCondition_broadcast(&entry->cond);
         celixThreadMutex_unlock(&entry->mutex);
     }
@@ -913,12 +939,46 @@ static void celix_increaseCountHook(celix_service_registry_listener_hook_entry_t
 static void celix_decreaseCountHook(celix_service_registry_listener_hook_entry_t *entry) {
     if (entry != NULL) {
         celixThreadMutex_lock(&entry->mutex);
-        entry->count -= 1;
+        entry->useCount -= 1;
+        celixThreadCondition_broadcast(&entry->cond);
+        celixThreadMutex_unlock(&entry->mutex);
+    }
+}
+
+static void celix_increaseCountServiceListener(celix_service_registry_service_listener_entry_t *entry) {
+    if (entry != NULL) {
+        celixThreadMutex_lock(&entry->mutex);
+        entry->useCount += 1;
+        celixThreadCondition_broadcast(&entry->cond);
+        celixThreadMutex_unlock(&entry->mutex);
+    }
+}
+
+static void celix_decreaseCountServiceListener(celix_service_registry_service_listener_entry_t *entry) {
+    if (entry != NULL) {
+        celixThreadMutex_lock(&entry->mutex);
+        entry->useCount -= 1;
         celixThreadCondition_broadcast(&entry->cond);
         celixThreadMutex_unlock(&entry->mutex);
     }
 }
 
+static inline void celix_waitAndDestroyServiceListener(celix_service_registry_service_listener_entry_t *entry) {
+    celixThreadMutex_lock(&entry->mutex);
+    while (entry->useCount != 0) {
+        celixThreadCondition_wait(&entry->cond, &entry->mutex);
+    }
+    celixThreadMutex_unlock(&entry->mutex);
+
+    //use count == 0 -> safe to destroy.
+    //destroy
+    celixThreadMutex_destroy(&entry->mutex);
+    celixThreadCondition_destroy(&entry->cond);
+    celix_filter_destroy(entry->filter);
+    free(entry);
+}
+
+
 celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId) {
     celix_array_list_t *result = celix_arrayList_create();
     celixThreadRwlock_readLock(&registry->lock);
@@ -972,4 +1032,249 @@ bool celix_serviceRegistry_getServiceInfo(
     celixThreadRwlock_unlock(&registry->lock);
 
     return found;
-}
\ No newline at end of file
+}
+
+celix_status_t celix_serviceRegistry_addServiceListener(celix_service_registry_t *registry, celix_bundle_t *bundle, const char *stringFilter, celix_service_listener_t *listener) {
+
+    celix_filter_t *filter = NULL;
+    if (stringFilter != NULL) {
+        filter = celix_filter_create(stringFilter);
+        if (filter == NULL) {
+            fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Cannot add service listener filter '%s' is invalid", stringFilter);
+            return CELIX_ILLEGAL_ARGUMENT;
+        }
+    }
+
+    celix_service_registry_service_listener_entry_t *entry = calloc(1, sizeof(*entry));
+    entry->bundle = bundle;
+    entry->filter = filter;
+    entry->listener = listener;
+    entry->useCount = 1; //new entry -> count on 1
+    celixThreadMutex_create(&entry->mutex, NULL);
+    celixThreadCondition_init(&entry->cond, NULL);
+
+    celix_array_list_t *registrations =  celix_arrayList_create();
+
+    celixThreadRwlock_writeLock(&registry->lock);
+    celix_arrayList_add(registry->serviceListeners, entry); //use count 1
+
+    //find already registered services
+    hash_map_iterator_t iter = hashMapIterator_construct(registry->serviceRegistrations);
+    while (hashMapIterator_hasNext(&iter)) {
+        celix_array_list_t *regs = (array_list_pt) hashMapIterator_nextValue(&iter);
+        for (int regIdx = 0; (regs != NULL) && regIdx < celix_arrayList_size(regs); ++regIdx) {
+            service_registration_pt registration = celix_arrayList_get(regs, regIdx);
+            properties_pt props = NULL;
+            serviceRegistration_getProperties(registration, &props);
+            if (celix_filter_match(filter, props)) {
+                serviceRegistration_retain(registration);
+                long svcId = serviceRegistration_getServiceId(registration);
+                celix_arrayList_add(registrations, registration);
+                //update pending register event count
+                celix_increasePendingRegisteredEvent(registry, svcId);
+            }
+        }
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    //NOTE there is a race condition with serviceRegistry_registerServiceInternal, as result
+    //a REGISTERED event can be triggered twice instead of once. The service tracker can deal with this.
+    //The handling of pending registered events is to ensure that the UNREGISTERING event is always
+    //after the 1 or 2 REGISTERED events.
+
+    for (int i = 0; i < celix_arrayList_size(registrations); ++i) {
+        service_registration_pt reg = celix_arrayList_get(registrations, i);
+        long svcId = serviceRegistration_getServiceId(reg);
+        service_reference_pt ref = NULL;
+        serviceRegistry_getServiceReference_internal(registry, bundle, reg, &ref);
+        celix_service_event_t event;
+        event.reference = ref;
+        event.type = OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED;
+        listener->serviceChanged(listener->handle, &event);
+        serviceReference_release(ref, NULL);
+        serviceRegistration_release(reg);
+
+        //update pending register event count
+        celix_decreasePendingRegisteredEvent(registry, svcId);
+    }
+    celix_arrayList_destroy(registrations);
+
+    serviceRegistry_callHooksForListenerFilter(registry, bundle, entry->filter, false);
+
+    celix_decreaseCountServiceListener(entry); //use count decreased, can be 0
+    return CELIX_SUCCESS;
+}
+
+celix_status_t celix_serviceRegistry_removeServiceListener(celix_service_registry_t *registry, celix_service_listener_t *listener) {
+    celix_service_registry_service_listener_entry_t *entry = NULL;
+
+    celixThreadRwlock_writeLock(&registry->lock);
+    for (int i = 0; i < celix_arrayList_size(registry->serviceListeners); ++i) {
+        celix_service_registry_service_listener_entry_t *visit = celix_arrayList_get(registry->serviceListeners, i);
+        if (visit->listener == listener) {
+            entry = visit;
+            celix_arrayList_removeAt(registry->serviceListeners, i);
+            break;
+        }
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    if (entry != NULL) {
+        serviceRegistry_callHooksForListenerFilter(registry, entry->bundle, entry->filter, true);
+        celix_waitAndDestroyServiceListener(entry);
+    } else {
+        fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Cannot remove service listener, listener not found");
+        return CELIX_ILLEGAL_ARGUMENT;
+    }
+    return CELIX_SUCCESS;
+}
+
+static void celix_serviceRegistry_serviceChanged(celix_service_registry_t *registry, celix_service_event_type_t eventType, service_registration_pt registration) {
+    celix_service_registry_service_listener_entry_t *entry;
+
+    celix_array_list_t* retainedEntries = celix_arrayList_create();
+    celix_array_list_t* matchedEntries = celix_arrayList_create();
+
+    celixThreadRwlock_readLock(&registry->lock);
+    for (int i = 0; i < celix_arrayList_size(registry->serviceListeners); ++i) {
+        entry = celix_arrayList_get(registry->serviceListeners, i);
+        celix_arrayList_add(retainedEntries, entry);
+        celix_increaseCountServiceListener(entry); //ensure that use count > 0, so that the listener cannot be destroyed until all pending event are handled.
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    for (int i = 0; i < celix_arrayList_size(retainedEntries); ++i) {
+        entry = celix_arrayList_get(retainedEntries, i);
+        int matched = 0;
+        celix_properties_t *props = NULL;
+        bool matchResult = false;
+        serviceRegistration_getProperties(registration, &props);
+        if (entry->filter != NULL) {
+            filter_match(entry->filter, props, &matchResult);
+        }
+        matched = (entry->filter == NULL) || matchResult;
+        if (matched) {
+            celix_arrayList_add(matchedEntries, entry);
+        } else {
+            celix_decreaseCountServiceListener(entry); //Not a match -> release entry
+        }
+    }
+    celix_arrayList_destroy(retainedEntries);
+
+    /*
+     * TODO FIXME, A deadlock can happen when (e.g.) a service is deregistered, triggering this fw_serviceChanged and
+     * one of the matching service listener callbacks tries to remove an other matched service listener.
+     * The remove service listener will call the listener_waitForDestroy and the fw_serviceChanged part keeps the
+     * usageCount on > 0.
+     *
+     * Not sure how to prevent/handle this.
+     */
+
+    for (int i = 0; i < celix_arrayList_size(matchedEntries); ++i) {
+        entry = celix_arrayList_get(matchedEntries, i);
+        service_reference_pt reference = NULL;
+        celix_service_event_t event;
+        serviceRegistry_getServiceReference(registry, entry->bundle, registration, &reference);
+        event.type = eventType;
+        event.reference = reference;
+        entry->listener->serviceChanged(entry->listener->handle, &event);
+        serviceRegistry_ungetServiceReference(registry, entry->bundle, reference);
+        celix_decreaseCountServiceListener(entry); //decrease usage, so that the listener can be destroyed (if use count is now 0)
+    }
+    celix_arrayList_destroy(matchedEntries);
+}
+
+
+static void celix_increasePendingRegisteredEvent(celix_service_registry_t *registry, long svcId) {
+    celixThreadMutex_lock(&registry->pendingRegisterEvents.mutex);
+    long count = (long)hashMap_get(registry->pendingRegisterEvents.map, (void*)svcId);
+    count += 1;
+    hashMap_put(registry->pendingRegisterEvents.map, (void*)svcId, (void*)count);
+    celixThreadMutex_unlock(&registry->pendingRegisterEvents.mutex);
+}
+
+static void celix_decreasePendingRegisteredEvent(celix_service_registry_t *registry, long svcId) {
+    celixThreadMutex_lock(&registry->pendingRegisterEvents.mutex);
+    long count = (long)hashMap_get(registry->pendingRegisterEvents.map, (void*)svcId);
+    assert(count >= 1);
+    count -= 1;
+    if (count > 0) {
+        hashMap_put(registry->pendingRegisterEvents.map, (void *)svcId, (void *)count);
+    } else {
+        hashMap_remove(registry->pendingRegisterEvents.map, (void*)svcId);
+    }
+    celixThreadCondition_signal(&registry->pendingRegisterEvents.cond);
+    celixThreadMutex_unlock(&registry->pendingRegisterEvents.mutex);
+}
+
+static void celix_waitForPendingRegisteredEvents(celix_service_registry_t *registry, long svcId) {
+    celixThreadMutex_lock(&registry->pendingRegisterEvents.mutex);
+    long count = (long)hashMap_get(registry->pendingRegisterEvents.map, (void*)svcId);
+    while (count > 0) {
+        celixThreadCondition_wait(&registry->pendingRegisterEvents.cond, &registry->pendingRegisterEvents.mutex);
+        count = (long)hashMap_get(registry->pendingRegisterEvents.map, (void*)svcId);
+    }
+    celixThreadMutex_unlock(&registry->pendingRegisterEvents.mutex);
+}
+
+//static void celix_serviceRegistry_triggerListenerHooks(celix_service_registry_t *registry, const char* serviceName, const celix_properties_t *properties) {
+//     //If this is a listener hook, invoke the callback with all current listeners
+//    if (strcmp(serviceName, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME) == 0) {
+//        celix_array_list_t *infos = NULL;
+//        service_reference_pt ref = NULL;
+//        listener_hook_service_pt hook = NULL;
+//
+//        status = CELIX_DO_IF(status, arrayList_create(&infos));
+//
+//        if (status == CELIX_SUCCESS) {
+//            celix_status_t subs = CELIX_SUCCESS;
+//
+//            celixThreadMutex_lock(&framework->serviceListenersLock);
+//            for (i = 0; i < arrayList_size(framework->serviceListeners); i++) {
+//                celix_fw_service_listener_entry_t *listener = arrayList_get(framework->serviceListeners, i);
+//                bundle_context_t *context = NULL;
+//                listener_hook_info_pt info = NULL;
+//                bundle_context_pt lContext = NULL;
+//
+//                subs = CELIX_DO_IF(subs, bundle_getContext(entry->bnd, &context));
+//                if (subs == CELIX_SUCCESS) {
+//                    info = (listener_hook_info_pt) malloc(sizeof(*info));
+//                    if (info == NULL) {
+//                        subs = CELIX_ENOMEM;
+//                    }
+//                }
+//
+//                subs = CELIX_DO_IF(subs, bundle_getContext(listener->bundle, &lContext));
+//                if (subs == CELIX_SUCCESS) {
+//                    info->context = lContext;
+//                    info->removed = false;
+//                }
+//                subs = CELIX_DO_IF(subs, filter_getString(listener->filter, &info->filter));
+//
+//                if (subs == CELIX_SUCCESS) {
+//                    arrayList_add(infos, info);
+//                }
+//                else{
+//                    fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not pass all listeners to the hook: %s", serviceName);
+//                    free(info);
+//                }
+//            }
+//            celixThreadMutex_unlock(&framework->serviceListenersLock);
+//
+//            status = CELIX_DO_IF(status, serviceRegistry_getServiceReference(framework->registry, framework->bundle,
+//                                                                             *registration, &ref));
+//            status = CELIX_DO_IF(status, fw_getService(framework,framework->bundle, ref, (const void **) &hook));
+//            if (status == CELIX_SUCCESS) {
+//                hook->added(hook->handle, infos);
+//            }
+//            status = CELIX_DO_IF(status, serviceRegistry_ungetService(framework->registry, framework->bundle, ref, NULL));
+//            status = CELIX_DO_IF(status, serviceRegistry_ungetServiceReference(framework->registry, framework->bundle, ref));
+//
+//            for (int j = 0; j < arrayList_size(infos); j++) {
+//                listener_hook_info_pt info = arrayList_get(infos, j);
+//                free(info);
+//            }
+//            arrayList_destroy(infos);
+//        }
+//    }
+//}
\ No newline at end of file
diff --git a/libs/framework/src/service_registry_private.h b/libs/framework/src/service_registry_private.h
index 82d719a..3a4cd01 100644
--- a/libs/framework/src/service_registry_private.h
+++ b/libs/framework/src/service_registry_private.h
@@ -36,18 +36,33 @@ struct celix_serviceRegistry {
 	framework_pt framework;
 	registry_callback_t callback;
 
-	hash_map_pt serviceRegistrations; //key = bundle (reg owner), value = list ( registration )
-	hash_map_pt serviceReferences; //key = bundle, value = map (key = serviceId, value = reference)
+    celix_thread_rwlock_t lock; //protect below
+
+	hash_map_t *serviceRegistrations; //key = bundle (reg owner), value = list ( registration )
+	hash_map_t *serviceReferences; //key = bundle, value = map (key = serviceId, value = reference)
 
 	bool checkDeletedReferences; //If enabled. check if provided service references are still valid
-	hash_map_pt deletedServiceReferences; //key = ref pointer, value = bool
+	hash_map_t *deletedServiceReferences; //key = ref pointer, value = bool
 
-	serviceChanged_function_pt serviceChanged;
 	unsigned long currentServiceId;
 
-	array_list_pt listenerHooks; //celix_service_registry_listener_hook_entry_t*
+	celix_array_list_t *listenerHooks; //celix_service_registry_listener_hook_entry_t*
+	celix_array_list_t *serviceListeners; //celix_service_registry_service_listener_entry_t*
 
-	celix_thread_rwlock_t lock;
+	/**
+	 * The pending register events are introduced to ensure UNREGISTERING events are always
+	 * after REGISTERED events in service listeners.
+	 * When a listener is registered and it retroactively triggers registered events, it will also
+	 * increase the pending registered events for the matching services.
+	 * Also when a new service is registered all matching services listeners are called.
+	 * This is used to ensuring unregistering events can only be triggered after all registered
+	 * events - for a given service - are triggered.
+	 */
+	struct {
+	    celix_thread_mutex_t mutex;
+	    celix_thread_cond_t cond;
+	    hash_map_t *map; //key = svc id, value = long (nr of pending register events)
+	} pendingRegisterEvents;
 };
 
 typedef struct celix_service_registry_listener_hook_entry {
@@ -55,9 +70,18 @@ typedef struct celix_service_registry_listener_hook_entry {
     celix_listener_hook_service_t *hook;
     celix_thread_mutex_t mutex; //protects below
     celix_thread_cond_t cond;
-    unsigned int count;
+    unsigned int useCount;
 } celix_service_registry_listener_hook_entry_t;
 
+typedef struct celix_service_registry_service_listener_entry {
+    celix_bundle_t *bundle;
+    celix_filter_t *filter;
+    celix_service_listener_t *listener;
+    celix_thread_mutex_t mutex; //protects below
+    celix_thread_cond_t cond;
+    unsigned int useCount;
+} celix_service_registry_service_listener_entry_t;
+
 typedef enum reference_status_enum {
 	REF_ACTIVE,
 	REF_DELETED,
diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c
index d2a22f9..e421adc 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -39,12 +39,10 @@ static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t *t
 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*/,
-                                                            double waitTimeoutInSeconds,
                                                             void *callbackHandle,
                                                             void (*use)(void *handle, void *svc),
                                                             void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props),
@@ -53,6 +51,8 @@ static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracke
 static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance);
 static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t *instance);
 
+static void serviceTracker_serviceChanged(void *handle, celix_service_event_t *event);
+
 static celix_thread_once_t g_once = CELIX_THREAD_ONCE_INIT; //once for g_shutdownMutex, g_shutdownCond
 
 
@@ -90,9 +90,7 @@ static inline void tracked_release(celix_tracked_entry_t *tracked) {
     celixThreadMutex_lock(&tracked->mutex);
     assert(tracked->useCount > 0);
     tracked->useCount -= 1;
-    if (tracked->useCount == 0) {
-        celixThreadCondition_broadcast(&tracked->useCond);
-    }
+    celixThreadCondition_signal(&tracked->useCond);
     celixThreadMutex_unlock(&tracked->mutex);
 }
 
@@ -158,9 +156,10 @@ celix_status_t serviceTracker_destroy(service_tracker_pt tracker) {
 celix_status_t serviceTracker_open(service_tracker_pt tracker) {
     celix_service_listener_t *listener = NULL;
     celix_service_tracker_instance_t *instance = NULL;
-    array_list_pt initial = NULL;
     celix_status_t status = CELIX_SUCCESS;
 
+    bool addListener = false;
+
     celixThreadRwlock_writeLock(&tracker->instanceLock);
     if (tracker->instance == NULL) {
         instance = calloc(1, sizeof(*instance));
@@ -197,36 +196,20 @@ celix_status_t serviceTracker_open(service_tracker_pt tracker) {
         instance->removeWithProperties = tracker->removeWithProperties;
         instance->removeWithOwner = tracker->removeWithOwner;
 
-        status = bundleContext_getServiceReferences(tracker->context, NULL, tracker->filter, &initial); //REF COUNT to 1
-
         tracker->instance = instance;
+
+        addListener = true;
     } else {
         //already open
-    }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+        framework_logIfError(logger, status, NULL, "Tracker already open");
 
-    //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);
     }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
 
-	if (status != CELIX_SUCCESS && listener != NULL){
-		free(listener);
+	if (addListener) {
+	    bundleContext_addServiceListener(tracker->context, listener, tracker->filter);
 	}
-
-	framework_logIfError(logger, status, NULL, "Cannot open tracker");
-
-	return status;
+	return CELIX_SUCCESS;
 }
 
 static void* shutdownServiceTrackerInstanceHandler(void *data) {
@@ -254,33 +237,31 @@ celix_status_t serviceTracker_close(service_tracker_pt tracker) {
     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);
+        //prevent service listener events
         instance->closing = true;
         celixThreadMutex_unlock(&instance->closingLock);
+    }
+    celixThreadRwlock_unlock(&tracker->instanceLock);
 
-        int i;
+    if (instance != NULL) {
         celixThreadRwlock_writeLock(&instance->lock);
-        size_t size = celix_arrayList_size(instance->trackedServices);
+        int size = celix_arrayList_size(instance->trackedServices);
         celix_tracked_entry_t *trackedEntries[size];
-        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+        for (int 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);
 
         //loop trough tracked entries an untrack
-        for (i = 0; i < size; i++) {
+        for (int 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) {
+        while (instance->activeServiceChangeCalls > 0) {
             celixThreadCondition_wait(&instance->activeServiceChangeCallsCond, &instance->closingLock);
         }
         celixThreadMutex_unlock(&instance->closingLock);
@@ -292,7 +273,7 @@ celix_status_t serviceTracker_close(service_tracker_pt tracker) {
         // 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.
+        // are made back to the celix framework / tracker owner.
         serviceTracker_addInstanceFromShutdownList(instance);
         celix_thread_t localThread;
         celixThread_create(&localThread, NULL, shutdownServiceTrackerInstanceHandler, instance);
@@ -416,8 +397,8 @@ void *serviceTracker_getServiceByReference(service_tracker_pt tracker, service_r
 	return service;
 }
 
-void serviceTracker_serviceChanged(celix_service_listener_t *listener, celix_service_event_t *event) {
-	celix_service_tracker_instance_t *instance = listener->handle;
+static void serviceTracker_serviceChanged(void *handle, celix_service_event_t *event) {
+	celix_service_tracker_instance_t *instance = handle;
 
     celixThreadMutex_lock(&instance->closingLock);
     bool closing = instance->closing;
@@ -475,17 +456,14 @@ static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *ins
         celix_tracked_entry_t *visit = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
         serviceReference_equals(reference, visit->reference, &equals);
         if (equals) {
+            //NOTE it is possible to get two REGISTERED events, second one can be ignored.
             found = visit;
-            tracked_retain(found);
             break;
         }
     }
     celixThreadRwlock_unlock(&instance->lock);
 
-    if (found != NULL) {
-        status = serviceTracker_invokeModifiedService(instance, found);
-        tracked_retain(found);
-    } else if (status == CELIX_SUCCESS && found == NULL) {
+    if (found == NULL) {
         //NEW entry
         void *service = NULL;
         status = serviceTracker_invokeAddingService(instance, reference, &service);
@@ -502,14 +480,14 @@ static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *ins
                 serviceRegistration_getProperties(reg, &props);
             }
 
-            celix_tracked_entry_t *tracked = tracked_create(reference, service, props, bnd);
+            celix_tracked_entry_t *tracked = tracked_create(reference, service, props, bnd); //use count 1
 
             celixThreadRwlock_writeLock(&instance->lock);
             arrayList_add(instance->trackedServices, tracked);
             celixThreadRwlock_unlock(&instance->lock);
 
             serviceTracker_invokeAddService(instance, tracked);
-            serviceTracker_useHighestRankingServiceInternal(instance, tracked->serviceName, 0, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+            serviceTracker_useHighestRankingServiceInternal(instance, tracked->serviceName, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
         }
     }
 
@@ -551,31 +529,6 @@ static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestS
     }
 }
 
-static celix_status_t serviceTracker_invokeModifiedService(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
-    celix_status_t status = CELIX_SUCCESS;
-
-    void *customizerHandle = NULL;
-    modified_callback_pt function = NULL;
-    serviceTrackerCustomizer_getHandle(&instance->customizer, &customizerHandle);
-    serviceTrackerCustomizer_getModifiedFunction(&instance->customizer, &function);
-    if (function != NULL) {
-        function(customizerHandle, tracked->reference, tracked->service);
-    }
-    
-    void *handle = instance->callbackHandle;
-    if (instance->modified != NULL) {
-        instance->modified(handle, tracked->service);
-    }
-    if (instance->modifiedWithProperties != NULL) {
-        instance->modifiedWithProperties(handle, tracked->service, tracked->properties);
-    }
-    if (instance->modifiedWithOwner != NULL) {
-        instance->modifiedWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
-    }
-    return status;
-}
-
-
 static celix_status_t serviceTracker_invokeAddService(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
     celix_status_t status = CELIX_SUCCESS;
 
@@ -651,7 +604,7 @@ static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t* i
     if (size == 0) {
         serviceTracker_checkAndInvokeSetService(instance, NULL, NULL, NULL);
     } else {
-        serviceTracker_useHighestRankingServiceInternal(instance, serviceName, 0, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+        serviceTracker_useHighestRankingServiceInternal(instance, serviceName, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
     }
 
     serviceTracker_untrackTracked(instance, remove);
@@ -830,7 +783,6 @@ void celix_serviceTracker_destroy(celix_service_tracker_t *tracker) {
 
 static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracker_instance_t *instance,
                                                             const char *serviceName /*sanity*/,
-                                                            double waitForSvcTimeoutInSec /*0 -> do not wait */,
                                                             void *callbackHandle,
                                                             void (*use)(void *handle, void *svc),
                                                             void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props),
@@ -845,29 +797,6 @@ static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracke
     celixThreadRwlock_readLock(&instance->lock);
     unsigned int size = arrayList_size(instance->trackedServices);
 
-    if (waitForSvcTimeoutInSec > 0) {
-        struct timespec start;
-        struct timespec now;
-        clock_gettime(CLOCK_MONOTONIC, &start);
-
-        double billion = 1E9;
-        long waitFor = (long)(waitForSvcTimeoutInSec * billion);
-        long diffInNs = 0L;
-
-        while (size == 0 && diffInNs < waitFor) {
-            size = arrayList_size(instance->trackedServices);
-            if (size > 0) {
-                break;
-            } else {
-                celixThreadRwlock_unlock(&instance->lock);
-                usleep(1);
-                celixThreadRwlock_readLock(&instance->lock);
-            };
-            clock_gettime(CLOCK_MONOTONIC, &now);
-            diffInNs = ( now.tv_nsec - start.tv_nsec ) + ( now.tv_sec - start.tv_sec ) * (long)billion;
-        }
-    }
-
     for (i = 0; i < size; i++) {
         tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
         if (serviceName != NULL && tracked->serviceName != NULL && strncmp(tracked->serviceName, serviceName, 10*1024) == 0) {
@@ -912,34 +841,48 @@ bool celix_serviceTracker_useHighestRankingService(
         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, waitTimeoutInSeconds, callbackHandle, use,
-                                                                 useWithProperties, useWithOwner);
-    }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    struct timespec start, now;
+    clock_gettime(CLOCK_MONOTONIC, &start);
+    do {
+        celixThreadRwlock_readLock(&tracker->instanceLock);
+        if (tracker->instance != NULL) {
+            called = serviceTracker_useHighestRankingServiceInternal(tracker->instance, serviceName, callbackHandle, use, useWithProperties, useWithOwner);
+        }
+        celixThreadRwlock_unlock(&tracker->instanceLock);
+
+        if (waitTimeoutInSeconds <= 0) {
+            break;
+        } else if (!called) {
+            clock_gettime(CLOCK_MONOTONIC, &now);
+            double diff = celix_difftime(&start, &now);
+            if (diff > waitTimeoutInSeconds) {
+                break;
+            }
+            usleep(10);
+        }
+    } while (!called);
     return called;
 }
 
-void celix_serviceTracker_useServices(
+size_t celix_serviceTracker_useServices(
         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)) {
-    int i;
-
+    size_t count = 0;
     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);
+        int size = celix_arrayList_size(instance->trackedServices);
+        count = (size_t)size;
         celix_tracked_entry_t *entries[size];
-        for (i = 0; i < size; i++) {
+        for (int 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;
@@ -948,7 +891,7 @@ void celix_serviceTracker_useServices(
         celixThreadRwlock_unlock(&instance->lock);
 
         //then use entries and decrease use count
-        for (i = 0; i < size; i++) {
+        for (int 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) {
@@ -965,6 +908,7 @@ void celix_serviceTracker_useServices(
         }
     }
     celixThreadRwlock_unlock(&tracker->instanceLock);
+    return count;
 }
 
 void celix_serviceTracker_syncForFramework(void *fw) {


[celix] 01/02: Refactors some celix framework test from cpputest to gtest.

Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/framework_racecondition
in repository https://gitbox.apache.org/repos/asf/celix.git

commit aad0ecd8a173bcea08c2d57f6d4442bc116fbcbc
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Fri Mar 6 11:35:12 2020 +0100

    Refactors some celix framework test from cpputest to gtest.
---
 libs/framework/CMakeLists.txt                      |   4 +-
 libs/framework/{test => gtest}/CMakeLists.txt      |  18 +-
 .../framework/{test => gtest}/config.properties.in |   0
 .../{test => gtest}/framework1.properties.in       |   0
 .../{test => gtest}/framework2.properties.in       |   0
 .../src}/bundle_context_bundles_tests.cpp          | 224 ++++++++--------
 .../src}/bundle_context_services_test.cpp          | 281 +++++++++++----------
 libs/framework/{test => gtest/src}/dm_tests.cpp    |  38 +--
 .../src}/multiple_frameworks_test.cpp              |  25 +-
 libs/framework/{test => gtest/src}/nop_activator.c |   0
 libs/framework/{test => gtest/src}/run_tests.cpp   |  10 +-
 .../{test => gtest/src}/single_framework_test.cpp  |  41 +--
 .../{test => gtest}/subdir/CMakeLists.txt          |   0
 libs/framework/{test => gtest}/subdir/src/foo.c    |   0
 14 files changed, 325 insertions(+), 316 deletions(-)

diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 8297a97..a8d551a 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -52,9 +52,7 @@ add_library(Celix::framework ALIAS framework)
 
 
 if (ENABLE_TESTING)
-    find_package(CppUTest REQUIRED)
-    include_directories(SYSTEM PRIVATE ${CPPUTEST_INCLUDE_DIR})
-    add_subdirectory(test)
+    add_subdirectory(gtest)
 endif()
 
 
diff --git a/libs/framework/test/CMakeLists.txt b/libs/framework/gtest/CMakeLists.txt
similarity index 84%
rename from libs/framework/test/CMakeLists.txt
rename to libs/framework/gtest/CMakeLists.txt
index 33a7428..33cb7b9 100644
--- a/libs/framework/test/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -18,10 +18,10 @@
 add_celix_bundle(simple_test_bundle1 NO_ACTIVATOR VERSION 1.0.0)
 add_celix_bundle(simple_test_bundle2 NO_ACTIVATOR VERSION 1.0.0)
 add_celix_bundle(simple_test_bundle3 NO_ACTIVATOR VERSION 1.0.0)
-add_celix_bundle(bundle_with_exception SOURCES nop_activator.c VERSION 1.0.0)
+add_celix_bundle(bundle_with_exception SOURCES src/nop_activator.c VERSION 1.0.0)
 add_subdirectory(subdir) #simple_test_bundle4, simple_test_bundle5 and sublib
 
-add_celix_bundle(unresolveable_bundle SOURCES nop_activator.c VERSION 1.0.0)
+add_celix_bundle(unresolveable_bundle SOURCES src/nop_activator.c VERSION 1.0.0)
 target_link_libraries(unresolveable_bundle PRIVATE "-L${CMAKE_CURRENT_BINARY_DIR}/subdir -lsublib")
 if(NOT APPLE)
     set_target_properties(unresolveable_bundle PROPERTIES LINK_FLAGS -Wl,--no-as-needed)
@@ -29,15 +29,15 @@ endif()
 add_dependencies(unresolveable_bundle sublib)
 
 add_executable(test_framework
-    run_tests.cpp
-    single_framework_test.cpp
-    multiple_frameworks_test.cpp
-    bundle_context_bundles_tests.cpp
-    bundle_context_services_test.cpp
-    dm_tests.cpp
+    src/run_tests.cpp
+    src/single_framework_test.cpp
+    src/multiple_frameworks_test.cpp
+    src/bundle_context_bundles_tests.cpp
+    src/bundle_context_services_test.cpp
+    src/dm_tests.cpp
 )
 
-target_link_libraries(test_framework Celix::framework CURL::libcurl ${CPPUTEST_LIBRARY})
+target_link_libraries(test_framework Celix::framework CURL::libcurl GTest::GTest)
 add_dependencies(test_framework simple_test_bundle1_bundle simple_test_bundle2_bundle simple_test_bundle3_bundle simple_test_bundle4_bundle simple_test_bundle5_bundle bundle_with_exception_bundle unresolveable_bundle_bundle)
 target_include_directories(test_framework PRIVATE ../src)
 
diff --git a/libs/framework/test/config.properties.in b/libs/framework/gtest/config.properties.in
similarity index 100%
rename from libs/framework/test/config.properties.in
rename to libs/framework/gtest/config.properties.in
diff --git a/libs/framework/test/framework1.properties.in b/libs/framework/gtest/framework1.properties.in
similarity index 100%
rename from libs/framework/test/framework1.properties.in
rename to libs/framework/gtest/framework1.properties.in
diff --git a/libs/framework/test/framework2.properties.in b/libs/framework/gtest/framework2.properties.in
similarity index 100%
rename from libs/framework/test/framework2.properties.in
rename to libs/framework/gtest/framework2.properties.in
diff --git a/libs/framework/test/bundle_context_bundles_tests.cpp b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
similarity index 67%
rename from libs/framework/test/bundle_context_bundles_tests.cpp
rename to libs/framework/gtest/src/bundle_context_bundles_tests.cpp
index 72a4891..7295367 100644
--- a/libs/framework/test/bundle_context_bundles_tests.cpp
+++ b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+#include <gtest/gtest.h>
+
 #include <thread>
 #include <chrono>
 #include <iostream>
@@ -27,14 +29,11 @@
 
 #include "celix_api.h"
 
-#include <CppUTest/TestHarness.h>
-#include <CppUTest/CommandLineTestRunner.h>
-
-
-TEST_GROUP(CelixBundleContextBundlesTests) {
-    framework_t* fw = nullptr;
-    bundle_context_t *ctx = nullptr;
-    properties_t *properties = nullptr;
+class CelixBundleContextBundlesTests : public ::testing::Test {
+public:
+    celix_framework_t* fw = nullptr;
+    celix_bundle_context_t *ctx = nullptr;
+    celix_properties_t *properties = nullptr;
 
     const char * const TEST_BND1_LOC = "simple_test_bundle1.zip";
     const char * const TEST_BND2_LOC = "simple_test_bundle2.zip";
@@ -44,7 +43,7 @@ TEST_GROUP(CelixBundleContextBundlesTests) {
     const char * const TEST_BND_WITH_EXCEPTION_LOC = "bundle_with_exception.zip";
     const char * const TEST_BND_UNRESOLVEABLE_LOC = "unresolveable_bundle.zip";
 
-    void setup() {
+    CelixBundleContextBundlesTests() {
         properties = properties_create();
         properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
         properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
@@ -53,35 +52,42 @@ TEST_GROUP(CelixBundleContextBundlesTests) {
         fw = celix_frameworkFactory_createFramework(properties);
         ctx = framework_getContext(fw);
     }
-
-    void teardown() {
+    
+    ~CelixBundleContextBundlesTests() override {
         celix_frameworkFactory_destroyFramework(fw);
     }
+
+    CelixBundleContextBundlesTests(CelixBundleContextBundlesTests&&) = delete;
+    CelixBundleContextBundlesTests(const CelixBundleContextBundlesTests&) = delete;
+    CelixBundleContextBundlesTests& operator=(CelixBundleContextBundlesTests&&) = delete;
+    CelixBundleContextBundlesTests& operator=(const CelixBundleContextBundlesTests&) = delete;
 };
 
-TEST(CelixBundleContextBundlesTests, installBundlesTest) {
+
+
+TEST_F(CelixBundleContextBundlesTests, installBundlesTest) {
     long bndId = celix_bundleContext_installBundle(ctx, "non-existing.zip", true);
-    CHECK(bndId < 0);
+    ASSERT_TRUE(bndId < 0);
 
     bndId = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
-    CHECK(bndId >= 0);
+    ASSERT_TRUE(bndId >= 0);
 
     bndId = celix_bundleContext_installBundle(ctx, TEST_BND4_LOC, true); //not loaded in subdir
-    CHECK(bndId < 0);
+    ASSERT_TRUE(bndId < 0);
 
     setenv(CELIX_BUNDLES_PATH_NAME, "subdir", true);
     bndId = celix_bundleContext_installBundle(ctx, TEST_BND4_LOC, true); //subdir now part of CELIX_BUNDLES_PATH
-    CHECK(bndId >= 0);
+    ASSERT_TRUE(bndId >= 0);
 }
 
-TEST(CelixBundleContextBundlesTests, useBundlesTest) {
+TEST_F(CelixBundleContextBundlesTests, useBundlesTest) {
     int count = 0;
 
     auto use = [](void *handle, const bundle_t *bnd) {
         int *c = (int*)handle;
         *c += 1;
         long id = celix_bundle_getId(bnd);
-        CHECK(id >= 0);
+        ASSERT_TRUE(id >= 0);
     };
 
     celix_bundleContext_useBundles(ctx, &count, use);
@@ -89,193 +95,193 @@ TEST(CelixBundleContextBundlesTests, useBundlesTest) {
     count = 0;
     celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
     celix_bundleContext_useBundles(ctx, &count, use);
-    CHECK_EQUAL(1, count);
+    ASSERT_EQ(1, count);
 };
 
-TEST(CelixBundleContextBundlesTests, installAndUninstallBundlesTest) {
+TEST_F(CelixBundleContextBundlesTests, installAndUninstallBundlesTest) {
     //install bundles
     long bndId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
     long bndId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false);
     long bndId3 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
 
-    CHECK_TRUE(bndId1 >= 0L);
-    CHECK_TRUE(bndId2 >= 0L);
-    CHECK_TRUE(bndId3 >= 0L);
+    ASSERT_TRUE(bndId1 >= 0L);
+    ASSERT_TRUE(bndId2 >= 0L);
+    ASSERT_TRUE(bndId3 >= 0L);
 
-    CHECK_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
-    CHECK_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
-    CHECK_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
 
-    CHECK_TRUE(celix_bundleContext_isBundleActive(ctx, bndId1));
-    CHECK_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2)); //not auto started
-    CHECK_TRUE(celix_bundleContext_isBundleActive(ctx, bndId3));
+    ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId1));
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2)); //not auto started
+    ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId3));
 
     //uninstall bundles
-    CHECK_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId1));
-    CHECK_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId2));
-    CHECK_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId3));
+    ASSERT_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId2));
+    ASSERT_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId3));
 
-    CHECK_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
-    CHECK_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
-    CHECK_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
+    ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
+    ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
 
-    CHECK_FALSE(celix_bundleContext_isBundleActive(ctx, bndId1)); //not uninstall -> not active
-    CHECK_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2));
-    CHECK_FALSE(celix_bundleContext_isBundleActive(ctx, bndId3));
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId1)); //not uninstall -> not active
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2));
+    ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId3));
 
     //reinstall bundles
     long bndId4 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
     long bndId5 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false);
     long bndId6 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
 
-    CHECK_TRUE(bndId4 >= 0L);
-    CHECK_FALSE(bndId1 == bndId4); //not new id
-    CHECK_TRUE(bndId5 >= 0L);
-    CHECK_FALSE(bndId2 == bndId5); //not new id
-    CHECK_TRUE(bndId6 >= 0L);
-    CHECK_FALSE(bndId5 == bndId6); //not new id
+    ASSERT_TRUE(bndId4 >= 0L);
+    ASSERT_FALSE(bndId1 == bndId4); //not new id
+    ASSERT_TRUE(bndId5 >= 0L);
+    ASSERT_FALSE(bndId2 == bndId5); //not new id
+    ASSERT_TRUE(bndId6 >= 0L);
+    ASSERT_FALSE(bndId5 == bndId6); //not new id
 }
 
-TEST(CelixBundleContextBundlesTests, startBundleWithException) {
+TEST_F(CelixBundleContextBundlesTests, startBundleWithException) {
     long bndId = celix_bundleContext_installBundle(ctx, TEST_BND_WITH_EXCEPTION_LOC, true);
-    CHECK(bndId > 0); //bundle is installed, but not started
+    ASSERT_TRUE(bndId > 0); //bundle is installed, but not started
 
     bool called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void */*handle*/, const celix_bundle_t *bnd) {
         auto state = celix_bundle_getState(bnd);
-        CHECK_EQUAL(state, OSGI_FRAMEWORK_BUNDLE_RESOLVED);
+        ASSERT_EQ(state, OSGI_FRAMEWORK_BUNDLE_RESOLVED);
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 }
 
-TEST(CelixBundleContextBundlesTests, startUnresolveableBundle) {
+TEST_F(CelixBundleContextBundlesTests, startUnresolveableBundle) {
     long bndId = celix_bundleContext_installBundle(ctx, TEST_BND_UNRESOLVEABLE_LOC, true);
-    CHECK(bndId > 0); //bundle is installed, but not resolved
+    ASSERT_TRUE(bndId > 0); //bundle is installed, but not resolved
 
     bool called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void *, const celix_bundle_t *bnd) {
         auto state = celix_bundle_getState(bnd);
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_INSTALLED, state);
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_INSTALLED, state);
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 
     celix_bundleContext_startBundle(ctx, bndId);
 
    called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void *, const celix_bundle_t *bnd) {
         auto state = celix_bundle_getState(bnd);
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_INSTALLED, state);
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_INSTALLED, state);
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 }
 
 
-TEST(CelixBundleContextBundlesTests, useBundleTest) {
+TEST_F(CelixBundleContextBundlesTests, useBundleTest) {
     int count = 0;
 
     bool called = celix_bundleContext_useBundle(ctx, 0, &count, [](void *handle, const bundle_t *bnd) {
         int *c = (int*)handle;
         *c += 1;
         long id = celix_bundle_getId(bnd);
-        CHECK_EQUAL(0, id);
+        ASSERT_EQ(0, id);
     });
 
-    CHECK_TRUE(called);
-    CHECK_EQUAL(1, count);
+    ASSERT_TRUE(called);
+    ASSERT_EQ(1, count);
 };
 
-TEST(CelixBundleContextBundlesTests, StopStartTest) {
+TEST_F(CelixBundleContextBundlesTests, StopStartTest) {
     long bndId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
     long bndId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, true);
     long bndId3 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
-    CHECK_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
-    CHECK_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
-    CHECK_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
-    CHECK_FALSE(celix_bundleContext_isBundleInstalled(ctx, 600 /*non existing*/));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId2));
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId3));
+    ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, 600 /*non existing*/));
 
 
 
     celix_array_list_t *ids = celix_bundleContext_listBundles(ctx);
     size_t size = arrayList_size(ids);
-    CHECK_EQUAL(3, size);
+    ASSERT_EQ(3, size);
 
     int count = 0;
     celix_bundleContext_useBundles(ctx, &count, [](void *handle, const celix_bundle_t *bnd) {
         auto *c = (int*)handle;
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
         *c += 1;
     });
-    CHECK_EQUAL(3, count);
+    ASSERT_EQ(3, count);
 
 
     for (size_t i = 0; i < size; ++i) {
         bool stopped = celix_bundleContext_stopBundle(ctx, celix_arrayList_getLong(ids, (int)i));
-        CHECK_TRUE(stopped);
+        ASSERT_TRUE(stopped);
     }
 
     bool stopped = celix_bundleContext_stopBundle(ctx, 42 /*non existing*/);
-    CHECK_FALSE(stopped);
+    ASSERT_FALSE(stopped);
 
     bool started = celix_bundleContext_startBundle(ctx, 42 /*non existing*/);
-    CHECK_FALSE(started);
+    ASSERT_FALSE(started);
 
     for (size_t i = 0; i < size; ++i) {
-        bool started = celix_bundleContext_startBundle(ctx, celix_arrayList_getLong(ids, (int)i));
-        CHECK_TRUE(started);
+        started = celix_bundleContext_startBundle(ctx, celix_arrayList_getLong(ids, (int)i));
+        ASSERT_TRUE(started);
     }
 
     count = 0;
     celix_bundleContext_useBundles(ctx, &count, [](void *handle, const celix_bundle_t *bnd) {
         auto *c = (int*)handle;
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
         *c += 1;
     });
-    CHECK_EQUAL(3, count);
+    ASSERT_EQ(3, count);
 
     celix_arrayList_destroy(ids);
 }
 
-TEST(CelixBundleContextBundlesTests, DoubleStopTest) {
+TEST_F(CelixBundleContextBundlesTests, DoubleStopTest) {
     long bndId = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
-    CHECK_TRUE(bndId > 0);
-    CHECK_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId));
+    ASSERT_TRUE(bndId > 0);
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId));
 
     bool called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void *, const celix_bundle_t *bnd) {
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 
     //first
     celix_bundleContext_stopBundle(ctx, bndId);
 
     called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void *, const celix_bundle_t *bnd) {
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_RESOLVED, celix_bundle_getState(bnd));
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_RESOLVED, celix_bundle_getState(bnd));
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 
     //second
     celix_bundleContext_stopBundle(ctx, bndId);
 
     called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void *, const celix_bundle_t *bnd) {
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_RESOLVED, celix_bundle_getState(bnd));
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_RESOLVED, celix_bundle_getState(bnd));
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 
     //first
     celix_bundleContext_startBundle(ctx, bndId);
 
     called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void *, const celix_bundle_t *bnd) {
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 
     //second
     celix_bundleContext_startBundle(ctx, bndId);
 
     called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void *, const celix_bundle_t *bnd) {
-        CHECK_EQUAL(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
+        ASSERT_EQ(OSGI_FRAMEWORK_BUNDLE_ACTIVE, celix_bundle_getState(bnd));
     });
-    CHECK_TRUE(called);
+    ASSERT_TRUE(called);
 }
 
-TEST(CelixBundleContextBundlesTests, trackBundlesTest) {
+TEST_F(CelixBundleContextBundlesTests, trackBundlesTest) {
     struct data {
         int count{0};
         std::mutex mutex{};
@@ -285,7 +291,7 @@ TEST(CelixBundleContextBundlesTests, trackBundlesTest) {
 
     auto started = [](void *handle, const bundle_t *bnd) {
         struct data *d = static_cast<struct data*>(handle);
-        CHECK(bnd != nullptr);
+        ASSERT_TRUE(bnd != nullptr);
         d->mutex.lock();
         d->count += 1;
         d->cond.notify_all();
@@ -293,7 +299,7 @@ TEST(CelixBundleContextBundlesTests, trackBundlesTest) {
     };
     auto stopped = [](void *handle, const bundle_t *bnd) {
         struct data *d = static_cast<struct data*>(handle);
-        CHECK(bnd != nullptr);
+        ASSERT_TRUE(bnd != nullptr);
         d->mutex.lock();
         d->count -= 1;
         d->cond.notify_all();
@@ -301,28 +307,28 @@ TEST(CelixBundleContextBundlesTests, trackBundlesTest) {
     };
 
     long trackerId = celix_bundleContext_trackBundles(ctx, static_cast<void*>(&data), started, stopped);
-    CHECK_EQUAL(0, data.count); //note default framework bundle is not tracked
+    ASSERT_EQ(0, data.count); //note default framework bundle is not tracked
 
 
     long bundleId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
-    CHECK(bundleId1 >= 0);
+    ASSERT_TRUE(bundleId1 >= 0);
 
     {
         std::unique_lock<std::mutex> lock{data.mutex};
         data.cond.wait_for(lock, std::chrono::milliseconds(100), [&]{return data.count == 2;});
 
     }
-    CHECK_EQUAL(1, data.count);
+    ASSERT_EQ(1, data.count);
 
 
     long bundleId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, true);
-    CHECK(bundleId2 >= 0);
+    ASSERT_TRUE(bundleId2 >= 0);
     {
         std::unique_lock<std::mutex> lock{data.mutex};
         data.cond.wait_for(lock, std::chrono::milliseconds(100), [&]{return data.count == 3;});
 
     }
-    CHECK_EQUAL(2, data.count);
+    ASSERT_EQ(2, data.count);
 
     celix_bundleContext_uninstallBundle(ctx, bundleId2);
     {
@@ -330,31 +336,31 @@ TEST(CelixBundleContextBundlesTests, trackBundlesTest) {
         data.cond.wait_for(lock, std::chrono::milliseconds(100), [&]{return data.count == 2;});
 
     }
-    CHECK_EQUAL(2, data.count);
+    ASSERT_EQ(2, data.count);
 
     long bundleId3 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
-    CHECK(bundleId3 >= 0);
+    ASSERT_TRUE(bundleId3 >= 0);
     {
         std::unique_lock<std::mutex> lock{data.mutex};
         data.cond.wait_for(lock, std::chrono::milliseconds(100), [&]{return data.count == 3;});
 
     }
-    CHECK_EQUAL(3, data.count);
+    ASSERT_EQ(3, data.count);
 
     bundleId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, true);
-    CHECK(bundleId3 >= 0);
+    ASSERT_TRUE(bundleId3 >= 0);
     {
         std::unique_lock<std::mutex> lock{data.mutex};
         data.cond.wait_for(lock, std::chrono::milliseconds(100), [&]{return data.count == 4;});
 
     }
-    CHECK_EQUAL(4, data.count);
+    ASSERT_EQ(4, data.count);
 
 
     celix_bundleContext_stopTracker(ctx, trackerId);
 };
 
-TEST(CelixBundleContextBundlesTests, useBundlesConcurrentTest) {
+TEST_F(CelixBundleContextBundlesTests, useBundlesConcurrentTest) {
 
     struct data {
         std::mutex mutex{};
@@ -365,7 +371,7 @@ TEST(CelixBundleContextBundlesTests, useBundlesConcurrentTest) {
     struct data data{};
 
     auto use = [](void *handle, const bundle_t *bnd) {
-        CHECK(bnd != nullptr);
+        ASSERT_TRUE(bnd != nullptr);
 
         struct data *d = static_cast<struct data*>(handle);
 
@@ -380,7 +386,7 @@ TEST(CelixBundleContextBundlesTests, useBundlesConcurrentTest) {
 
     auto call = [&] {
         bool called = celix_bundleContext_useBundle(ctx, bndId, &data, use);
-        CHECK(called);
+        ASSERT_TRUE(called);
     };
     std::thread useThread{call};
 
@@ -413,7 +419,7 @@ TEST(CelixBundleContextBundlesTests, useBundlesConcurrentTest) {
     std::cout << "uninstall thread joined" << std::endl;
 };
 
-TEST(CelixBundleContextBundlesTests, bundleInfoTests) {
+TEST_F(CelixBundleContextBundlesTests, bundleInfoTests) {
     struct data {
         int provideCount{0};
         int requestedCount{0};
@@ -431,18 +437,18 @@ TEST(CelixBundleContextBundlesTests, bundleInfoTests) {
     };
 
     bool called = celix_bundleContext_useBundle(ctx, 0, &data, updateCountFp);
-    CHECK_TRUE(called);
-    CHECK_EQUAL(0, data.provideCount);
-    CHECK_EQUAL(0, data.requestedCount);
+    ASSERT_TRUE(called);
+    ASSERT_EQ(0, data.provideCount);
+    ASSERT_EQ(0, data.requestedCount);
 
 
     long svcId = celix_bundleContext_registerService(ctx, (void*)0x42, "NopService", NULL);
     long trackerId = celix_bundleContext_trackServices(ctx, "AService", NULL, NULL, NULL);
 
     called = celix_bundleContext_useBundle(ctx, 0, &data, updateCountFp);
-    CHECK_TRUE(called);
-    CHECK_EQUAL(1, data.provideCount);
-    CHECK_EQUAL(1, data.requestedCount);
+    ASSERT_TRUE(called);
+    ASSERT_EQ(1, data.provideCount);
+    ASSERT_EQ(1, data.requestedCount);
 
     celix_bundleContext_unregisterService(ctx, svcId);
     celix_bundleContext_stopTracker(ctx, trackerId);
diff --git a/libs/framework/test/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
similarity index 77%
rename from libs/framework/test/bundle_context_services_test.cpp
rename to libs/framework/gtest/src/bundle_context_services_test.cpp
index 262cae2..fa650a4 100644
--- a/libs/framework/test/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -17,14 +17,15 @@
  * under the License.
  */
 
+#include <gtest/gtest.h>
+
+
 #include <thread>
 #include <chrono>
 #include <iostream>
 #include <mutex>
 #include <condition_variable>
-#include <zconf.h>
 #include <string.h>
-#include <map>
 #include <future>
 
 #include "celix_api.h"
@@ -32,18 +33,13 @@
 #include "celix_service_factory.h"
 #include "service_tracker_private.h"
 
+class CelixBundleContextServicesTests : public ::testing::Test {
+public:
+    celix_framework_t* fw = nullptr;
+    celix_bundle_context_t *ctx = nullptr;
+    celix_properties_t *properties = nullptr;
 
-#include <CppUTest/TestHarness.h>
-#include <CppUTest/CommandLineTestRunner.h>
-
-
-
-TEST_GROUP(CelixBundleContextServicesTests) {
-    framework_t* fw = nullptr;
-    bundle_context_t *ctx = nullptr;
-    properties_t *properties = nullptr;
-
-    void setup() {
+    CelixBundleContextServicesTests() {
         properties = properties_create();
         properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
         properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
@@ -53,12 +49,17 @@ TEST_GROUP(CelixBundleContextServicesTests) {
         ctx = framework_getContext(fw);
     }
 
-    void teardown() {
+    ~CelixBundleContextServicesTests() override {
         celix_frameworkFactory_destroyFramework(fw);
     }
+
+    CelixBundleContextServicesTests(CelixBundleContextServicesTests&&) = delete;
+    CelixBundleContextServicesTests(const CelixBundleContextServicesTests&) = delete;
+    CelixBundleContextServicesTests& operator=(CelixBundleContextServicesTests&&) = delete;
+    CelixBundleContextServicesTests& operator=(const CelixBundleContextServicesTests&) = delete;
 };
 
-TEST(CelixBundleContextServicesTests, registerService) {
+TEST_F(CelixBundleContextServicesTests, registerService) {
     struct calc {
         int (*calc)(int);
     };
@@ -70,18 +71,18 @@ TEST(CelixBundleContextServicesTests, registerService) {
     };
 
     long svcId = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    CHECK(svcId >= 0);
+    ASSERT_TRUE(svcId >= 0);
     celix_bundleContext_unregisterService(ctx, svcId);
 };
 
-TEST(CelixBundleContextServicesTests, incorrectUnregisterCalls) {
+TEST_F(CelixBundleContextServicesTests, incorrectUnregisterCalls) {
     celix_bundleContext_unregisterService(ctx, 1);
     celix_bundleContext_unregisterService(ctx, 2);
     celix_bundleContext_unregisterService(ctx, -1);
     celix_bundleContext_unregisterService(ctx, -2);
 };
 
-TEST(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
+TEST_F(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
     struct calc {
         int (*calc)(int);
     };
@@ -93,16 +94,16 @@ TEST(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
     };
 
     long svcId1 = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    CHECK(svcId1 >= 0);
+    ASSERT_TRUE(svcId1 >= 0);
 
     long svcId2 = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    CHECK(svcId2 >= 0);
+    ASSERT_TRUE(svcId2 >= 0);
 
     long svcId3 = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    CHECK(svcId3 >= 0);
+    ASSERT_TRUE(svcId3 >= 0);
 
     auto use = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
         int *total =  static_cast<int*>(handle);
         struct calc *calc = static_cast<struct calc*>(svc);
         int tmp = calc->calc(1);
@@ -111,24 +112,24 @@ TEST(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
 
     int total = 0;
     celix_bundleContext_useServices(ctx, "calc", &total, use);
-    CHECK_EQUAL(42 * 3, total);
+    ASSERT_EQ(42 * 3, total);
 
 
     celix_bundleContext_unregisterService(ctx, svcId3);
     total = 0;
     celix_bundleContext_useServices(ctx, "calc", &total, use);
-    CHECK_EQUAL(42 * 2, total);
+    ASSERT_EQ(42 * 2, total);
 
     total = 0;
     bool called = celix_bundleContext_useService(ctx, "calc", &total, use);
-    CHECK(called);
-    CHECK_EQUAL(42, total);
+    ASSERT_TRUE(called);
+    ASSERT_EQ(42, total);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
     celix_bundleContext_unregisterService(ctx, svcId2);
 };
 
-TEST(CelixBundleContextServicesTests, registerAndUseService) {
+TEST_F(CelixBundleContextServicesTests, registerAndUseService) {
     struct calc {
         int (*calc)(int);
     };
@@ -140,18 +141,18 @@ TEST(CelixBundleContextServicesTests, registerAndUseService) {
     };
 
     long svcId = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    CHECK(svcId >= 0);
+    ASSERT_TRUE(svcId >= 0);
 
     int result = 0;
     bool called = celix_bundleContext_useServiceWithId(ctx, svcId, calcName, &result, [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
         int *result =  static_cast<int*>(handle);
         struct calc *calc = static_cast<struct calc*>(svc);
         int tmp = calc->calc(2);
         *result = tmp;
     });
-    CHECK(called);
-    CHECK_EQUAL(84, result);
+    ASSERT_TRUE(called);
+    ASSERT_EQ(84, result);
 
     result = 0;
     long nonExistingSvcId = 101;
@@ -161,13 +162,13 @@ TEST(CelixBundleContextServicesTests, registerAndUseService) {
         int tmp = calc->calc(2);
         *result = tmp;
     });
-    CHECK(!called);
-    CHECK_EQUAL(0, result); //e.g. not called
+    ASSERT_TRUE(!called);
+    ASSERT_EQ(0, result); //e.g. not called
 
     celix_bundleContext_unregisterService(ctx, svcId);
 };
 
-TEST(CelixBundleContextServicesTests, registerAndUseServiceWithTimeout) {
+TEST_F(CelixBundleContextServicesTests, registerAndUseServiceWithTimeout) {
     struct calc {
         int (*calc)(int);
     };
@@ -182,7 +183,7 @@ TEST(CelixBundleContextServicesTests, registerAndUseServiceWithTimeout) {
     opts.filter.serviceName = "calc";
 
     bool called = celix_bundleContext_useServiceWithOptions(ctx, &opts);
-    CHECK(!called); //service not avail.
+    ASSERT_TRUE(!called); //service not avail.
 
     std::future<bool> result{std::async([&]{
         opts.waitTimeoutInSeconds = 5.0;
@@ -192,10 +193,10 @@ TEST(CelixBundleContextServicesTests, registerAndUseServiceWithTimeout) {
         return calledAsync;
     })};
     long svcId = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    CHECK(svcId >= 0);
+    ASSERT_TRUE(svcId >= 0);
 
 
-    CHECK(result.get()); //should return true after waiting for the registered service.
+    ASSERT_TRUE(result.get()); //should return true after waiting for the registered service.
 
 
     celix_bundleContext_unregisterService(ctx, svcId);
@@ -209,12 +210,12 @@ TEST(CelixBundleContextServicesTests, registerAndUseServiceWithTimeout) {
         printf("returned from use service with timeout. calc called %s.\n", calledAsync ? "true" : "false");
         return calledAsync;
     })};
-    CHECK(!result2.get());
+    ASSERT_TRUE(!result2.get());
 
     celix_bundleContext_unregisterService(ctx, svcId);
 }
 
-TEST(CelixBundleContextServicesTests, registerAndUseServiceWithCorrectVersion) {
+TEST_F(CelixBundleContextServicesTests, registerAndUseServiceWithCorrectVersion) {
     struct calc {
         int (*calc)(int);
     };
@@ -235,7 +236,7 @@ TEST(CelixBundleContextServicesTests, registerAndUseServiceWithCorrectVersion) {
     reg_opts.svc = &svc;
 
     bool called = celix_bundleContext_useServiceWithOptions(ctx, &use_opts);
-    CHECK(!called); //service not avail.
+    ASSERT_TRUE(!called); //service not avail.
 
     std::future<bool> result{std::async([&]{
         use_opts.waitTimeoutInSeconds = 5.0;
@@ -245,14 +246,14 @@ TEST(CelixBundleContextServicesTests, registerAndUseServiceWithCorrectVersion) {
         return calledAsync;
     })};
     long svcId = celix_bundleContext_registerServiceWithOptions(ctx, &reg_opts);
-    CHECK(svcId >= 0);
+    ASSERT_TRUE(svcId >= 0);
 
-    CHECK(result.get()); //should return true after waiting for the registered service.
+    ASSERT_TRUE(result.get()); //should return true after waiting for the registered service.
 
     celix_bundleContext_unregisterService(ctx, svcId);
 }
 
-TEST(CelixBundleContextServicesTests, registerAndUseServiceWithIncorrectVersion) {
+TEST_F(CelixBundleContextServicesTests, registerAndUseServiceWithIncorrectVersion) {
     struct calc {
         int (*calc)(int);
     };
@@ -273,7 +274,7 @@ TEST(CelixBundleContextServicesTests, registerAndUseServiceWithIncorrectVersion)
     reg_opts.svc = &svc;
 
     bool called = celix_bundleContext_useServiceWithOptions(ctx, &use_opts);
-    CHECK(!called); //service not avail.
+    ASSERT_TRUE(!called); //service not avail.
 
     std::future<bool> result{std::async([&]{
         use_opts.waitTimeoutInSeconds = 1.0;
@@ -283,13 +284,13 @@ TEST(CelixBundleContextServicesTests, registerAndUseServiceWithIncorrectVersion)
         return calledAsync;
     })};
     long svcId = celix_bundleContext_registerServiceWithOptions(ctx, &reg_opts);
-    CHECK(svcId >= 0);
-    CHECK(!result.get());
+    ASSERT_TRUE(svcId >= 0);
+    ASSERT_TRUE(!result.get());
 
     celix_bundleContext_unregisterService(ctx, svcId);
 }
 
-TEST(CelixBundleContextServicesTests, registerAndUseWithForcedRaceCondition) {
+TEST_F(CelixBundleContextServicesTests, registerAndUseWithForcedRaceCondition) {
     struct calc {
         int (*calc)(int);
     };
@@ -301,7 +302,7 @@ TEST(CelixBundleContextServicesTests, registerAndUseWithForcedRaceCondition) {
     };
 
     long svcId = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    CHECK(svcId >= 0);
+    ASSERT_TRUE(svcId >= 0);
 
     struct sync {
         std::mutex mutex{};
@@ -314,7 +315,7 @@ TEST(CelixBundleContextServicesTests, registerAndUseWithForcedRaceCondition) {
     struct sync callInfo{};
 
     auto use = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
 
         struct sync *h = static_cast<struct sync*>(handle);
 
@@ -333,8 +334,8 @@ TEST(CelixBundleContextServicesTests, registerAndUseWithForcedRaceCondition) {
 
     auto call = [&] {
         bool called = celix_bundleContext_useServiceWithId(ctx, svcId, calcName, &callInfo, use);
-        CHECK(called);
-        CHECK_EQUAL(84, callInfo.result);
+        ASSERT_TRUE(called);
+        ASSERT_EQ(84, callInfo.result);
     };
     std::thread useThread{call};
 
@@ -369,71 +370,71 @@ TEST(CelixBundleContextServicesTests, registerAndUseWithForcedRaceCondition) {
 };
 
 
-TEST(CelixBundleContextServicesTests, servicesTrackerTest) {
+TEST_F(CelixBundleContextServicesTests, servicesTrackerTest) {
     int count = 0;
     auto add = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
         int *c = static_cast<int*>(handle);
         *c += 1;
     };
     auto remove = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
         int *c = static_cast<int*>(handle);
         *c -= 1;
     };
 
     long trackerId = celix_bundleContext_trackServices(ctx, "calc", &count, add, remove);
-    CHECK(trackerId > 0);
-    CHECK_EQUAL(0, count);
+    ASSERT_TRUE(trackerId > 0);
+    ASSERT_EQ(0, count);
 
     long svcId1 = celix_bundleContext_registerService(ctx, (void*)0x100, "calc", nullptr);
-    CHECK(svcId1 > 0);
-    CHECK_EQUAL(1, count);
+    ASSERT_TRUE(svcId1 > 0);
+    ASSERT_EQ(1, count);
 
     long svcId2 = celix_bundleContext_registerService(ctx, (void*)0x200, "calc", nullptr);
-    CHECK(svcId2 > 0);
-    CHECK_EQUAL(2, count);
+    ASSERT_TRUE(svcId2 > 0);
+    ASSERT_EQ(2, count);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
-    CHECK_EQUAL(1, count);
+    ASSERT_EQ(1, count);
 
     celix_bundleContext_stopTracker(ctx, trackerId);
     celix_bundleContext_unregisterService(ctx, svcId2);
 }
 
-TEST(CelixBundleContextServicesTests, servicesTrackerInvalidArgsTest) {
+TEST_F(CelixBundleContextServicesTests, servicesTrackerInvalidArgsTest) {
     long trackerId = celix_bundleContext_trackServices(nullptr, nullptr, nullptr, nullptr, nullptr);
-    CHECK(trackerId < 0); //required ctx and service name missing
+    ASSERT_TRUE(trackerId < 0); //required ctx and service name missing
     trackerId = celix_bundleContext_trackServices(ctx, nullptr, nullptr, nullptr, nullptr);
-    CHECK(trackerId < 0); //required service name missing
+    ASSERT_TRUE(trackerId < 0); //required service name missing
     trackerId = celix_bundleContext_trackServices(ctx, "calc", nullptr, nullptr, nullptr);
-    CHECK(trackerId >= 0); //valid
+    ASSERT_TRUE(trackerId >= 0); //valid
     celix_bundleContext_stopTracker(ctx, trackerId);
 
 
     //opts
     trackerId = celix_bundleContext_trackServicesWithOptions(nullptr, nullptr);
-    CHECK(trackerId < 0); //required ctx and opts missing
+    ASSERT_TRUE(trackerId < 0); //required ctx and opts missing
     trackerId = celix_bundleContext_trackServicesWithOptions(ctx, nullptr);
-    CHECK(trackerId < 0); //required opts missing
+    ASSERT_TRUE(trackerId < 0); //required opts missing
     celix_service_tracking_options_t opts{};
     trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
-    CHECK(trackerId < 0); //required opts->serviceName missing
+    ASSERT_TRUE(trackerId < 0); //required opts->serviceName missing
     opts.filter.serviceName = "calc";
     trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
-    CHECK(trackerId >= 0); //valid
+    ASSERT_TRUE(trackerId >= 0); //valid
     celix_bundleContext_stopTracker(ctx, trackerId);
 }
 
-TEST(CelixBundleContextServicesTests, servicesTrackerTestWithAlreadyRegisteredServices) {
+TEST_F(CelixBundleContextServicesTests, servicesTrackerTestWithAlreadyRegisteredServices) {
     int count = 0;
     auto add = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
         int *c = static_cast<int*>(handle);
         *c += 1;
     };
     auto remove = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
         int *c = static_cast<int*>(handle);
         *c -= 1;
     };
@@ -444,37 +445,37 @@ TEST(CelixBundleContextServicesTests, servicesTrackerTestWithAlreadyRegisteredSe
 
 
     long trackerId = celix_bundleContext_trackServices(ctx, "calc", &count, add, remove);
-    CHECK(trackerId > 0);
-    CHECK_EQUAL(2, count);
+    ASSERT_TRUE(trackerId > 0);
+    ASSERT_EQ(2, count);
 
     long svcId3 = celix_bundleContext_registerService(ctx, (void*)0x100, "calc", nullptr);
-    CHECK(svcId1 > 0);
-    CHECK_EQUAL(3, count);
+    ASSERT_TRUE(svcId1 > 0);
+    ASSERT_EQ(3, count);
 
     long svcId4 = celix_bundleContext_registerService(ctx, (void*)0x200, "calc", nullptr);
-    CHECK(svcId2 > 0);
-    CHECK_EQUAL(4, count);
+    ASSERT_TRUE(svcId2 > 0);
+    ASSERT_EQ(4, count);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
     celix_bundleContext_unregisterService(ctx, svcId3);
-    CHECK_EQUAL(2, count);
+    ASSERT_EQ(2, count);
 
     celix_bundleContext_stopTracker(ctx, trackerId);
     celix_bundleContext_unregisterService(ctx, svcId2);
     celix_bundleContext_unregisterService(ctx, svcId4);
 }
 
-TEST(CelixBundleContextServicesTests, servicesTrackerTestWithProperties) {
+TEST_F(CelixBundleContextServicesTests, servicesTrackerTestWithProperties) {
     int count = 0;
     auto add = [](void *handle, void *svc, const properties_t *props) {
-        CHECK(svc != nullptr);
-        STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+        ASSERT_TRUE(svc != nullptr);
+        ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
         int *c = static_cast<int*>(handle);
         *c += 1;
     };
     auto remove = [](void *handle, void *svc, const properties_t *props) {
-        CHECK(svc != nullptr);
-        STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+        ASSERT_TRUE(svc != nullptr);
+        ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
         int *c = static_cast<int*>(handle);
         *c -= 1;
     };
@@ -487,33 +488,33 @@ TEST(CelixBundleContextServicesTests, servicesTrackerTestWithProperties) {
     opts.addWithProperties = add;
     opts.removeWithProperties = remove;
     long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
-    CHECK(trackerId > 0);
-    CHECK_EQUAL(1, count);
+    ASSERT_TRUE(trackerId > 0);
+    ASSERT_EQ(1, count);
 
     long svcId2 = celix_bundleContext_registerService(ctx, (void*)0x200, "calc", nullptr);
-    CHECK(svcId1 > 0);
-    CHECK_EQUAL(2, count);
+    ASSERT_TRUE(svcId1 > 0);
+    ASSERT_EQ(2, count);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
     celix_bundleContext_unregisterService(ctx, svcId2);
-    CHECK_EQUAL(0, count);
+    ASSERT_EQ(0, count);
 
     celix_bundleContext_stopTracker(ctx, trackerId);
 }
 
-TEST(CelixBundleContextServicesTests, servicesTrackerTestWithOwner) {
+TEST_F(CelixBundleContextServicesTests, servicesTrackerTestWithOwner) {
     int count = 0;
     auto add = [](void *handle, void *svc, const properties_t *props, const bundle_t *svcOwner) {
-        CHECK(svc != nullptr);
-        STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
-        CHECK(celix_bundle_getId(svcOwner) >= 0);
+        ASSERT_TRUE(svc != nullptr);
+        ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+        ASSERT_TRUE(celix_bundle_getId(svcOwner) >= 0);
         int *c = static_cast<int*>(handle);
         *c += 1;
     };
     auto remove = [](void *handle, void *svc, const properties_t *props, const bundle_t *svcOwner) {
-        CHECK(svc != nullptr);
-        STRCMP_EQUAL("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
-        CHECK(celix_bundle_getId(svcOwner) >= 0);
+        ASSERT_TRUE(svc != nullptr);
+        ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+        ASSERT_TRUE(celix_bundle_getId(svcOwner) >= 0);
         int *c = static_cast<int*>(handle);
         *c -= 1;
     };
@@ -526,21 +527,21 @@ TEST(CelixBundleContextServicesTests, servicesTrackerTestWithOwner) {
     opts.addWithOwner = add;
     opts.removeWithOwner = remove;
     long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
-    CHECK(trackerId > 0);
-    CHECK_EQUAL(1, count);
+    ASSERT_TRUE(trackerId > 0);
+    ASSERT_EQ(1, count);
 
     long svcId2 = celix_bundleContext_registerService(ctx, (void*)0x200, "calc", nullptr);
-    CHECK(svcId1 > 0);
-    CHECK_EQUAL(2, count);
+    ASSERT_TRUE(svcId1 > 0);
+    ASSERT_EQ(2, count);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
     celix_bundleContext_unregisterService(ctx, svcId2);
-    CHECK_EQUAL(0, count);
+    ASSERT_EQ(0, count);
 
     celix_bundleContext_stopTracker(ctx, trackerId);
 }
 
-TEST(CelixBundleContextServicesTests, serviceTrackerWithRaceConditionTest) {
+TEST_F(CelixBundleContextServicesTests, serviceTrackerWithRaceConditionTest) {
     struct calc {
         int (*calc)(int);
     };
@@ -563,7 +564,7 @@ TEST(CelixBundleContextServicesTests, serviceTrackerWithRaceConditionTest) {
     struct data data{};
 
     auto add = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
 
         struct data *d = static_cast<struct data*>(handle);
 
@@ -582,7 +583,7 @@ TEST(CelixBundleContextServicesTests, serviceTrackerWithRaceConditionTest) {
     };
 
     auto remove = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
 
         struct data *d = static_cast<struct data*>(handle);
 
@@ -636,14 +637,14 @@ TEST(CelixBundleContextServicesTests, serviceTrackerWithRaceConditionTest) {
     unregisterThread.join();
     std::cout << "threads joined" << std::endl;
 
-    CHECK_EQUAL(84, data.result);
-    CHECK(data.inAddCall);
-    CHECK(data.inRemoveCall);
+    ASSERT_EQ(84, data.result);
+    ASSERT_TRUE(data.inAddCall);
+    ASSERT_TRUE(data.inRemoveCall);
 
     celix_bundleContext_stopTracker(ctx, trackerId);
 };
 
-TEST(CelixBundleContextServicesTests, servicesTrackerSetTest) {
+TEST_F(CelixBundleContextServicesTests, servicesTrackerSetTest) {
     int count = 0;
 
     void *svc1 = (void*)0x100; //no ranking
@@ -652,18 +653,18 @@ TEST(CelixBundleContextServicesTests, servicesTrackerSetTest) {
     void *svc4 = (void*)0x400; //5 ranking
 
     auto set = [](void *handle, void *svc) {
-        CHECK(svc != nullptr);
+        ASSERT_TRUE(svc != nullptr);
         static int callCount = 0;
         callCount += 1;
         if (callCount == 1) {
             //first time svc1 should be set (oldest service with equal ranking
-            CHECK_EQUAL(0x100, (long)svc);
+            ASSERT_EQ(0x100, (long)svc);
         } else if (callCount == 2) {
-            CHECK_EQUAL(0x300, (long)svc);
+            ASSERT_EQ(0x300, (long)svc);
             //second time svc3 should be set (highest ranking)
         } else if (callCount == 3) {
             //third time svc4 should be set (highest ranking
-            CHECK_EQUAL(0x400, (long)svc);
+            ASSERT_EQ(0x400, (long)svc);
         }
 
         int *c = static_cast<int*>(handle);
@@ -679,7 +680,7 @@ TEST(CelixBundleContextServicesTests, servicesTrackerSetTest) {
     opts.filter.serviceName = "NA";
     opts.set = set;
     long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
-    CHECK(trackerId > 0);
+    ASSERT_TRUE(trackerId > 0);
 
     //register svc3 should lead to second set call
     properties_t *props3 = celix_properties_create();
@@ -699,13 +700,13 @@ TEST(CelixBundleContextServicesTests, servicesTrackerSetTest) {
     celix_bundleContext_unregisterService(ctx, svcId2);
     celix_bundleContext_unregisterService(ctx, svcId4);
 
-    CHECK_EQUAL(3, count); //check if the set is called the expected times
+    ASSERT_EQ(3, count); //check if the set is called the expected times
 }
 
 //TODO test tracker with options for properties & service owners
 
 
-TEST(CelixBundleContextServicesTests, serviceFactoryTest) {
+TEST_F(CelixBundleContextServicesTests, serviceFactoryTest) {
     struct calc {
         int (*calc)(int);
     };
@@ -728,7 +729,7 @@ TEST(CelixBundleContextServicesTests, serviceFactoryTest) {
     };
 
     long facId = celix_bundleContext_registerServiceFactory(ctx, &fac, name, nullptr);
-    CHECK_TRUE(facId >= 0);
+    ASSERT_TRUE(facId >= 0);
 
 
     int result = -1;
@@ -737,30 +738,30 @@ TEST(CelixBundleContextServicesTests, serviceFactoryTest) {
         auto *calc = (struct calc*)svc;
         *r = calc->calc(2);
     });
-    CHECK_TRUE(called);
-    CHECK_EQUAL(84, result);
-    CHECK_EQUAL(2, count); //expecting getService & unGetService to be called during the useService call.
+    ASSERT_TRUE(called);
+    ASSERT_EQ(84, result);
+    ASSERT_EQ(2, count); //expecting getService & unGetService to be called during the useService call.
 
 
     celix_bundleContext_unregisterService(ctx, facId);
 }
 
-TEST(CelixBundleContextServicesTests, findServicesTest) {
+TEST_F(CelixBundleContextServicesTests, findServicesTest) {
     long svcId1 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
     long svcId2 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
 
     long foundId = celix_bundleContext_findService(ctx, "non existing service name");
-    CHECK_EQUAL(-1L, foundId);
+    ASSERT_EQ(-1L, foundId);
 
     foundId = celix_bundleContext_findService(ctx, "example");
-    CHECK_EQUAL(foundId, svcId1); //oldest should have highest ranking
+    ASSERT_EQ(foundId, svcId1); //oldest should have highest ranking
 
     array_list_t *list = celix_bundleContext_findServices(ctx, "non existintg service name");
-    CHECK_EQUAL(0, celix_arrayList_size(list));
+    ASSERT_EQ(0, celix_arrayList_size(list));
     arrayList_destroy(list);
 
     list = celix_bundleContext_findServices(ctx, "example");
-    CHECK_EQUAL(2, celix_arrayList_size(list));
+    ASSERT_EQ(2, celix_arrayList_size(list));
     arrayList_destroy(list);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
@@ -768,50 +769,50 @@ TEST(CelixBundleContextServicesTests, findServicesTest) {
     celix_service_filter_options_t opts{};
     opts.serviceName = "example";
     foundId = celix_bundleContext_findServiceWithOptions(ctx, &opts);
-    CHECK_EQUAL(foundId, svcId2); //only one left
+    ASSERT_EQ(foundId, svcId2); //only one left
 
     celix_bundleContext_unregisterService(ctx, svcId2);
 }
 
-TEST(CelixBundleContextServicesTests, trackServiceTrackerTest) {
+TEST_F(CelixBundleContextServicesTests, trackServiceTrackerTest) {
 
     int count = 0;
 
     auto add = [](void *handle, const celix_service_tracker_info_t *info) {
-        STRCMP_EQUAL("example", info->serviceName);
-        STRCMP_EQUAL(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
+        ASSERT_STRCASEEQ("example", info->serviceName);
+        ASSERT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
         auto *c = static_cast<int*>(handle);
         *c += 1;
     };
     auto remove = [](void *handle, const celix_service_tracker_info_t *info) {
-        STRCMP_EQUAL("example", info->serviceName);
-        STRCMP_EQUAL(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
+        ASSERT_STRCASEEQ("example", info->serviceName);
+        ASSERT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
         auto *c = static_cast<int*>(handle);
         *c -= 1;
     };
 
     long trackerId = celix_bundleContext_trackServiceTrackers(ctx, "example", &count, add, remove);
-    CHECK_TRUE(trackerId >= 0);
-    CHECK_EQUAL(0, count);
+    ASSERT_TRUE(trackerId >= 0);
+    ASSERT_EQ(0, count);
 
     long tracker2 = celix_bundleContext_trackService(ctx, "example", nullptr, nullptr);
-    CHECK_TRUE(tracker2 >= 0);
-    CHECK_EQUAL(1, count);
+    ASSERT_TRUE(tracker2 >= 0);
+    ASSERT_EQ(1, count);
 
     long tracker3 = celix_bundleContext_trackServices(ctx, "example", nullptr, nullptr, nullptr);
-    CHECK_TRUE(tracker3 >= 0);
-    CHECK_EQUAL(2, count);
+    ASSERT_TRUE(tracker3 >= 0);
+    ASSERT_EQ(2, count);
 
     long tracker4 = celix_bundleContext_trackServices(ctx, "no-match", nullptr, nullptr, nullptr);
-    CHECK_TRUE(tracker4 >= 0);
-    CHECK_EQUAL(2, count);
+    ASSERT_TRUE(tracker4 >= 0);
+    ASSERT_EQ(2, count);
 
     celix_bundleContext_stopTracker(ctx, tracker2);
     celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on separate track -> need sync
-    CHECK_EQUAL(1, count);
+    ASSERT_EQ(1, count);
     celix_bundleContext_stopTracker(ctx, tracker3);
     celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on separate track -> need sync
-    CHECK_EQUAL(0, count);
+    ASSERT_EQ(0, count);
 
     celix_bundleContext_stopTracker(ctx, trackerId);
     celix_bundleContext_stopTracker(ctx, tracker4);
diff --git a/libs/framework/test/dm_tests.cpp b/libs/framework/gtest/src/dm_tests.cpp
similarity index 67%
rename from libs/framework/test/dm_tests.cpp
rename to libs/framework/gtest/src/dm_tests.cpp
index 81eb8c0..18ed4e1 100644
--- a/libs/framework/test/dm_tests.cpp
+++ b/libs/framework/gtest/src/dm_tests.cpp
@@ -17,18 +17,17 @@
  * under the License.
  */
 
-#include "celix_api.h"
-
-#include <CppUTest/TestHarness.h>
-#include <CppUTest/CommandLineTestRunner.h>
+#include <gtest/gtest.h>
 
+#include "celix_api.h"
 
-TEST_GROUP(DepenencyManagerTests) {
-    framework_t* fw = nullptr;
-    bundle_context_t *ctx = nullptr;
-    properties_t *properties = nullptr;
+class DepenencyManagerTests : public ::testing::Test {
+public:
+    celix_framework_t* fw = nullptr;
+    celix_bundle_context_t *ctx = nullptr;
+    celix_properties_t *properties = nullptr;
 
-    void setup() {
+    DepenencyManagerTests() {
         properties = properties_create();
         properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
         properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
@@ -38,27 +37,32 @@ TEST_GROUP(DepenencyManagerTests) {
         ctx = framework_getContext(fw);
     }
 
-    void teardown() {
+    ~DepenencyManagerTests() override {
         celix_frameworkFactory_destroyFramework(fw);
     }
+
+    DepenencyManagerTests(DepenencyManagerTests&&) = delete;
+    DepenencyManagerTests(const DepenencyManagerTests&) = delete;
+    DepenencyManagerTests& operator=(DepenencyManagerTests&&) = delete;
+    DepenencyManagerTests& operator=(const DepenencyManagerTests&) = delete;
 };
 
-TEST(DepenencyManagerTests, DmCreateComponent) {
+TEST_F(DepenencyManagerTests, DmCreateComponent) {
     auto *mng = celix_bundleContext_getDependencyManager(ctx);
     auto *cmp = celix_dmComponent_create(ctx, "test1");
     celix_dependencyManager_add(mng, cmp);
 
-    CHECK_EQUAL(1, celix_dependencyManager_nrOfComponents(mng));
-    CHECK_TRUE(celix_dependencyManager_allComponentsActive(mng));
+    ASSERT_EQ(1, celix_dependencyManager_nrOfComponents(mng));
+    ASSERT_TRUE(celix_dependencyManager_allComponentsActive(mng));
 
     cmp = celix_dmComponent_create(ctx, "test2");
     celix_dependencyManager_add(mng, cmp);
 
-    CHECK_EQUAL(2, celix_dependencyManager_nrOfComponents(mng));
-    CHECK_TRUE(celix_dependencyManager_allComponentsActive(mng));
+    ASSERT_EQ(2, celix_dependencyManager_nrOfComponents(mng));
+    ASSERT_TRUE(celix_dependencyManager_allComponentsActive(mng));
 }
 
-TEST(DepenencyManagerTests, TestCheckActive) {
+TEST_F(DepenencyManagerTests, TestCheckActive) {
     auto *mng = celix_bundleContext_getDependencyManager(ctx);
     auto *cmp = celix_dmComponent_create(ctx, "test1");
 
@@ -69,5 +73,5 @@ TEST(DepenencyManagerTests, TestCheckActive) {
 
 
     celix_dependencyManager_add(mng, cmp);
-    CHECK_FALSE(celix_dependencyManager_areComponentsActive(mng));
+    ASSERT_FALSE(celix_dependencyManager_areComponentsActive(mng));
 }
diff --git a/libs/framework/test/multiple_frameworks_test.cpp b/libs/framework/gtest/src/multiple_frameworks_test.cpp
similarity index 84%
rename from libs/framework/test/multiple_frameworks_test.cpp
rename to libs/framework/gtest/src/multiple_frameworks_test.cpp
index 0797980..910f2b9 100644
--- a/libs/framework/test/multiple_frameworks_test.cpp
+++ b/libs/framework/gtest/src/multiple_frameworks_test.cpp
@@ -17,8 +17,7 @@
  * under the License.
  */
 
-#include <CppUTest/TestHarness.h>
-#include <CppUTest/CommandLineTestRunner.h>
+#include <gtest/gtest.h>
 
 extern "C" {
 
@@ -44,26 +43,26 @@ extern "C" {
 
         //server
         rc = celixLauncher_launch("framework1.properties", &serverFramework);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
 
         bundle = nullptr;
         rc = framework_getFrameworkBundle(serverFramework, &bundle);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
 
         rc = bundle_getContext(bundle, &serverContext);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
 
 
         //client
         rc = celixLauncher_launch("framework2.properties", &clientFramework);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
 
         bundle = nullptr;
         rc = framework_getFrameworkBundle(clientFramework, &bundle);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
 
         rc = bundle_getContext(bundle, &clientContext);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
     }
 
     static void teardownFm(void) {
@@ -88,17 +87,17 @@ extern "C" {
 
 }
 
-
-TEST_GROUP(CelixMultipleFrameworks) {
-    void setup() {
+class CelixMultipleFrameworks : public ::testing::Test {
+public:
+    CelixMultipleFrameworks() {
         setupFm();
     }
 
-    void teardown() {
+    ~CelixMultipleFrameworks() override {
         teardownFm();
     }
 };
 
-TEST(CelixMultipleFrameworks, testFrameworks) {
+TEST_F(CelixMultipleFrameworks, testFrameworks) {
     testFrameworks();
 }
diff --git a/libs/framework/test/nop_activator.c b/libs/framework/gtest/src/nop_activator.c
similarity index 100%
rename from libs/framework/test/nop_activator.c
rename to libs/framework/gtest/src/nop_activator.c
diff --git a/libs/framework/test/run_tests.cpp b/libs/framework/gtest/src/run_tests.cpp
similarity index 79%
rename from libs/framework/test/run_tests.cpp
rename to libs/framework/gtest/src/run_tests.cpp
index efaee82..339f725 100644
--- a/libs/framework/test/run_tests.cpp
+++ b/libs/framework/gtest/src/run_tests.cpp
@@ -17,10 +17,10 @@
  * under the License.
  */
 
-#include <CppUTest/TestHarness.h>
-#include "CppUTest/CommandLineTestRunner.h"
+#include <gtest/gtest.h>
 
-int main(int argc, char** argv) {
-    MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
-    return RUN_ALL_TESTS(argc, argv);
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int rc = RUN_ALL_TESTS();
+    return rc;
 }
\ No newline at end of file
diff --git a/libs/framework/test/single_framework_test.cpp b/libs/framework/gtest/src/single_framework_test.cpp
similarity index 77%
rename from libs/framework/test/single_framework_test.cpp
rename to libs/framework/gtest/src/single_framework_test.cpp
index b13342b..f2015dd 100644
--- a/libs/framework/test/single_framework_test.cpp
+++ b/libs/framework/gtest/src/single_framework_test.cpp
@@ -17,8 +17,7 @@
  * under the License.
  */
 
-#include <CppUTest/TestHarness.h>
-#include <CppUTest/CommandLineTestRunner.h>
+#include <gtest/gtest.h>
 
 extern "C" {
 
@@ -32,21 +31,21 @@ extern "C" {
 #include "celix_framework_factory.h"
 
 
-    static framework_pt framework = nullptr;
-    static bundle_context_pt context = nullptr;
+    static celix_framework_t *framework = nullptr;
+    static celix_bundle_context_t *context = nullptr;
 
     static void setupFm(void) {
         int rc = 0;
 
         rc = celixLauncher_launch("config.properties", &framework);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
 
         bundle_pt bundle = nullptr;
         rc = framework_getFrameworkBundle(framework, &bundle);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
 
         rc = bundle_getContext(bundle, &context);
-        CHECK_EQUAL(CELIX_SUCCESS, rc);
+        ASSERT_EQ(CELIX_SUCCESS, rc);
     }
 
     static void teardownFm(void) {
@@ -64,38 +63,40 @@ extern "C" {
         printf("testing startup/shutdown single framework\n");
     }
 
-    //TODO test register / use service
-
 }
 
 
-TEST_GROUP(CelixFramework) {
-    void setup() {
+class CelixFramework : public ::testing::Test {
+public:
+    CelixFramework() {
         setupFm();
     }
 
-    void teardown() {
+    ~CelixFramework() override {
         teardownFm();
     }
 };
 
-TEST(CelixFramework, testFramework) {
+TEST_F(CelixFramework, testFramework) {
     testFramework();
 }
 
-TEST_GROUP(FrameworkFactory) {
+class FrameworkFactory : public ::testing::Test {
+public:
+    FrameworkFactory() = default;
+    ~FrameworkFactory() override = default;
 };
 
 
-TEST(FrameworkFactory, testFactoryCreate) {
+TEST_F(FrameworkFactory, testFactoryCreate) {
     framework_t* fw = celix_frameworkFactory_createFramework(nullptr);
-    CHECK(fw != nullptr);
+    ASSERT_TRUE(fw != nullptr);
     celix_frameworkFactory_destroyFramework(fw);
 }
 
-TEST(FrameworkFactory, testFactoryCreateAndToManyStartAndStops) {
+TEST_F(FrameworkFactory, testFactoryCreateAndToManyStartAndStops) {
     framework_t* fw = celix_frameworkFactory_createFramework(nullptr);
-    CHECK(fw != nullptr);
+    ASSERT_TRUE(fw != nullptr);
 
     framework_start(fw); //should already be done by frameworkFactory_newFramework();
     framework_start(fw);
@@ -112,9 +113,9 @@ TEST(FrameworkFactory, testFactoryCreateAndToManyStartAndStops) {
     framework_destroy(fw); //note stop, wait and then destroy is needed .. combine ?
 }
 
-TEST(FrameworkFactory, restartFramework) {
+TEST_F(FrameworkFactory, restartFramework) {
     framework_t* fw = celix_frameworkFactory_createFramework(nullptr);
-    CHECK(fw != nullptr);
+    ASSERT_TRUE(fw != nullptr);
 
 
     /* TODO fix mem leak in restarting framework
diff --git a/libs/framework/test/subdir/CMakeLists.txt b/libs/framework/gtest/subdir/CMakeLists.txt
similarity index 100%
rename from libs/framework/test/subdir/CMakeLists.txt
rename to libs/framework/gtest/subdir/CMakeLists.txt
diff --git a/libs/framework/test/subdir/src/foo.c b/libs/framework/gtest/subdir/src/foo.c
similarity index 100%
rename from libs/framework/test/subdir/src/foo.c
rename to libs/framework/gtest/subdir/src/foo.c