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 <[email protected]>
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:[email protected]";>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) {

Reply via email to