Merge pull request #286 from apache/feature/async_svc_registration

Feature/async svc registration
diff --git a/bundles/http_admin/http_admin/src/http_admin.c b/bundles/http_admin/http_admin/src/http_admin.c
index ca7c93d..20b2287 100755
--- a/bundles/http_admin/http_admin/src/http_admin.c
+++ b/bundles/http_admin/http_admin/src/http_admin.c
@@ -122,17 +122,17 @@
 
     //Destroy alias map by removing symbolic links first.
     unsigned int size = celix_arrayList_size(admin->aliasList);
-    for (unsigned int i = (size - 1); i < size; i--) {
+    for (int i = 0; i < size; ++i) {
         http_alias_t *alias = celix_arrayList_get(admin->aliasList, i);
 
         //Delete alias in cache directory
-        if (remove(alias->alias_path) < 0)
+        if (remove(alias->alias_path) < 0) {
             fprintf(stdout, "remove of %s failed\n", alias->alias_path);
+        }
 
         free(alias->url);
         free(alias->alias_path);
         free(alias);
-        celix_arrayList_removeAt(admin->aliasList, i);
     }
     celix_arrayList_destroy(admin->aliasList);
 
@@ -520,6 +520,7 @@
         http_alias_t *alias = arrayList_get(admin->aliasList, i);
         if(alias->bundle_id == bundle_id) {
             remove(alias->alias_path); //Delete alias in cache directory
+            free(alias->url);
             free(alias->alias_path);
             free(alias);
             celix_arrayList_removeAt(admin->aliasList, i);
diff --git a/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc b/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc
index 56a9ce5..b385a19 100644
--- a/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc
+++ b/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc
@@ -34,6 +34,7 @@
         auto* properties = celix_properties_create();
         celix_properties_set(properties, "org.osgi.framework.storage", ".cacheLogBundleTestSuite");
 
+
         auto* fwPtr = celix_frameworkFactory_createFramework(properties);
         auto* ctxPtr = celix_framework_getFrameworkContext(fwPtr);
         fw = std::shared_ptr<celix_framework_t>{fwPtr, [](celix_framework_t* f) {celix_frameworkFactory_destroyFramework(f);}};
@@ -120,6 +121,10 @@
     EXPECT_EQ(0, control->nrOfSinks(control->handle, nullptr));
 
     celix_log_sink_t logSink;
+    logSink.handle = nullptr;
+    logSink.sinkLog = [](void */*handle*/, celix_log_level_e /*level*/, long /*logServiceId*/, const char* /*logServiceName*/, const char* /*file*/, const char* /*function*/, int /*line*/, const char */*format*/, va_list /*formatArgs*/) {
+        //nop
+    };
     celix_service_registration_options_t opts{};
     opts.serviceName = CELIX_LOG_SINK_NAME;
     opts.serviceVersion = CELIX_LOG_SINK_VERSION;
@@ -147,6 +152,11 @@
 
 TEST_F(LogBundleTestSuite, SinkLogControl) {
     celix_log_sink_t logSink;
+    logSink.handle = nullptr;
+    logSink.sinkLog = [](void */*handle*/, celix_log_level_e /*level*/, long /*logServiceId*/, const char* /*logServiceName*/, const char* /*file*/, const char* /*function*/, int /*line*/, const char */*format*/, va_list /*formatArgs*/) {
+        //nop
+    };
+
     celix_service_registration_options_t opts{};
     opts.serviceName = CELIX_LOG_SINK_NAME;
     opts.serviceVersion = CELIX_LOG_SINK_VERSION;
@@ -214,6 +224,7 @@
 TEST_F(LogBundleTestSuite, LogServiceControl) {
     //request "default" log service
     long trkId1 = celix_bundleContext_trackService(ctx.get(), CELIX_LOG_SERVICE_NAME, NULL, NULL);
+    celix_framework_waitForEmptyEventQueue(fw.get());
     EXPECT_EQ(2, control->nrOfLogServices(control->handle, nullptr));
 
     //request a 'logger1' log service
@@ -221,10 +232,12 @@
     opts.filter.serviceName = CELIX_LOG_SERVICE_NAME;
     opts.filter.filter = "(name=test::group::Log1)";
     long trkId2 = celix_bundleContext_trackServicesWithOptions(ctx.get(), &opts);
+    celix_framework_waitForEmptyEventQueue(fw.get());
     EXPECT_EQ(3, control->nrOfLogServices(control->handle, nullptr));
 
     opts.filter.filter = "(name=test::group::Log2)";
     long trkId3 = celix_bundleContext_trackServicesWithOptions(ctx.get(), &opts);
+    celix_framework_waitForEmptyEventQueue(fw.get());
     EXPECT_EQ(4, control->nrOfLogServices(control->handle, nullptr));
     EXPECT_EQ(2, control->nrOfLogServices(control->handle, "test::group"));
 
@@ -267,7 +280,9 @@
 
     EXPECT_GE(level, CELIX_LOG_LEVEL_TRACE);
     EXPECT_GE(logServiceId, 0);
-    EXPECT_STREQ("test::Log1", logServiceName);
+    if (level == CELIX_LOG_LEVEL_FATAL) {
+        EXPECT_STREQ("test::Log1", logServiceName);
+    }
 
     vfprintf(stdout, format, formatArgs);
 
@@ -276,6 +291,11 @@
 
 TEST_F(LogBundleTestSuite, LogServiceAndSink) {
     celix_log_sink_t logSink;
+    logSink.handle = nullptr;
+    logSink.sinkLog = [](void */*handle*/, celix_log_level_e /*level*/, long /*logServiceId*/, const char* /*logServiceName*/, const char* /*file*/, const char* /*function*/, int /*line*/, const char */*format*/, va_list /*formatArgs*/) {
+        //nop
+    };
+
     std::atomic<size_t> count{0};
     logSink.handle = (void*)&count;
     logSink.sinkLog = logSinkFunction;
@@ -307,31 +327,32 @@
         };
         trkId = celix_bundleContext_trackServicesWithOptions(ctx.get(), &opts);
     }
+    celix_framework_waitForEmptyEventQueue(fw.get());
 
     ASSERT_TRUE(logSvc.load() != nullptr);
-    EXPECT_EQ(0, count.load());
+    auto initial = count.load();
     celix_log_service_t *ls = logSvc.load();
     ls->info(ls->handle, "test %i %i %i", 1, 2, 3); //active log level
-    EXPECT_EQ(1, count.load());
+    EXPECT_EQ(initial +1, count.load());
     ls->debug(ls->handle, "test %i %i %i", 1, 2, 3); //note not a active log level
-    EXPECT_EQ(1, count.load());
+    EXPECT_EQ(initial +1, count.load());
 
     control->setActiveLogLevels(control->handle, "test::Log1", CELIX_LOG_LEVEL_DEBUG);
     ls->debug(ls->handle, "test %i %i %i", 1, 2, 3); //active log level
-    EXPECT_EQ(2, count.load());
+    EXPECT_EQ(initial +2, count.load());
 
     control->setActiveLogLevels(control->handle, "test::Log1", CELIX_LOG_LEVEL_DISABLED);
     ls->debug(ls->handle, "test %i %i %i", 1, 2, 3); //log service disable
-    EXPECT_EQ(2, count.load());
+    EXPECT_EQ(initial +2, count.load());
 
     control->setActiveLogLevels(control->handle, "test::Log1", CELIX_LOG_LEVEL_TRACE);
     control->setSinkEnabled(control->handle, "test::Sink1", false);
     ls->debug(ls->handle, "test %i %i %i", 1, 2, 3); //active log level and enabled log service, but sink disabled.
-    EXPECT_EQ(2, count.load());
+    EXPECT_EQ(initial +2, count.load());
 
     control->setSinkEnabled(control->handle, "test::Sink1", true);
     ls->debug(ls->handle, "test %i %i %i", 1, 2, 3); //all enabled and active again
-    EXPECT_EQ(3, count.load());
+    EXPECT_EQ(initial +3, count.load());
 
     ls->trace(ls->handle, "test %i %i %i", 1, 2, 3); //+1
     ls->debug(ls->handle, "test %i %i %i", 1, 2, 3); //+1
@@ -341,18 +362,23 @@
     ls->fatal(ls->handle, "test %i %i %i", 1, 2, 3); //+1
     ls->log(ls->handle, CELIX_LOG_LEVEL_ERROR, "error"); //+1
     ls->logDetails(ls->handle, CELIX_LOG_LEVEL_ERROR, __FILE__, __FUNCTION__, __LINE__, "error"); //+1
-    EXPECT_EQ(11, count.load());
+    EXPECT_EQ(initial +11, count.load());
 
     celix_bundleContext_unregisterService(ctx.get(), svcId); //no log sink anymore
 
     ls->fatal(ls->handle, "test %i %i %i", 1, 2, 3); //+0 (no log to sink, fallback to stdout)
-    EXPECT_EQ(11, count.load());
+    EXPECT_EQ(initial +11, count.load());
 
     celix_bundleContext_stopTracker(ctx.get(), trkId);
 }
 
 TEST_F(LogBundleTestSuite, LogAdminCmd) {
     celix_log_sink_t logSink;
+    logSink.handle = nullptr;
+    logSink.sinkLog = [](void */*handle*/, celix_log_level_e /*level*/, long /*logServiceId*/, const char* /*logServiceName*/, const char* /*file*/, const char* /*function*/, int /*line*/, const char */*format*/, va_list /*formatArgs*/) {
+        //nop
+    };
+
     long svcId;
     {
         auto *svcProps = celix_properties_create();
diff --git a/bundles/logging/log_admin/src/celix_log_admin.c b/bundles/logging/log_admin/src/celix_log_admin.c
index 26849c2..b048cb7 100644
--- a/bundles/logging/log_admin/src/celix_log_admin.c
+++ b/bundles/logging/log_admin/src/celix_log_admin.c
@@ -195,6 +195,24 @@
         newEntry->logSvc.vlog = celix_logAdmin_vlog;
         newEntry->logSvc.vlogDetails = celix_logAdmin_vlogDetails;
         hashMap_put(admin->loggers, (void*)newEntry->name, newEntry);
+        celixThreadRwlock_unlock(&admin->lock);
+
+        {
+            //register new log service async
+            celix_properties_t* props = celix_properties_create();
+            celix_properties_set(props, CELIX_LOG_SERVICE_PROPERTY_NAME, newEntry->name);
+            if (celix_utils_stringEquals(newEntry->name, CELIX_LOG_ADMIN_DEFAULT_LOG_NAME) == 0) {
+                //ensure that the default log service is found when no name filter is used.
+                celix_properties_setLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, 100);
+            }
+
+            celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+            opts.serviceName = CELIX_LOG_SERVICE_NAME;
+            opts.serviceVersion = CELIX_LOG_SERVICE_VERSION;
+            opts.properties = props;
+            opts.svc = &newEntry->logSvc;
+            newEntry->logSvcId = celix_bundleContext_registerServiceWithOptionsAsync(admin->ctx, &opts);
+        }
 
         if (celix_utils_stringEquals(newEntry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) {
             celix_framework_t* fw = celix_bundleContext_getFramework(admin->ctx);
@@ -202,24 +220,7 @@
         }
     } else {
         found->count += 1;
-    }
-    celixThreadRwlock_unlock(&admin->lock);
-
-    if (newEntry != NULL) {
-        //register new instance
-        celix_properties_t* props = celix_properties_create();
-        celix_properties_set(props, CELIX_LOG_SERVICE_PROPERTY_NAME, newEntry->name);
-        if (celix_utils_stringEquals(newEntry->name, CELIX_LOG_ADMIN_DEFAULT_LOG_NAME) == 0) {
-            //ensure that the default log service is found when no name filter is used.
-            celix_properties_setLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, 100);
-        }
-
-        celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
-        opts.serviceName = CELIX_LOG_SERVICE_NAME;
-        opts.serviceVersion = CELIX_LOG_SERVICE_VERSION;
-        opts.properties = props;
-        opts.svc = &newEntry->logSvc;
-        newEntry->logSvcId = celix_bundleContext_registerServiceWithOptions(admin->ctx, &opts);
+        celixThreadRwlock_unlock(&admin->lock);
     }
 }
 
@@ -232,31 +233,28 @@
     celix_logAdmin_addLogSvcForName(admin, name);
 }
 
-static void celix_logAdmin_remLogSvcForName(celix_log_admin_t* admin, const char* name) {
-    celix_log_service_entry_t* remEntry = NULL;
+static void celix_logAdmin_freeLogEntry(void *data) {
+    celix_log_service_entry_t* entry = data;
+    if (celix_utils_stringEquals(entry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) {
+        celix_framework_t* fw = celix_bundleContext_getFramework(entry->admin->ctx);
+        celix_framework_setLogCallback(fw, NULL, NULL);
+    }
+    free(entry->name);
+    free(entry);
+}
 
+static void celix_logAdmin_remLogSvcForName(celix_log_admin_t* admin, const char* name) {
     celixThreadRwlock_writeLock(&admin->lock);
     celix_log_service_entry_t* found = hashMap_get(admin->loggers, name);
     if (found != NULL) {
         found->count -= 1;
         if (found->count == 0) {
             //remove
-            remEntry = found;
             hashMap_remove(admin->loggers, name);
+            celix_bundleContext_unregisterServiceAsync(admin->ctx, found->logSvcId, found, celix_logAdmin_freeLogEntry);
         }
     }
     celixThreadRwlock_unlock(&admin->lock);
-
-    if (remEntry != NULL) {
-        if (celix_utils_stringEquals(remEntry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) {
-            celix_framework_t* fw = celix_bundleContext_getFramework(admin->ctx);
-            celix_framework_setLogCallback(fw, NULL, NULL);
-        }
-
-        celix_bundleContext_unregisterService(admin->ctx, remEntry->logSvcId);
-        free(remEntry->name);
-        free(remEntry);
-    }
 }
 
 
@@ -311,7 +309,7 @@
 
     celixThreadRwlock_writeLock(&admin->lock);
     celix_log_sink_entry_t* entry = hashMap_get(admin->sinks, sinkName);
-    if (entry->svcId != svcId) {
+    if (entry != NULL && entry->svcId != svcId) {
         //no match (note there can be invalid log sinks with the same name, but different svc ids.
         entry = NULL;
     }
@@ -591,10 +589,10 @@
         opts.callbackHandle = admin;
         opts.addWithProperties = celix_logAdmin_addSink;
         opts.removeWithProperties = celix_logAdmin_remSink;
-        admin->logWriterTrackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+        admin->logWriterTrackerId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts);
     }
 
-    admin->logServiceMetaTrackerId = celix_bundleContext_trackServiceTrackers(ctx, CELIX_LOG_SERVICE_NAME, admin, celix_logAdmin_trackerAdd, celix_logAdmin_trackerRem);
+    admin->logServiceMetaTrackerId = celix_bundleContext_trackServiceTrackersAsync(ctx, CELIX_LOG_SERVICE_NAME, admin, celix_logAdmin_trackerAdd, celix_logAdmin_trackerRem, NULL, NULL);
 
     {
         admin->controlSvc.handle = admin;
@@ -612,7 +610,7 @@
         opts.serviceName = CELIX_LOG_CONTROL_NAME;
         opts.serviceVersion = CELIX_LOG_CONTROL_VERSION;
         opts.svc = &admin->controlSvc;
-        admin->controlSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts);
+        admin->controlSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
     }
 
     {
@@ -629,12 +627,11 @@
         opts.serviceVersion = CELIX_SHELL_COMMAND_SERVICE_VERSION;
         opts.properties = props;
         opts.svc = &admin->cmdSvc;
-        admin->cmdSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts);
+        admin->cmdSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
     }
 
     //add log service for the framework
     celix_logAdmin_addLogSvcForName(admin, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME);
-
     return admin;
 }
 
@@ -642,10 +639,11 @@
     if (admin != NULL) {
         celix_logAdmin_remLogSvcForName(admin, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME);
 
-        celix_bundleContext_unregisterService(admin->ctx, admin->cmdSvcId);
-        celix_bundleContext_unregisterService(admin->ctx, admin->controlSvcId);
-        celix_bundleContext_stopTracker(admin->ctx, admin->logServiceMetaTrackerId);
-        celix_bundleContext_stopTracker(admin->ctx, admin->logWriterTrackerId);
+        celix_bundleContext_unregisterServiceAsync(admin->ctx, admin->cmdSvcId, NULL, NULL);
+        celix_bundleContext_unregisterServiceAsync(admin->ctx, admin->controlSvcId, NULL, NULL);
+        celix_bundleContext_stopTrackerAsync(admin->ctx, admin->logServiceMetaTrackerId, NULL, NULL);
+        celix_bundleContext_stopTrackerAsync(admin->ctx, admin->logWriterTrackerId, NULL, NULL);
+        celix_bundleContext_waitForEvents(admin->ctx);
 
         assert(hashMap_size(admin->loggers) == 0); //note stopping service tracker tracker should triggered all needed remove events
         hashMap_destroy(admin->loggers, false, false);
diff --git a/bundles/pubsub/pubsub_admin_zmq/v2/src/pubsub_zmq_admin.c b/bundles/pubsub/pubsub_admin_zmq/v2/src/pubsub_zmq_admin.c
index 1434f8d..f6dc84b 100644
--- a/bundles/pubsub/pubsub_admin_zmq/v2/src/pubsub_zmq_admin.c
+++ b/bundles/pubsub/pubsub_admin_zmq/v2/src/pubsub_zmq_admin.c
@@ -459,6 +459,12 @@
     return status;
 }
 
+static void pubsub_zmqAdmin_getSerType(void *handle, void *svc __attribute__((unused)), const celix_properties_t* props) {
+    const char** out = handle;
+    *out = celix_properties_get(props, PUBSUB_MESSAGE_SERIALIZATION_SERVICE_SERIALIZATION_TYPE_PROPERTY, NULL);
+}
+
+
 celix_status_t pubsub_zmqAdmin_setupTopicSender(void *handle, const char *scope, const char *topic, const celix_properties_t *topicProperties, long serializerSvcId __attribute__((unused)), long protocolSvcId, celix_properties_t **outPublisherEndpoint) {
     pubsub_zmq_admin_t *psa = handle;
     celix_status_t  status = CELIX_SUCCESS;
@@ -475,7 +481,17 @@
         staticBindUrl = celix_properties_get(topicProperties, PUBSUB_ZMQ_STATIC_BIND_URL, NULL);
     }
     char *key = pubsubEndpoint_createScopeTopicKey(scope, topic);
-    const char *serType = celix_properties_get(topicProperties, PUBSUB_SERIALIZER_TYPE_KEY, NULL);
+
+    //get serializer type
+    const char *serType = NULL;
+    celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
+    opts.callbackHandle = &serType;
+    opts.useWithProperties = pubsub_zmqAdmin_getSerType;
+    opts.filter.serviceName = PUBSUB_MESSAGE_SERIALIZATION_SERVICE_NAME;
+    char filter[32];
+    snprintf(filter, 32, "(%s=%li)", OSGI_FRAMEWORK_SERVICE_ID, serializerSvcId);
+    opts.filter.filter = filter;
+    celix_bundleContext_useServiceWithOptions(psa->ctx, &opts);
 
     celixThreadMutex_lock(&psa->protocols.mutex);
     celixThreadMutex_lock(&psa->topicSenders.mutex);
@@ -570,7 +586,17 @@
     celix_properties_t *newEndpoint = NULL;
 
     char *key = pubsubEndpoint_createScopeTopicKey(scope, topic);
-    const char *serType = celix_properties_get(topicProperties, PUBSUB_SERIALIZER_TYPE_KEY, NULL);
+
+    //get serializer type
+    const char *serType = NULL;
+    celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
+    opts.callbackHandle = &serType;
+    opts.useWithProperties = pubsub_zmqAdmin_getSerType;
+    opts.filter.serviceName = PUBSUB_MESSAGE_SERIALIZATION_SERVICE_NAME;
+    char filter[32];
+    snprintf(filter, 32, "(%s=%li)", OSGI_FRAMEWORK_SERVICE_ID, serializerSvcId);
+    opts.filter.filter = filter;
+    celix_bundleContext_useServiceWithOptions(psa->ctx, &opts);
 
     celixThreadMutex_lock(&psa->protocols.mutex);
     celixThreadMutex_lock(&psa->topicReceivers.mutex);
diff --git a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
index a7e9386..9d1ffe9 100644
--- a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
+++ b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
@@ -170,10 +170,8 @@
     data.topic = topic;
     celix_bundleContext_useBundle(ctx, bundleId, &data, retrieveTopicProperties);
 
-    if (data.props != NULL) {
-        pubsubEndpoint_setFields(ep, fwUUID, scope, topic, PUBSUB_PUBLISHER_ENDPOINT_TYPE, NULL, NULL, NULL, data.props);
-        celix_properties_destroy(data.props); //safe to delete, properties are copied in pubsubEndpoint_setFields
-    }
+    pubsubEndpoint_setFields(ep, fwUUID, scope, topic, PUBSUB_PUBLISHER_ENDPOINT_TYPE, NULL, NULL, NULL, data.props);
+    celix_properties_destroy(data.props); //safe to delete, properties are copied in pubsubEndpoint_setFields
 
     if (!pubsubEndpoint_isValid(ep, false, false)) {
         celix_properties_destroy(ep);
diff --git a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint_match.c b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint_match.c
index ef99ff5..92ebe69 100644
--- a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint_match.c
+++ b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint_match.c
@@ -56,38 +56,21 @@
     return score;
 }
 
-struct psa_serializer_selection_data {
-    const char *requested_serializer;
-    long matchingSvcId;
-};
-
-void psa_serializer_selection_callback(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    struct psa_serializer_selection_data *data = handle;
-    const char *serType = celix_properties_get(props, PUBSUB_SERIALIZER_TYPE_KEY, NULL);
-    if (serType == NULL) {
-        fprintf(stderr, "Warning found serializer without mandatory serializer type key (%s)\n", PUBSUB_SERIALIZER_TYPE_KEY);
-    } else {
-        if (strncmp(data->requested_serializer, serType, 1024 * 1024) == 0) {
-            data->matchingSvcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        }
-    }
-}
-
 static long getPSASerializer(celix_bundle_context_t *ctx, const char *requested_serializer) {
-    long svcId;
+    long svcId = -1L;
 
     if (requested_serializer != NULL) {
-        struct psa_serializer_selection_data data;
-        data.requested_serializer = requested_serializer;
-        data.matchingSvcId = -1L;
+        char filter[512];
+        snprintf(filter, 512, "(%s=%s)", PUBSUB_SERIALIZER_TYPE_KEY, requested_serializer);
 
-        celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-        opts.filter.serviceName = PUBSUB_SERIALIZER_SERVICE_NAME;
-        opts.filter.ignoreServiceLanguage = true;
-        opts.callbackHandle = &data;
-        opts.useWithProperties = psa_serializer_selection_callback;
-        celix_bundleContext_useServicesWithOptions(ctx, &opts);
-        svcId = data.matchingSvcId;
+        celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS;
+        opts.serviceName = PUBSUB_SERIALIZER_SERVICE_NAME;
+        opts.filter = filter;
+
+        svcId = celix_bundleContext_findServiceWithOptions(ctx, &opts);
+        if (svcId == -1) {
+            fprintf(stderr, "Warning cannot find serializer with requested serializer type '%s'\n", requested_serializer);
+        }
     } else {
         celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS;
         opts.serviceName = PUBSUB_SERIALIZER_SERVICE_NAME;
diff --git a/bundles/pubsub/pubsub_utils/src/pubsub_matching.c b/bundles/pubsub/pubsub_utils/src/pubsub_matching.c
index 48ca2ce..66193f9 100644
--- a/bundles/pubsub/pubsub_utils/src/pubsub_matching.c
+++ b/bundles/pubsub/pubsub_utils/src/pubsub_matching.c
@@ -33,51 +33,20 @@
     celix_properties_t *outEndpoint;
 } ps_utils_retrieve_topic_properties_data_t;
 
-void ps_utils_serializer_selection_callback(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    struct ps_utils_serializer_selection_data *data = handle;
-    const char *serType = celix_properties_get(props, PUBSUB_MESSAGE_SERIALIZATION_SERVICE_SERIALIZATION_TYPE_PROPERTY, NULL);
-    long foundRanking = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, -1);
-    if (serType == NULL) {
-        fprintf(stderr, "Warning found serializer without mandatory serializer type key (%s)\n", PUBSUB_MESSAGE_SERIALIZATION_SERVICE_SERIALIZATION_TYPE_PROPERTY);
-    } else {
-        if (strncmp(data->requested_serializer, serType, 1024 * 1024) == 0 && foundRanking > data->matchingRanking) {
-            data->matchingRanking = foundRanking;
-            data->matchingSvcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        }
-    }
-}
-
-
-
-void ps_protocol_selection_callback(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    struct ps_utils_protocol_selection_data *data = handle;
-    const char *serType = celix_properties_get(props, PUBSUB_PROTOCOL_TYPE_KEY, NULL);
-    if (serType == NULL) {
-        fprintf(stderr, "Warning found protocol without mandatory protocol type key (%s)\n", PUBSUB_PROTOCOL_TYPE_KEY);
-    } else {
-        if (strncmp(data->requested_protocol, serType, 1024 * 1024) == 0) {
-            data->matchingSvcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        }
-    }
-}
-
-
 static long getPSSerializer(celix_bundle_context_t *ctx, const char *requested_serializer) {
-    long svcId;
+    long svcId = -1L;
 
     if (requested_serializer != NULL) {
-        struct ps_utils_serializer_selection_data data;
-        data.requested_serializer = requested_serializer;
-        data.matchingSvcId = -1L;
-        data.matchingRanking = -2L;
-
-        celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-        opts.filter.serviceName = PUBSUB_MESSAGE_SERIALIZATION_SERVICE_NAME;
-        opts.filter.ignoreServiceLanguage = true;
-        opts.callbackHandle = &data;
-        opts.useWithProperties = ps_utils_serializer_selection_callback;
-        celix_bundleContext_useServicesWithOptions(ctx, &opts);
-        svcId = data.matchingSvcId;
+        char filter[512];
+        int written = snprintf(filter, 512, "(%s=%s)", PUBSUB_MESSAGE_SERIALIZATION_SERVICE_SERIALIZATION_TYPE_PROPERTY, requested_serializer);
+        if (written > 512) {
+            fprintf(stderr, "Cannot create serializer filter. need more than 512 char array\n");
+        } else {
+            celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS;
+            opts.serviceName = PUBSUB_MESSAGE_SERIALIZATION_SERVICE_NAME;
+            opts.filter = filter;
+            svcId = celix_bundleContext_findServiceWithOptions(ctx, &opts);
+        }
     } else {
         celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS;
         opts.serviceName = PUBSUB_MESSAGE_SERIALIZATION_SERVICE_NAME;
@@ -118,20 +87,19 @@
 }
 
 static long getPSProtocol(celix_bundle_context_t *ctx, const char *requested_protocol) {
-    long svcId;
+    long svcId = -1L;
 
     if (requested_protocol != NULL) {
-        struct ps_utils_protocol_selection_data data;
-        data.requested_protocol = requested_protocol;
-        data.matchingSvcId = -1L;
-
-        celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-        opts.filter.serviceName = PUBSUB_PROTOCOL_SERVICE_NAME;
-        opts.filter.ignoreServiceLanguage = true;
-        opts.callbackHandle = &data;
-        opts.useWithProperties = ps_protocol_selection_callback;
-        celix_bundleContext_useServicesWithOptions(ctx, &opts);
-        svcId = data.matchingSvcId;
+        char filter[512];
+        int written = snprintf(filter, 512, "(%s=%s)", PUBSUB_PROTOCOL_TYPE_KEY, requested_protocol);
+        if (written > 512) {
+            fprintf(stderr, "Cannot create protocol filter. need more than 512 char array\n");
+        } else {
+            celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS;
+            opts.serviceName = PUBSUB_PROTOCOL_SERVICE_NAME;
+            opts.filter = filter;
+            svcId = celix_bundleContext_findServiceWithOptions(ctx, &opts);
+        }
     } else {
         celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS;
         opts.serviceName = PUBSUB_PROTOCOL_SERVICE_NAME;
diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
index e3a8000..0f1cbb9 100644
--- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
+++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
@@ -315,6 +315,7 @@
     act->testSvc.testCreateRemoteServiceInRemoteCall = testCreateRemoteServiceInRemoteCall;
     act->testSvc.testCreateDestroyComponentWithRemoteService = bndTestCreateDestroyComponentWithRemoteService;
 
+    act->testSvc.testCreateRemoteServiceInRemoteCall = testCreateRemoteServiceInRemoteCall;
 
     //create mutex
     pthread_mutex_init(&act->mutex, NULL);
diff --git a/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c
index c34a67d..40e26f3 100644
--- a/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c
+++ b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c
@@ -112,6 +112,7 @@
     celix_status_t status;
     struct disc_mock_activator * act = userData;
 
+    serviceRegistration_unregister(act->endpointListenerService);
     status = serviceRegistration_unregister(act->reg);
 
     return status;
diff --git a/bundles/shell/shell/src/help_command.c b/bundles/shell/shell/src/help_command.c
index fa124bb..a2ad219 100644
--- a/bundles/shell/shell/src/help_command.c
+++ b/bundles/shell/shell/src/help_command.c
@@ -57,6 +57,7 @@
         for (i = 0; i < arrayList_size(commands); i++) {
             char *name = arrayList_get(commands, i);
             fprintf(out, "%s\n", name);
+            free(name);
         }
         fprintf(out, "\nUse 'help <command-name>' for more information.\n");
         celix_arrayList_destroy(commands);
diff --git a/bundles/shell/shell/src/shell.c b/bundles/shell/shell/src/shell.c
index d3fb27d..d4f063b 100644
--- a/bundles/shell/shell/src/shell.c
+++ b/bundles/shell/shell/src/shell.c
@@ -33,11 +33,8 @@
 
     shell->ctx = ctx;
     shell->logHelper = celix_logHelper_create(ctx, "celix_shell");
-
-    celix_thread_mutexattr_t attr;
-    celixThreadMutexAttr_create(&attr);
-    celixThreadMutexAttr_settype(&attr, CELIX_THREAD_MUTEX_RECURSIVE); //NOTE recursive, because command can also use the shell service
-    celixThreadMutex_create(&shell->mutex, &attr);
+    
+    celixThreadRwlock_create(&shell->lock, NULL);
     shell->commandServices = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
     shell->legacyCommandServices = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
 
@@ -46,9 +43,11 @@
 
 void shell_destroy(shell_t *shell) {
     if (shell != NULL) {
-        celixThreadMutex_destroy(&shell->mutex);
+        celixThreadRwlock_writeLock(&shell->lock);
         hashMap_destroy(shell->commandServices, false, false);
         hashMap_destroy(shell->legacyCommandServices, false, false);
+        celixThreadRwlock_unlock(&shell->lock);
+        celixThreadRwlock_destroy(&shell->lock);
         celix_logHelper_destroy(shell->logHelper);
         free(shell);
     }
@@ -64,7 +63,7 @@
         status = CELIX_BUNDLE_EXCEPTION;
     } else {
         long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        celixThreadMutex_lock(&shell->mutex);
+        celixThreadRwlock_writeLock(&shell->lock);
         if (hashMap_containsKey(shell->commandServices, name)) {
             celix_logHelper_log(shell->logHelper, CELIX_LOG_LEVEL_WARNING, "Command with name %s already registered!", name);
         } else {
@@ -79,7 +78,7 @@
             entry->localName = localName;
             hashMap_put(shell->commandServices, (void*)name, entry);
         }
-        celixThreadMutex_unlock(&shell->mutex);
+        celixThreadRwlock_unlock(&shell->lock);
     }
 
     return status;
@@ -94,7 +93,7 @@
         status = CELIX_BUNDLE_EXCEPTION;
     } else {
         long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        celixThreadMutex_lock(&shell->mutex);
+        celixThreadRwlock_writeLock(&shell->lock);
         if (hashMap_containsKey(shell->commandServices, name)) {
             celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, name);
             if (entry->svcId == svcId) {
@@ -108,7 +107,7 @@
         } else {
             celix_logHelper_log(shell->logHelper, CELIX_LOG_LEVEL_WARNING, "Cannot find shell command with name %s!", name);
         }
-        celixThreadMutex_unlock(&shell->mutex);
+        celixThreadRwlock_unlock(&shell->lock);
     }
 
     return status;
@@ -124,7 +123,7 @@
         status = CELIX_BUNDLE_EXCEPTION;
     } else {
         long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        celixThreadMutex_lock(&shell->mutex);
+        celixThreadRwlock_writeLock(&shell->lock);
         if (hashMap_containsKey(shell->legacyCommandServices, name)) {
             celix_logHelper_log(shell->logHelper, CELIX_LOG_LEVEL_WARNING, "Command with name %s already registered!", name);
         } else {
@@ -134,7 +133,7 @@
             entry->props = props;
             hashMap_put(shell->legacyCommandServices, (void*)name, entry);
         }
-        celixThreadMutex_unlock(&shell->mutex);
+        celixThreadRwlock_unlock(&shell->lock);
     }
 
     return status;
@@ -151,7 +150,7 @@
         status = CELIX_BUNDLE_EXCEPTION;
     } else {
         long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        celixThreadMutex_lock(&shell->mutex);
+        celixThreadRwlock_writeLock(&shell->lock);
         if (hashMap_containsKey(shell->legacyCommandServices, name)) {
             celix_legacy_command_entry_t *entry = hashMap_get(shell->legacyCommandServices, name);
             if (entry->svcId == svcId) {
@@ -163,7 +162,7 @@
         } else {
             celix_logHelper_log(shell->logHelper, CELIX_LOG_LEVEL_WARNING, "Cannot find shell command with name %s!", name);
         }
-        celixThreadMutex_unlock(&shell->mutex);
+        celixThreadRwlock_unlock(&shell->lock);
     }
 
     return status;
@@ -174,7 +173,7 @@
 	celix_status_t status = CELIX_SUCCESS;
 	celix_array_list_t *result = celix_arrayList_create();
 
-    celixThreadMutex_lock(&shell->mutex);
+    celixThreadRwlock_readLock(&shell->lock);
     hash_map_iterator_t iter = hashMapIterator_construct(shell->commandServices);
     while (hashMapIterator_hasNext(&iter)) {
         const char *name = hashMapIterator_nextKey(&iter);
@@ -186,7 +185,7 @@
         const char *name = hashMapIterator_nextKey(&iter);
         celix_arrayList_add(result, strndup(name, 1024*1024*10));
     }
-    celixThreadMutex_unlock(&shell->mutex);
+    celixThreadRwlock_unlock(&shell->lock);
 
     *outCommands = result;
 
@@ -197,7 +196,7 @@
 celix_status_t shell_getCommandUsage(shell_t *shell, const char *commandName, char **outUsage) {
     celix_status_t status = CELIX_SUCCESS;
 
-    celixThreadMutex_lock(&shell->mutex);
+    celixThreadRwlock_readLock(&shell->lock);
     celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, commandName);
     celix_legacy_command_entry_t *legacyEntry = hashMap_get(shell->legacyCommandServices, commandName);
     if (entry != NULL) {
@@ -209,7 +208,7 @@
     } else {
         *outUsage = NULL;
     }
-    celixThreadMutex_unlock(&shell->mutex);
+    celixThreadRwlock_unlock(&shell->lock);
 
     return status;
 }
@@ -217,7 +216,7 @@
 celix_status_t shell_getCommandDescription(shell_t *shell, const char *commandName, char **outDescription) {
     celix_status_t status = CELIX_SUCCESS;
 
-    celixThreadMutex_lock(&shell->mutex);
+    celixThreadRwlock_readLock(&shell->lock);
     celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, commandName);
     celix_legacy_command_entry_t *legacyEntry = hashMap_get(shell->legacyCommandServices, commandName);
     if (entry != NULL) {
@@ -229,7 +228,7 @@
     } else {
         *outDescription = NULL;
     }
-    celixThreadMutex_unlock(&shell->mutex);
+    celixThreadRwlock_unlock(&shell->lock);
 
     return status;
 }
@@ -270,7 +269,7 @@
     char *commandName = (pos != strlen(commandLine)) ? strndup(commandLine, pos) : strdup(commandLine);
 
 
-    celixThreadMutex_lock(&shell->mutex);
+    celixThreadRwlock_readLock(&shell->lock);
     celix_shell_command_entry_t *entry = shell_findEntry(shell, commandName, err);
     celix_legacy_command_entry_t *legacyEntry = hashMap_get(shell->legacyCommandServices, commandName);
     if (entry != NULL) {
@@ -283,7 +282,7 @@
         fprintf(err, "No command '%s'. Provided command line: %s\n", commandName, commandLine);
         status = CELIX_BUNDLE_EXCEPTION;
     }
-    celixThreadMutex_unlock(&shell->mutex);
+    celixThreadRwlock_unlock(&shell->lock);
     free(commandName);
 
 	return status;
diff --git a/bundles/shell/shell/src/shell_private.h b/bundles/shell/shell/src/shell_private.h
index ad602bc..4afa972 100644
--- a/bundles/shell/shell/src/shell_private.h
+++ b/bundles/shell/shell/src/shell_private.h
@@ -63,7 +63,7 @@
 struct shell {
 	celix_bundle_context_t *ctx;
     celix_log_helper_t *logHelper;
-    celix_thread_mutex_t mutex; //protects below
+    celix_thread_rwlock_t lock; //protects below
     hash_map_t *commandServices; //key = char* (fully qualified command name), value = celix_shell_command_entry_t*
     hash_map_t *legacyCommandServices; //key = char* (command name), value = celix_legacy_command_entry_t*
 };
diff --git a/bundles/shell/shell/test/CMakeLists.txt b/bundles/shell/shell/test/CMakeLists.txt
index 4ae6f29..ebf4d1e 100644
--- a/bundles/shell/shell/test/CMakeLists.txt
+++ b/bundles/shell/shell/test/CMakeLists.txt
@@ -18,12 +18,10 @@
 find_package(CppUTest REQUIRED)
 
 add_executable(test_shell
-    src/run_tests.cpp
-    src/shell_tests.cpp
+        src/ShellTestSuite.cpp
 )
 
-target_link_libraries(test_shell PRIVATE Celix::framework CURL::libcurl ${CppUTest_LIBRARY} Celix::shell_api)
-target_include_directories(test_shell SYSTEM PRIVATE ${CppUTest_INCLUDE_DIRS})
+target_link_libraries(test_shell PRIVATE Celix::framework CURL::libcurl Celix::shell_api GTest::gtest GTest::gtest_main)
 add_dependencies(test_shell shell_bundle)
 target_compile_definitions(test_shell PRIVATE -DSHELL_BUNDLE_LOCATION=\"$<TARGET_PROPERTY:shell,BUNDLE_FILE>\")
 target_compile_options(test_shell PRIVATE -Wno-deprecated-declarations)
diff --git a/bundles/shell/shell/test/src/shell_tests.cpp b/bundles/shell/shell/test/src/ShellTestSuite.cpp
similarity index 60%
rename from bundles/shell/shell/test/src/shell_tests.cpp
rename to bundles/shell/shell/test/src/ShellTestSuite.cpp
index c0e09f4..bdf4fa6 100644
--- a/bundles/shell/shell/test/src/shell_tests.cpp
+++ b/bundles/shell/shell/test/src/ShellTestSuite.cpp
@@ -17,55 +17,45 @@
  * under the License.
  */
 
+#include <gtest/gtest.h>
 
 #include "celix_shell_command.h"
 #include "celix_api.h"
 #include "celix_shell.h"
 
-#include <CppUTest/TestHarness.h>
-#include <CppUTest/CommandLineTestRunner.h>
+class ShellTestSuite : public ::testing::Test {
+public:
+    static constexpr const char * const SHELL_BUNDLE_LOC = "" SHELL_BUNDLE_LOCATION "";
 
-#ifdef SHELL_BUNDLE_LOCATION
-const char * const SHELL_BUNDLE = SHELL_BUNDLE_LOCATION;
-#endif
+    ShellTestSuite() : ctx{createFrameworkContext()} {}
 
-#ifdef __APPLE__
-#include "memstream/open_memstream.h"
-#else
-#include <stdio.h>
-#endif
+    static std::shared_ptr<celix_bundle_context_t> createFrameworkContext() {
+        auto properties = properties_create();
+        properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
+        properties_set(properties, "org.osgi.framework.storage", ".cacheShellTestSuite");
 
+        auto* cFw = celix_frameworkFactory_createFramework(properties);
+        auto cCtx = framework_getContext(cFw);
 
-TEST_GROUP(CelixShellTests) {
-    framework_t* fw = nullptr;
-    bundle_context_t *ctx = nullptr;
-    celix_properties_t *properties = nullptr;
+        long shellBundleId = celix_bundleContext_installBundle(cCtx, SHELL_BUNDLE_LOCATION, true);
+        EXPECT_GE(shellBundleId, 0);
 
-    void setup() {
-        properties = celix_properties_create();
-        celix_properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
-        celix_properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
-        celix_properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
-
-        fw = celix_frameworkFactory_createFramework(properties);
-        ctx = framework_getContext(fw);
-
-        long bndId = celix_bundleContext_installBundle(ctx, SHELL_BUNDLE, true);
-        CHECK_TRUE(bndId >= 0);
+        return std::shared_ptr<celix_bundle_context_t>{cCtx, [](celix_bundle_context_t* context) {
+            auto *fw = celix_bundleContext_getFramework(context);
+            celix_frameworkFactory_destroyFramework(fw);
+        }};
     }
-
-    void teardown() {
-        celix_frameworkFactory_destroyFramework(fw);
-    }
+    
+    std::shared_ptr<celix_bundle_context_t> ctx;
 };
 
-TEST(CelixShellTests, shellBundleInstalledTest) {
-    auto *bndIds = celix_bundleContext_listBundles(ctx);
-    CHECK_EQUAL(1, celix_arrayList_size(bndIds));
+TEST_F(ShellTestSuite, shellBundleInstalledTest) {
+    auto *bndIds = celix_bundleContext_listBundles(ctx.get());
+    EXPECT_EQ(1, celix_arrayList_size(bndIds));
     celix_arrayList_destroy(bndIds);
 }
 
-static void callCommand(celix_bundle_context_t *ctx, const char *cmdLine, bool cmdShouldSucceed) {
+static void callCommand(std::shared_ptr<celix_bundle_context_t>& ctx, const char *cmdLine, bool cmdShouldSucceed) {
     celix_service_use_options_t opts{};
 
     struct callback_data {
@@ -82,21 +72,22 @@
     opts.use = [](void *handle, void *svc) {
         auto *shell = static_cast<celix_shell_t *>(svc);
         auto *d = static_cast<struct callback_data*>(handle);
-        CHECK_TRUE(shell != nullptr);
+        EXPECT_TRUE(shell != nullptr);
         celix_status_t status = shell->executeCommand(shell->handle, d->cmdLine, stdout, stderr);
         if (d->cmdShouldSucceed) {
-            CHECK_EQUAL_TEXT(CELIX_SUCCESS, status, d->cmdLine);
+            EXPECT_EQ(CELIX_SUCCESS, status);
         } else {
-            CHECK_TRUE_TEXT(status != CELIX_SUCCESS, d->cmdLine);
+            EXPECT_TRUE(status != CELIX_SUCCESS);
         }
     };
-    bool called = celix_bundleContext_useServiceWithOptions(ctx, &opts);
-    CHECK_TRUE(called);
+    bool called = celix_bundleContext_useServiceWithOptions(ctx.get(), &opts);
+    EXPECT_TRUE(called);
 }
 
-TEST(CelixShellTests, testAllCommandsAreCallable) {
+TEST_F(ShellTestSuite, testAllCommandsAreCallable) {
     callCommand(ctx, "non-existing", false);
     callCommand(ctx, "install a-bundle-loc.zip", false);
+    callCommand(ctx, "help", true);
     callCommand(ctx, "help lb", false); //note need namespace
     callCommand(ctx, "help celix::lb", true);
     callCommand(ctx, "help non-existing-command", false);
@@ -110,22 +101,22 @@
     callCommand(ctx, "update 15", false);
 }
 
-TEST(CelixShellTests, quitTest) {
+TEST_F(ShellTestSuite, quitTest) {
     callCommand(ctx, "quit", true);
 }
 
-TEST(CelixShellTests, stopFrameworkTest) {
+TEST_F(ShellTestSuite, stopFrameworkTest) {
     callCommand(ctx, "stop 0", true);
 }
 
-TEST(CelixShellTests, queryTest) {
+TEST_F(ShellTestSuite, queryTest) {
     celix_service_use_options_t opts{};
     opts.filter.serviceName = CELIX_SHELL_COMMAND_SERVICE_NAME;
     opts.filter.filter = "(command.name=celix::query)";
     opts.waitTimeoutInSeconds = 1.0;
     opts.use = [](void */*handle*/, void *svc) {
         auto *command = static_cast<celix_shell_command_t*>(svc);
-        CHECK_TRUE(command != nullptr);
+        EXPECT_TRUE(command != nullptr);
 
         {
             char *buf = nullptr;
@@ -133,8 +124,8 @@
             FILE *sout = open_memstream(&buf, &len);
             command->executeCommand(command->handle, (char *) "query", sout, sout);
             fclose(sout);
-            STRCMP_CONTAINS("Provided services found 1", buf); //note could be 11, 12, etc
-            //STRCMP_CONTAINS("Requested services found 1", buf); //note very explicit, could be improved
+            char* found = strstr(buf, "Provided services found 1"); //note could be 11, 12, etc
+            EXPECT_TRUE(found != nullptr);
             free(buf);
         }
         {
@@ -143,53 +134,54 @@
             FILE *sout = open_memstream(&buf, &len);
             command->executeCommand(command->handle, (char *) "query 0", sout, sout); //note query framework bundle -> no results
             fclose(sout);
-            STRCMP_CONTAINS("No results", buf); //note could be 11, 12, etc
+            char* found = strstr(buf, "No results"); //note could be 11, 12, etc
+            EXPECT_TRUE(found != nullptr);
             free(buf);
         }
     };
-    bool called = celix_bundleContext_useServiceWithOptions(ctx, &opts);
-    CHECK_TRUE(called);
+    bool called = celix_bundleContext_useServiceWithOptions(ctx.get(), &opts);
+    EXPECT_TRUE(called);
 }
 
-TEST(CelixShellTests, localNameClashTest) {
+TEST_F(ShellTestSuite, localNameClashTest) {
     callCommand(ctx, "lb", true);
 
     celix_shell_command_t cmdService;
     cmdService.handle = nullptr;
     cmdService.executeCommand = [](void *, const char* cmdLine, FILE *, FILE *) -> bool {
-        CHECK_TRUE(cmdLine != NULL);
+        EXPECT_TRUE(cmdLine != nullptr);
         return true;
     };
 
     celix_properties_t *props = celix_properties_create();
     celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "3rdparty::lb");
-    long svcId = celix_bundleContext_registerService(ctx, &cmdService, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+    long svcId = celix_bundleContext_registerService(ctx.get(), &cmdService, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
 
     //two lb commands, need namespace
     callCommand(ctx, "lb", false);
     callCommand(ctx, "celix::lb", true);
     callCommand(ctx, "3rdparty::lb", true);
 
-    celix_bundleContext_unregisterService(ctx, svcId);
+    celix_bundleContext_unregisterService(ctx.get(), svcId);
 
 }
 
 #ifdef CELIX_INSTALL_DEPRECATED_API
 #include "command.h"
-TEST(CelixShellTests, legacyCommandTest) {
+TEST_F(ShellTestSuite, legacyCommandTest) {
     command_service_t cmdService;
     cmdService.handle = nullptr;
     cmdService.executeCommand = [](void *, char* cmdLine, FILE *, FILE *) -> celix_status_t {
-        CHECK_TRUE(cmdLine != NULL);
+        EXPECT_TRUE(cmdLine != nullptr);
         return CELIX_SUCCESS;
     };
 
     celix_properties_t *props = celix_properties_create();
     celix_properties_set(props, OSGI_SHELL_COMMAND_NAME, "testCommand");
-    long svcId = celix_bundleContext_registerService(ctx, &cmdService, OSGI_SHELL_COMMAND_SERVICE_NAME, props);
+    long svcId = celix_bundleContext_registerService(ctx.get(), &cmdService, OSGI_SHELL_COMMAND_SERVICE_NAME, props);
 
     callCommand(ctx, "testCommand", true);
 
-    celix_bundleContext_unregisterService(ctx, svcId);
+    celix_bundleContext_unregisterService(ctx.get(), svcId);
 }
 #endif
\ No newline at end of file
diff --git a/bundles/shell/shell/test/src/run_tests.cpp b/bundles/shell/shell/test/src/run_tests.cpp
deleted file mode 100644
index efaee82..0000000
--- a/bundles/shell/shell/test/src/run_tests.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <CppUTest/TestHarness.h>
-#include "CppUTest/CommandLineTestRunner.h"
-
-int main(int argc, char** argv) {
-    MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
-    return RUN_ALL_TESTS(argc, argv);
-}
\ No newline at end of file
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 950de4e..5d4ea4a 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -45,10 +45,6 @@
 target_link_libraries(framework PUBLIC Celix::utils Celix::dfi ${CELIX_OPTIONAL_EXTRA_LIBS})
 target_link_libraries(framework PUBLIC UUID::lib CURL::libcurl ZLIB::ZLIB)
 
-#Note option to ensure celix uses separate shutdown thread for closing service trackers.
-#This can prevent deadlocks, but those deadlock are bugs which need to be solved instead of this approach.
-#target_compile_definitions(framework PRIVATE -DCELIX_SERVICE_TRACKER_USE_SHUTDOWN_THREAD)
-
 install(TARGETS framework EXPORT celix DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT framework)
 install(DIRECTORY include/ DESTINATION include/celix COMPONENT framework)
 
diff --git a/libs/framework/gtest/CMakeLists.txt b/libs/framework/gtest/CMakeLists.txt
index cfd605c..89f9eb0 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -32,7 +32,6 @@
 add_dependencies(unresolveable_bundle sublib)
 
 add_executable(test_framework
-    src/run_tests.cpp
     src/single_framework_test.cpp
     src/multiple_frameworks_test.cpp
     src/bundle_context_bundles_tests.cpp
@@ -40,7 +39,7 @@
     src/DependencyManagerTestSuite.cc
 )
 
-target_link_libraries(test_framework Celix::framework CURL::libcurl GTest::gtest)
+target_link_libraries(test_framework Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
 add_dependencies(test_framework simple_test_bundle1_bundle simple_test_bundle2_bundle simple_test_bundle3_bundle simple_test_bundle4_bundle simple_test_bundle5_bundle bundle_with_exception_bundle unresolveable_bundle_bundle)
 target_include_directories(test_framework PRIVATE ../src)
 
diff --git a/libs/framework/gtest/src/bundle_context_bundles_tests.cpp b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
index 5a9253d..90f1d00 100644
--- a/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
+++ b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
@@ -378,6 +378,90 @@
     celix_bundleContext_stopTracker(ctx, trackerId);
 };
 
+
+TEST_F(CelixBundleContextBundlesTests, trackBundlesTestAsync) {
+    struct data {
+        std::atomic<int> installedCount{0};
+        std::atomic<int> startedCount{0};
+        std::atomic<int> stoppedCount{0};
+    };
+    struct data data;
+
+    auto installed = [](void *handle, const bundle_t *bnd) {
+        auto *d = static_cast<struct data*>(handle);
+        EXPECT_TRUE(bnd != nullptr);
+        d->installedCount.fetch_add(1);
+    };
+
+    auto started = [](void *handle, const bundle_t *bnd) {
+        auto *d = static_cast<struct data*>(handle);
+        EXPECT_TRUE(bnd != nullptr);
+        d->startedCount.fetch_add(1);
+    };
+
+    auto stopped = [](void *handle, const bundle_t *bnd) {
+        auto *d = static_cast<struct data*>(handle);
+        if (bnd == nullptr) {
+            celix_logUtils_logToStdout("test", CELIX_LOG_LEVEL_ERROR, "bnd should not be null");
+        }
+        EXPECT_TRUE(bnd != nullptr);
+        d->stoppedCount.fetch_add(1);
+    };
+
+    celix_bundle_tracking_options_t opts{};
+    opts.callbackHandle = static_cast<void*>(&data);
+    opts.onInstalled = installed;
+    opts.onStarted = started;
+    opts.onStopped = stopped;
+
+    long bundleId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true);
+    celix_framework_waitForEmptyEventQueue(fw);
+    EXPECT_TRUE(bundleId1 >= 0);
+
+    /*
+     * NOTE for bundles already installed (TEST_BND1) the callbacks are called on the
+     * thread of celix_bundleContext_trackBundlesWithOptions.
+     * For Bundles installed after the celix_bundleContext_trackBundlesWithOptions function
+     * the called are called on the Celix framework event queue thread.
+     */
+    long trackerId = celix_bundleContext_trackBundlesWithOptionsAsync(ctx, &opts);
+    celix_bundleContext_waitForAsyncTracker(ctx, trackerId);
+    EXPECT_EQ(1, data.installedCount.load());
+    EXPECT_EQ(1, data.startedCount.load());
+    EXPECT_EQ(0, data.stoppedCount.load());
+
+
+    long bundleId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, true);
+    celix_framework_waitForEmptyEventQueue(fw);
+    EXPECT_TRUE(bundleId2 >= 0);
+    EXPECT_EQ(2, data.installedCount.load());
+    EXPECT_EQ(2, data.startedCount.load());
+    EXPECT_EQ(0, data.stoppedCount.load());
+
+    celix_bundleContext_uninstallBundle(ctx, bundleId2);
+    celix_framework_waitForEmptyEventQueue(fw);
+    EXPECT_EQ(2, data.installedCount.load());
+    EXPECT_EQ(2, data.startedCount.load());
+    EXPECT_EQ(1, data.stoppedCount.load());
+
+    long bundleId3 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true);
+    celix_framework_waitForEmptyEventQueue(fw);
+    EXPECT_TRUE(bundleId3 >= 0);
+    EXPECT_EQ(3, data.installedCount.load());
+    EXPECT_EQ(3, data.startedCount.load());
+    EXPECT_EQ(1, data.stoppedCount.load());
+
+    bundleId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, true);
+    celix_framework_waitForEmptyEventQueue(fw);
+    EXPECT_TRUE(bundleId2 >= 0);
+    EXPECT_EQ(4, data.installedCount.load());
+    EXPECT_EQ(4, data.startedCount.load());
+    EXPECT_EQ(1, data.stoppedCount.load());
+
+    celix_bundleContext_stopTrackerAsync(ctx, trackerId, nullptr, nullptr);
+    celix_bundleContext_waitForAsyncStopTracker(ctx, trackerId);
+};
+
 TEST_F(CelixBundleContextBundlesTests, useBundlesConcurrentTest) {
 
     struct data {
@@ -455,19 +539,40 @@
     };
 
     bool called = celix_bundleContext_useBundle(ctx, 0, &data, updateCountFp);
-    ASSERT_TRUE(called);
-    ASSERT_EQ(0, data.provideCount);
-    ASSERT_EQ(0, data.requestedCount);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(0, data.provideCount);
+    EXPECT_EQ(0, data.requestedCount);
 
 
     long svcId = celix_bundleContext_registerService(ctx, (void*)0x42, "NopService", NULL);
     long trackerId = celix_bundleContext_trackServices(ctx, "AService", NULL, NULL, NULL);
 
     called = celix_bundleContext_useBundle(ctx, 0, &data, updateCountFp);
-    ASSERT_TRUE(called);
-    ASSERT_EQ(1, data.provideCount);
-    ASSERT_EQ(1, data.requestedCount);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(1, data.provideCount);
+    EXPECT_EQ(1, data.requestedCount);
 
     celix_bundleContext_unregisterService(ctx, svcId);
     celix_bundleContext_stopTracker(ctx, trackerId);
 }
+
+TEST_F(CelixBundleContextBundlesTests, startStopBundleTrackerAsync) {
+    std::atomic<int> count{0};
+
+    auto cb = [](void* data) {
+        auto* c = static_cast<std::atomic<int>*>(data);
+        (*c)++;
+    };
+
+    celix_bundle_tracking_options_t opts{};
+    opts.trackerCreatedCallbackData = &count;
+    opts.trackerCreatedCallback = cb;
+    long trkId = celix_bundleContext_trackBundlesWithOptionsAsync(ctx, &opts);
+    EXPECT_GE(trkId, 0);
+    celix_bundleContext_waitForAsyncTracker(ctx, trkId);
+    EXPECT_EQ(count.load(), 1); //1x tracker started
+
+    celix_bundleContext_stopTrackerAsync(ctx, trkId, &count, cb);
+    celix_bundleContext_waitForAsyncStopTracker(ctx, trkId);
+    EXPECT_EQ(2, count.load()); //1x tracker started, 1x tracker stopped
+}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index e544d2f..b19fbe9 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -44,6 +44,7 @@
         properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
         properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
         properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
+        properties_set(properties, "CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace");
 
         fw = celix_frameworkFactory_createFramework(properties);
         ctx = framework_getContext(fw);
@@ -75,6 +76,27 @@
     celix_bundleContext_unregisterService(ctx, svcId);
 };
 
+TEST_F(CelixBundleContextServicesTests, registerServiceAsync) {
+    struct calc {
+        int (*calc)(int);
+    };
+
+    const char *calcName = "calc";
+    calc svc;
+    svc.calc = [](int n) -> int {
+        return n * 42;
+    };
+
+    long svcId = celix_bundleContext_registerServiceAsync(ctx, &svc, calcName, nullptr);
+    ASSERT_TRUE(svcId >= 0);
+    celix_bundleContext_waitForAsyncRegistration(ctx, svcId);
+    ASSERT_GE(celix_bundleContext_findService(ctx, calcName), 0L);
+
+    celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL);
+    celix_bundleContext_waitForAsyncUnregistration(ctx, svcId);
+    ASSERT_LT(celix_bundleContext_findService(ctx, calcName), 0L);
+};
+
 TEST_F(CelixBundleContextServicesTests, incorrectUnregisterCalls) {
     celix_bundleContext_unregisterService(ctx, 1);
     celix_bundleContext_unregisterService(ctx, 2);
@@ -82,6 +104,13 @@
     celix_bundleContext_unregisterService(ctx, -2);
 };
 
+TEST_F(CelixBundleContextServicesTests, incorrectAsyncUnregisterCalls) {
+    celix_bundleContext_unregisterServiceAsync(ctx, 1, NULL, NULL);
+    celix_bundleContext_unregisterServiceAsync(ctx, 2, NULL, NULL);
+    celix_bundleContext_unregisterServiceAsync(ctx, -1, NULL, NULL);
+    celix_bundleContext_unregisterServiceAsync(ctx, -2, NULL, NULL);
+};
+
 TEST_F(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
     struct calc {
         int (*calc)(int);
@@ -94,16 +123,16 @@
     };
 
     long svcId1 = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    ASSERT_TRUE(svcId1 >= 0);
+    EXPECT_TRUE(svcId1 >= 0);
 
     long svcId2 = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    ASSERT_TRUE(svcId2 >= 0);
+    EXPECT_TRUE(svcId2 >= 0);
 
     long svcId3 = celix_bundleContext_registerService(ctx, &svc, calcName, nullptr);
-    ASSERT_TRUE(svcId3 >= 0);
+    EXPECT_TRUE(svcId3 >= 0);
 
     auto use = [](void *handle, void *svc) {
-        ASSERT_TRUE(svc != nullptr);
+        EXPECT_TRUE(svc != nullptr);
         int *total =  static_cast<int*>(handle);
         struct calc *calc = static_cast<struct calc*>(svc);
         int tmp = calc->calc(1);
@@ -112,20 +141,20 @@
 
     int total = 0;
     auto count = celix_bundleContext_useServices(ctx, "calc", &total, use);
-    ASSERT_EQ(3, count);
-    ASSERT_EQ(42 * 3, total);
+    EXPECT_EQ(3, count);
+    EXPECT_EQ(42 * 3, total);
 
 
     celix_bundleContext_unregisterService(ctx, svcId3);
     total = 0;
     count = celix_bundleContext_useServices(ctx, "calc", &total, use);
-    ASSERT_EQ(2, count);
-    ASSERT_EQ(42 * 2, total);
+    EXPECT_EQ(2, count);
+    EXPECT_EQ(42 * 2, total);
 
     total = 0;
     bool called = celix_bundleContext_useService(ctx, "calc", &total, use);
-    ASSERT_TRUE(called);
-    ASSERT_EQ(42, total);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(42, total);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
     celix_bundleContext_unregisterService(ctx, svcId2);
@@ -223,6 +252,56 @@
     }
 }
 
+TEST_F(CelixBundleContextServicesTests, registerAsyncAndUseServiceWithTimeout) {
+    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";
+
+        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_registerServiceAsync(ctx, &svc, calcName, nullptr);
+        EXPECT_TRUE(svcId >= 0);
+
+
+        EXPECT_TRUE(result.get()); //should return true after waiting for the registered service.
+
+
+        celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL);
+        celix_bundleContext_waitForAsyncUnregistration(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) {
     struct calc {
         int (*calc)(int);
@@ -410,11 +489,46 @@
     celix_bundleContext_unregisterService(ctx, svcId2);
 }
 
+TEST_F(CelixBundleContextServicesTests, servicesTrackerTestAsync) {
+    std::atomic<int> count {0};
+    auto add = [](void *handle, void *svc) {
+        ASSERT_TRUE(svc != nullptr);
+        auto *c = static_cast<std::atomic<int>*>(handle);
+        *c += 1;
+    };
+    auto remove = [](void *handle, void *svc) {
+        ASSERT_TRUE(svc != nullptr);
+        auto *c = static_cast<std::atomic<int>*>(handle);
+        *c -= 1;
+    };
+
+    long trackerId = celix_bundleContext_trackServicesAsync(ctx, "calc", &count, add, remove);
+    ASSERT_TRUE(trackerId >= 0);
+    ASSERT_EQ(0, count);
+
+    long svcId1 = celix_bundleContext_registerServiceAsync(ctx, (void*)0x100, "calc", nullptr);
+    celix_bundleContext_waitForAsyncRegistration(ctx, svcId1); //note also means the service tracker is done
+    ASSERT_TRUE(svcId1 >= 0);
+    ASSERT_EQ(1, count);
+
+    long svcId2 = celix_bundleContext_registerServiceAsync(ctx, (void*)0x200, "calc", nullptr);
+    celix_bundleContext_waitForAsyncRegistration(ctx, svcId2);
+    ASSERT_TRUE(svcId2 >= 0);
+    ASSERT_EQ(2, count);
+
+    celix_bundleContext_unregisterServiceAsync(ctx, svcId1, NULL, NULL);
+    celix_bundleContext_waitForAsyncUnregistration(ctx, svcId1);
+    ASSERT_EQ(1, count);
+
+    celix_bundleContext_stopTrackerAsync(ctx, trackerId, NULL, NULL);
+    celix_bundleContext_unregisterServiceAsync(ctx, svcId2, NULL, NULL);
+
+    celix_framework_waitForEmptyEventQueue(fw);
+}
+
 TEST_F(CelixBundleContextServicesTests, servicesTrackerInvalidArgsTest) {
     long trackerId = celix_bundleContext_trackServices(nullptr, nullptr, nullptr, nullptr, nullptr);
-    ASSERT_TRUE(trackerId < 0); //required ctx and service name missing
-    trackerId = celix_bundleContext_trackServices(ctx, nullptr, nullptr, nullptr, nullptr);
-    ASSERT_TRUE(trackerId < 0); //required service name missing
+    ASSERT_TRUE(trackerId < 0); //required ctx missing
     trackerId = celix_bundleContext_trackServices(ctx, "calc", nullptr, nullptr, nullptr);
     ASSERT_TRUE(trackerId >= 0); //valid
     celix_bundleContext_stopTracker(ctx, trackerId);
@@ -427,7 +541,9 @@
     ASSERT_TRUE(trackerId < 0); //required opts missing
     celix_service_tracking_options_t opts{};
     trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
-    ASSERT_TRUE(trackerId < 0); //required opts->serviceName missing
+    ASSERT_TRUE(trackerId >= 0); //valid with empty opts
+    celix_bundleContext_stopTracker(ctx, trackerId);
+
     opts.filter.serviceName = "calc";
     trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
     ASSERT_TRUE(trackerId >= 0); //valid
@@ -661,7 +777,6 @@
     void *svc4 = (void*)0x400; //5 ranking
 
     auto set = [](void *handle, void *svc) {
-        ASSERT_TRUE(svc != nullptr);
         static int callCount = 0;
         callCount += 1;
         if (callCount == 1) {
@@ -687,32 +802,86 @@
     opts.callbackHandle = (void*)&count;
     opts.filter.serviceName = "NA";
     opts.set = set;
-    long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts); //call 1
     ASSERT_TRUE(trackerId >= 0);
 
     //register svc3 should lead to second set call
     properties_t *props3 = celix_properties_create();
     celix_properties_set(props3, OSGI_FRAMEWORK_SERVICE_RANKING, "10");
-    long svcId3 = celix_bundleContext_registerService(ctx, svc3, "NA", props3);
+    long svcId3 = celix_bundleContext_registerService(ctx, svc3, "NA", props3); //call 2
 
     //register svc4 should lead to no set (lower ranking)
     properties_t *props4 = celix_properties_create();
     celix_properties_set(props4, OSGI_FRAMEWORK_SERVICE_RANKING, "10");
-    long svcId4 = celix_bundleContext_registerService(ctx, svc4, "NA", props4);
+    long svcId4 = celix_bundleContext_registerService(ctx, svc4, "NA", props4); //no update
 
     //unregister svc3 should lead to set (new highest ranking)
-    celix_bundleContext_unregisterService(ctx, svcId3);
+    celix_bundleContext_unregisterService(ctx, svcId3); //call 3
 
-    celix_bundleContext_stopTracker(ctx, trackerId);
+    celix_bundleContext_stopTracker(ctx, trackerId); //call 4 (NULL)
     celix_bundleContext_unregisterService(ctx, svcId1);
     celix_bundleContext_unregisterService(ctx, svcId2);
     celix_bundleContext_unregisterService(ctx, svcId4);
 
-    ASSERT_EQ(3, count); //check if the set is called the expected times
+    ASSERT_EQ(4, count); //check if the set is called the expected times
 }
 
-//TODO test tracker with options for properties & service owners
+TEST_F(CelixBundleContextServicesTests, trackAllServices) {
+    std::atomic<size_t> count{0};
 
+    void *svc1 = (void *) 0x100; //no ranking
+    void *svc2 = (void *) 0x200; //no ranking
+    void *svc3 = (void *) 0x300; //10 ranking
+    void *svc4 = (void *) 0x400; //5 ranking
+
+    long svcId1 = celix_bundleContext_registerService(ctx, svc1, "svc_type1", nullptr);
+    long svcId2 = celix_bundleContext_registerService(ctx, svc2, "svc_type1", nullptr);
+    long svcId3 = celix_bundleContext_registerService(ctx, svc3, "svc_type2", nullptr);
+    long svcId4 = celix_bundleContext_registerService(ctx, svc4, "svc_type2", nullptr);
+
+    celix_service_tracking_options_t opts{};
+    opts.callbackHandle = (void *) &count;
+    opts.filter.serviceName = nullptr;
+    opts.callbackHandle = (void *) &count;
+    opts.add = [](void *handle, void *) {
+        auto c = (std::atomic<size_t> *) handle;
+        c->fetch_add(1);
+    };
+    long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    EXPECT_GE(trackerId, 0);
+    EXPECT_EQ(4, count.load());
+
+    celix_bundleContext_unregisterService(ctx, svcId1);
+    celix_bundleContext_unregisterService(ctx, svcId2);
+    celix_bundleContext_unregisterService(ctx, svcId3);
+    celix_bundleContext_unregisterService(ctx, svcId4);
+    celix_bundleContext_stopTracker(ctx, trackerId);
+}
+
+TEST_F(CelixBundleContextServicesTests, metaTrackAllServiceTrackers) {
+    std::atomic<size_t> count{0};
+    auto add = [](void *handle, const celix_service_tracker_info_t*) {
+        auto *c = (std::atomic<size_t>*)handle;
+        c->fetch_add(1);
+    };
+    long trkId1 = celix_bundleContext_trackServiceTrackers(ctx, nullptr, (void*)&count, add, nullptr);
+    EXPECT_TRUE(trkId1 >= 0);
+
+    celix_service_tracking_options_t opts{};
+    opts.filter.serviceName = "service1";
+    long trkId2 = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    EXPECT_TRUE(trkId2 >= 0);
+
+    opts.filter.serviceName = "service2";
+    long trkId3 = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    EXPECT_TRUE(trkId3 >= 0);
+
+    EXPECT_EQ(2, count.load());
+
+    celix_bundleContext_stopTracker(ctx, trkId1);
+    celix_bundleContext_stopTracker(ctx, trkId2);
+    celix_bundleContext_stopTracker(ctx, trkId3);
+}
 
 TEST_F(CelixBundleContextServicesTests, serviceFactoryTest) {
     struct calc {
@@ -754,9 +923,54 @@
     celix_bundleContext_unregisterService(ctx, facId);
 }
 
+
+TEST_F(CelixBundleContextServicesTests, asyncServiceFactoryTest) {
+    struct calc {
+        int (*calc)(int);
+    };
+    auto name = "CALC";
+
+    int count = 0;
+    celix_service_factory_t fac;
+    memset(&fac, 0, sizeof(fac));
+    fac.handle = (void*)&count;
+    fac.getService = [](void *handle, const celix_bundle_t *, const celix_properties_t *) -> void* {
+        auto *c = (int *)handle;
+        *c += 1;
+        static struct calc svc; //normally a service per bundle
+        svc.calc = [](int arg) { return arg * 42; };
+        return &svc;
+    };
+    fac.ungetService = [](void *handle, const celix_bundle_t *, const celix_properties_t *) {
+        auto *c = (int *)handle;
+        *c += 1;
+    };
+
+    long facId = celix_bundleContext_registerServiceFactoryAsync(ctx, &fac, name, nullptr);
+    ASSERT_TRUE(facId >= 0);
+    celix_bundleContext_waitForAsyncRegistration(ctx, facId);
+
+
+    int result = -1;
+    bool called = celix_bundleContext_useService(ctx, name, &result, [](void *handle, void* svc) {
+        auto *r = (int *)(handle);
+        auto *calc = (struct calc*)svc;
+        *r = calc->calc(2);
+    });
+    ASSERT_TRUE(called);
+    ASSERT_EQ(84, result);
+    ASSERT_EQ(2, count); //expecting getService & unGetService to be called during the useService call.
+
+
+    celix_bundleContext_unregisterServiceAsync(ctx, facId, NULL, NULL);
+}
+
 TEST_F(CelixBundleContextServicesTests, findServicesTest) {
     long svcId1 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
     long svcId2 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
+    long svcId3 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
+    long svcId4 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
+
 
     long foundId = celix_bundleContext_findService(ctx, "non existing service name");
     ASSERT_EQ(-1L, foundId);
@@ -764,15 +978,17 @@
     foundId = celix_bundleContext_findService(ctx, "example");
     ASSERT_EQ(foundId, svcId1); //oldest should have highest ranking
 
-    array_list_t *list = celix_bundleContext_findServices(ctx, "non existintg service name");
+    array_list_t *list = celix_bundleContext_findServices(ctx, "non existing service name");
     ASSERT_EQ(0, celix_arrayList_size(list));
     arrayList_destroy(list);
 
     list = celix_bundleContext_findServices(ctx, "example");
-    ASSERT_EQ(2, celix_arrayList_size(list));
+    ASSERT_EQ(4, celix_arrayList_size(list));
     arrayList_destroy(list);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
+    celix_bundleContext_unregisterService(ctx, svcId3);
+    celix_bundleContext_unregisterService(ctx, svcId4);
 
     celix_service_filter_options_t opts{};
     opts.serviceName = "example";
@@ -787,41 +1003,194 @@
     int count = 0;
 
     auto add = [](void *handle, const celix_service_tracker_info_t *info) {
-        ASSERT_STRCASEEQ("example", info->serviceName);
-        ASSERT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
+        EXPECT_STRCASEEQ("example", info->serviceName);
+        EXPECT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
         auto *c = static_cast<int*>(handle);
         *c += 1;
     };
     auto remove = [](void *handle, const celix_service_tracker_info_t *info) {
-        ASSERT_STRCASEEQ("example", info->serviceName);
-        ASSERT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
+        EXPECT_STRCASEEQ("example", info->serviceName);
+        EXPECT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
         auto *c = static_cast<int*>(handle);
         *c -= 1;
     };
 
     long trackerId = celix_bundleContext_trackServiceTrackers(ctx, "example", &count, add, remove);
-    ASSERT_TRUE(trackerId >= 0);
-    ASSERT_EQ(0, count);
+    EXPECT_TRUE(trackerId >= 0);
+    EXPECT_EQ(0, count);
 
     long tracker2 = celix_bundleContext_trackService(ctx, "example", nullptr, nullptr);
-    ASSERT_TRUE(tracker2 >= 0);
-    ASSERT_EQ(1, count);
+    EXPECT_TRUE(tracker2 >= 0);
+    EXPECT_EQ(1, count);
 
     long tracker3 = celix_bundleContext_trackServices(ctx, "example", nullptr, nullptr, nullptr);
-    ASSERT_TRUE(tracker3 >= 0);
-    ASSERT_EQ(2, count);
+    EXPECT_TRUE(tracker3 >= 0);
+    EXPECT_EQ(2, count);
 
     long tracker4 = celix_bundleContext_trackServices(ctx, "no-match", nullptr, nullptr, nullptr);
-    ASSERT_TRUE(tracker4 >= 0);
-    ASSERT_EQ(2, count);
+    EXPECT_TRUE(tracker4 >= 0);
+    EXPECT_EQ(2, count);
 
     celix_bundleContext_stopTracker(ctx, tracker2);
-    celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on separate track -> need sync
-    ASSERT_EQ(1, count);
+    EXPECT_EQ(1, count);
     celix_bundleContext_stopTracker(ctx, tracker3);
-    celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on separate track -> need sync
-    ASSERT_EQ(0, count);
+    EXPECT_EQ(0, count);
 
     celix_bundleContext_stopTracker(ctx, trackerId);
     celix_bundleContext_stopTracker(ctx, tracker4);
 }
+
+TEST_F(CelixBundleContextServicesTests, floodEventLoopTest) {
+    struct callback_data {
+        std::mutex mutex{};
+        std::condition_variable cond{};
+        bool ready{false};
+    };
+    callback_data data{};
+
+    //test so that the framework needs to use dynamic allocated event on the event loop
+    celix_service_registration_options_t opts{};
+    opts.svc = (void*)0x42;
+    opts.serviceName = "test";
+    opts.asyncData = (void*)&data;
+    opts.asyncCallback = [](void *d, long /*svcId*/) {
+        auto *localData = static_cast<callback_data*>(d);
+        std::unique_lock<std::mutex> lck{localData->mutex};
+        localData->cond.wait_for(lck, std::chrono::seconds{30}, [&]{ return localData->ready; }); //wait til ready.
+        EXPECT_TRUE(localData->ready);
+    };
+    long svcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
+    EXPECT_GE(svcId, 0);
+
+    int nrOfAdditionalRegistrations = 300;
+    std::vector<long> svcIds{};
+    std::vector<long> trackerIds{};
+    for (int i = 0; i < nrOfAdditionalRegistrations; ++i) {
+        long id = celix_bundleContext_registerServiceAsync(ctx, (void*)0x42, "test", nullptr); //note cannot be completed because the first service registration in blocking in the event loop.
+        EXPECT_GE(id, 0);
+        svcIds.push_back(id);
+        trackerIds.push_back(celix_bundleContext_trackServicesAsync(ctx, "test", nullptr, nullptr, nullptr));
+
+        //CHECK if celix_bundleContext_isServiceRegistered work
+        EXPECT_FALSE(celix_bundleContext_isServiceRegistered(ctx, id));
+    }
+
+    {
+        //let the first service registration continue and as result all the following registrations.
+        std::lock_guard<std::mutex> lck{data.mutex};
+        data.ready = true;
+        data.cond.notify_all();
+    }
+
+    celix_bundleContext_waitForAsyncRegistration(ctx, svcId);
+    EXPECT_TRUE(celix_bundleContext_isServiceRegistered(ctx, svcId));
+    long foundId = celix_bundleContext_findService(ctx, "test");
+    EXPECT_GE(foundId, 0);
+
+    celix_bundleContext_unregisterServiceAsync(ctx, svcId, nullptr, nullptr);
+    for (auto id : svcIds) {
+        celix_bundleContext_unregisterServiceAsync(ctx, id, nullptr, nullptr);
+        celix_bundleContext_findService(ctx, "test"); //just to add some entropy
+    }
+    for (auto id : trackerIds) {
+        celix_bundleContext_stopTrackerAsync(ctx, id, nullptr, nullptr);
+    }
+}
+
+
+TEST_F(CelixBundleContextServicesTests, serviceOnDemandWithAsyncRegisterTest) {
+    //NOTE that even though service are registered async, they should be found by a useService call.
+
+    bool called = celix_bundleContext_useService(ctx, "test", nullptr, [](void*, void*){/*nop*/});
+    EXPECT_FALSE(called); //service not available
+
+    struct test_service {
+        void* handle;
+    };
+
+    struct callback_data {
+        celix_bundle_context_t* ctx;
+        long svcId;
+        test_service ts;
+    };
+    callback_data cbData{ctx, -1L, {nullptr}};
+
+    long trkId = celix_bundleContext_trackServiceTrackers(ctx, "test", &cbData, [](void *voidData, const celix_service_tracker_info_t*) {
+        auto* data = static_cast<callback_data*>(voidData);
+        data->svcId = celix_bundleContext_registerServiceAsync(data->ctx, &data->ts, "test", nullptr);
+    }, nullptr);
+
+    called = celix_bundleContext_useService(ctx, "test", nullptr, nullptr);
+    EXPECT_TRUE(called); //service created on demand.
+
+    celix_bundleContext_unregisterService(ctx, cbData.svcId);
+    celix_bundleContext_stopTracker(ctx, trkId);
+}
+
+TEST_F(CelixBundleContextServicesTests, startStopServiceTrackerAsync) {
+    std::atomic<int> count{0};
+
+    auto cb = [](void* data) {
+        auto* c = static_cast<std::atomic<int>*>(data);
+        (*c)++;
+    };
+
+    celix_service_tracking_options_t opts{};
+    opts.trackerCreatedCallbackData = &count;
+    opts.trackerCreatedCallback = cb;
+    long trkId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts);
+    EXPECT_GE(trkId, 0);
+    celix_bundleContext_waitForAsyncTracker(ctx, trkId);
+    EXPECT_EQ(count.load(), 1); //1x tracker started
+
+    celix_bundleContext_stopTrackerAsync(ctx, trkId, &count, cb);
+    celix_bundleContext_waitForAsyncStopTracker(ctx, trkId);
+    EXPECT_EQ(2, count.load()); //1x tracker started, 1x tracker stopped
+}
+
+TEST_F(CelixBundleContextServicesTests, startStopMetaServiceTrackerAsync) {
+    std::atomic<int> count{0};
+
+    auto cb = [](void* data) {
+        auto* c = static_cast<std::atomic<int>*>(data);
+        (*c)++;
+    };
+
+    long trkId = celix_bundleContext_trackServiceTrackersAsync(ctx, "test", nullptr, nullptr, nullptr, &count, cb);
+    EXPECT_GE(trkId, 0);
+    celix_bundleContext_waitForAsyncTracker(ctx, trkId);
+    EXPECT_EQ(count.load(), 1); //1x tracker started
+
+    celix_bundleContext_stopTrackerAsync(ctx, trkId, &count, cb);
+    celix_bundleContext_waitForAsyncStopTracker(ctx, trkId);
+    EXPECT_EQ(2, count.load()); //1x tracker started, 1x tracker stopped
+}
+
+TEST_F(CelixBundleContextServicesTests, onlyCallAsyncCallbackWithAsyncApi) {
+    celix_service_tracking_options_t opts{};
+    opts.trackerCreatedCallback = [](void *) {
+        FAIL();
+    };
+    long trkId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    EXPECT_GT(trkId, 0);
+    celix_bundleContext_stopTracker(ctx, trkId);
+
+    celix_service_registration_options_t opts2{};
+    opts2.serviceName = "test";
+    opts2.svc = (void*)0x42;
+    opts2.asyncCallback = [](void*, long) {
+        FAIL();
+    };
+    long svcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts2);
+    EXPECT_GT(svcId, 0);
+    celix_bundleContext_waitForEvents(ctx);
+    celix_bundleContext_unregisterService(ctx, trkId);
+
+    celix_bundle_tracking_options_t opts3{};
+    opts3.trackerCreatedCallback = [](void *) {
+        FAIL();
+    };
+    trkId = celix_bundleContext_trackBundlesWithOptions(ctx, &opts3);
+    EXPECT_GT(trkId, 0);
+    celix_bundleContext_stopTracker(ctx, trkId);
+}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/run_tests.cpp b/libs/framework/gtest/src/run_tests.cpp
deleted file mode 100644
index 339f725..0000000
--- a/libs/framework/gtest/src/run_tests.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <gtest/gtest.h>
-
-int main(int argc, char **argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    int rc = RUN_ALL_TESTS();
-    return rc;
-}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/single_framework_test.cpp b/libs/framework/gtest/src/single_framework_test.cpp
index 05ab3c2..28d1a8a 100644
--- a/libs/framework/gtest/src/single_framework_test.cpp
+++ b/libs/framework/gtest/src/single_framework_test.cpp
@@ -18,17 +18,13 @@
  */
 
 #include <gtest/gtest.h>
+#include <atomic>
 
 extern "C" {
 
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
 #include "celix_launcher.h"
 #include "celix_framework_factory.h"
+#include "celix_framework.h"
 
 
     static celix_framework_t *framework = nullptr;
@@ -81,6 +77,24 @@
     testFramework();
 }
 
+TEST_F(CelixFramework, testEventQueue) {
+    long eid = celix_framework_nextEventId(framework);
+    EXPECT_GE(eid, 0);
+    celix_framework_waitForGenericEvent(framework, eid); //event never issued so should return directly
+
+    std::atomic<int> count{0};
+    celix_framework_fireGenericEvent(framework, eid, -1L, "test", static_cast<void*>(&count), [](void* data) {
+       auto *c = static_cast<std::atomic<int>*>(data);
+       *c += 1;
+    }, static_cast<void*>(&count), [](void* data) {
+        auto *c = static_cast<std::atomic<int>*>(data);
+        *c += 3;
+    });
+
+    celix_framework_waitForGenericEvent(framework, eid);
+    EXPECT_EQ(4, count);
+}
+
 class FrameworkFactory : public ::testing::Test {
 public:
     FrameworkFactory() = default;
@@ -170,6 +184,11 @@
     framework_start(fw);
     framework_stop(fw);
     framework_waitForStop(fw);
+
+    framework_start(fw);
+    framework_stop(fw);
+    framework_waitForStop(fw);
+
     framework_destroy(fw);
 }
 
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index 2f11e06..b99c8b5 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -40,16 +40,34 @@
 #define OPTS_INIT
 #endif
 
+
 /**
-* Register a service to the Celix framework.
-*
-* @param ctx The bundle context
-* @param svc the service object. Normally a pointer to a service struct (i.e. a struct with function pointers)
-* @param serviceName the service name, cannot be NULL
-* @param properties The meta properties associated with the service. The service registration will take ownership of the properties (i.e. no destroy needed)
-* @return The serviceId (>= 0) or < 0 if the registration was unsuccessful.
-*/
-long celix_bundleContext_registerService(celix_bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties);
+ * Register a service to the Celix framework.
+ *
+ * The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
+ * not yet concluded when this function returns, but is added to the event loop.
+ * Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
+ * actual service registration in the framework's service registry.
+ *
+ * @param ctx The bundle context
+ * @param svc the service object. Normally a pointer to a service struct (i.e. a struct with function pointers)
+ * @param serviceName the service name, cannot be NULL
+ * @param properties The meta properties associated with the service. The service registration will take ownership of the properties (i.e. no destroy needed)
+ * @return The serviceId (>=0) or -1 if the registration was unsuccessful.
+ */
+long celix_bundleContext_registerServiceAsync(celix_bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties);
+
+/**
+ * Register a service to the Celix framework.
+ * Note: Please use the celix_bundleContext_registerServiceAsync instead.
+ *
+ * @param ctx The bundle context
+ * @param svc the service object. Normally a pointer to a service struct (i.e. a struct with function pointers)
+ * @param serviceName the service name, cannot be NULL
+ * @param properties The meta properties associated with the service. The service registration will take ownership of the properties (i.e. no destroy needed)
+ * @return The serviceId (>=0) or -1 if the registration was unsuccessful.
+ */
+long celix_bundleContext_registerService(celix_bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties); //__attribute__((deprecated("Use celix_bundleContext_registerServiceAsync instead!")));
 
 /**
  * Register a service factory in the framework (for the C language).
@@ -61,13 +79,37 @@
  * When a service in no longer needed for a bundle (e.g. ending the useService(s) calls or when a service tracker is stopped)
  * the ungetService function of the service factory will be called.
  *
+ * The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
+ * not yet concluded when this function returns, but is added to the event loop.
+ * Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
+ * actual service registration in the framework's service registry.
+ *
+ * @param ctx The bundle context
+ * @param factory The pointer to the factory service.
+ * @param serviceName The required service name of the services this factory will produce.
+ * @param properties The optional service factory properties. For a service consumer this will be seen as the service properties.
+ * @return The serviceId (>= 0) or < 0 if the registration was unsuccessful.
+ */
+long celix_bundleContext_registerServiceFactoryAsync(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props);
+
+/**
+ * Register a service factory in the framework (for the C language).
+ * The service factory will be called for every bundle requesting/de-requesting a service. This gives the provider the
+ * option to create bundle specific service instances.
+ * Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead.
+ *
+ * When a service is requested for a bundle the getService of the factory service will be called. This function must
+ * return a valid pointer to a service conform the registered service name or NULL.
+ * When a service in no longer needed for a bundle (e.g. ending the useService(s) calls or when a service tracker is stopped)
+ * the ungetService function of the service factory will be called.
+ *
  * @param ctx The bundle context
  * @param factory The pointer to the factory service.
  * @param serviceName The required service name of the services this factory will produce.
  * @param properties The optional service factory properties. For a service consumer this will be seen as the service properties.
  * @return The serviceId (>= 0) or < 0 if the registration was unsuccessful.
  */
-long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props);
+long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props); //__attribute__((deprecated("Use celix_bundleContext_registerServiceFactoryAsync instead!")));
 
 /**
  * Service Registration Options when registering services to the Celix framework.
@@ -126,6 +168,17 @@
      * for this.
      */
     const char *serviceVersion OPTS_INIT;
+
+    /**
+     * Async data pointer for the async register callback.
+     */
+     void *asyncData OPTS_INIT;
+
+    /**
+    * Async callback. Will be called after the a service is registered in the service registry using a async call.
+    * Will be called on the Celix event loop.
+    */
+    void (*asyncCallback)(void *data, long serviceId) OPTS_INIT;
 } celix_service_registration_options_t;
 
 /**
@@ -137,18 +190,50 @@
     .serviceName = NULL, \
     .properties = NULL, \
     .serviceLanguage = NULL, \
-    .serviceVersion = NULL }
+    .serviceVersion = NULL, \
+    .asyncData = NULL, \
+    .asyncCallback = NULL }
 #endif
 
+/**
+ * Register a service to the Celix framework using the provided service registration options.
+ *
+ * The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
+ * not yet concluded when this function returns, but is added to the event loop..
+ * Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
+ * actual service registration in the framework's service registry.
+ *
+ * @param ctx The bundle context
+ * @param opts The pointer to the registration options. The options are only in the during registration call.
+ * @return The serviceId (>= 0) or -1 if the registration was unsuccessful and -2 if the registration was cancelled (@see celix_bundleContext_reserveSvcId).
+ */
+long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts);
 
 /**
-* Register a service to the Celix framework using the provided service registration options.
-*
-* @param ctx The bundle context
-* @param opts The pointer to the registration options. The options are only in the during registration call.
-* @return The serviceId (>= 0) or < 0 if the registration was unsuccessful.
-*/
-long celix_bundleContext_registerServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts);
+ * Register a service to the Celix framework using the provided service registration options.
+ * Note: Please use the celix_bundleContext_registerServiceAsyncWithOptions instead.
+ *
+ * @param ctx The bundle context
+ * @param opts The pointer to the registration options. The options are only in the during registration call.
+ * @return The serviceId (>= 0) or -1 if the registration was unsuccessful and -2 if the registration was cancelled (@see celix_bundleContext_reserveSvcId).
+ */
+long celix_bundleContext_registerServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts); //__attribute__((deprecated("Use celix_bundleContext_registerServiceAsyncWithOptions instead!")));
+
+/**
+ * Waits til the async service registration for the provided serviceId is done.
+ * Silently ignore service ids < 0.
+ * Will directly return if there is no pending service registration for the provided service id.
+ */
+void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t* ctx, long serviceId);
+
+/**
+ * Checks whether a service for the provided service id is registered in the service registry.
+ * Note return false if the service for the provided service id is still pending in the event loop.
+ * Silently ignore service ids < 0 (returns false).
+ *
+ * Returns true if the service is registered in the service registry.
+ */
+bool celix_bundleContext_isServiceRegistered(celix_bundle_context_t* ctx, long serviceId);
 
 
 /**
@@ -160,11 +245,30 @@
  * @param ctx The bundle context
  * @param serviceId The service id
  */
-void celix_bundleContext_unregisterService(celix_bundle_context_t *ctx, long serviceId);
+void celix_bundleContext_unregisterService(celix_bundle_context_t *ctx, long serviceId); //__attribute__((deprecated("Use celix_bundleContext_unregisterService instead!")));
 
 
+/**
+ * Unregister the service or service factory with service id.
+ * The service will only be unregistered if the bundle of the bundle context is the owner of the service.
+ *
+ * The service will be umregistered async on the Celix event loop thread. This means that service unregistration is (probably)
+ * not yet concluded when this function returns. Use celix_bundleContext_waitForAsyncUnregistration to synchronise with the
+ * actual service unregistration in the framework's service registry.
+ *
+ * @param ctx The bundle context
+ * @param serviceId The service id
+ * @param doneData The data used on the doneCallback (if present)
+ * @param doneCallback If not NULL, this callback will be called when the unregisration is done. (will be called on the event loop thread)
+ */
+void celix_bundleContext_unregisterServiceAsync(celix_bundle_context_t *ctx, long serviceId, void* doneData, void (*doneCallback)(void* doneData));
 
 
+/**
+ * Waits til the async service unregistration for the provided serviceId is done.
+ * Silently ignore service < 0.
+ */
+void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t* ctx, long serviceId);
 
 
 
@@ -192,7 +296,8 @@
  */
 typedef struct celix_service_filter_options {
     /**
-     * The required service name.
+     * The service name.
+     * If NULL is used any services which matches the filter string will be tracked.
      */
     const char* serviceName OPTS_INIT;
 
@@ -248,15 +353,39 @@
  */
 celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts);
 
-
 /**
  * track the highest ranking service with the provided serviceName.
  * The highest ranking services will used for the callback.
  * If a new and higher ranking services the callback with be called again with the new service.
  * If a service is removed a the callback with be called with next highest ranking service or NULL as service.
  *
+ * The service tracker will be created async on the Celix event loop thread. This means that the function can return
+ * before the tracker is created.
+ *
  * @param ctx The bundle context.
- * @param serviceName The required service name to track
+ * @param serviceName The required service name to track.
+ *                    If NULL is all service are tracked.
+ * @param callbackHandle The data pointer, which will be used in the callbacks
+ * @param set is a required callback, which will be called when a new highest ranking service is set.
+ * @return the tracker id (>=0) or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackServiceAsync(
+        celix_bundle_context_t* ctx,
+        const char* serviceName,
+        void* callbackHandle,
+        void (*set)(void* handle, void* svc)
+);
+
+/**
+ * track the highest ranking service with the provided serviceName.
+ * The highest ranking services will used for the callback.
+ * If a new and higher ranking services the callback with be called again with the new service.
+ * If a service is removed a the callback with be called with next highest ranking service or NULL as service.
+ * Note: Please use the celix_bundleContext_trackServiceAsync instead.
+ *
+ * @param ctx The bundle context.
+ * @param serviceName The required service name to track.
+ *                    If NULL is all service are tracked.
  * @param callbackHandle The data pointer, which will be used in the callbacks
  * @param set is a required callback, which will be called when a new highest ranking service is set.
  * @return the tracker id (>=0) or < 0 if unsuccessful.
@@ -266,13 +395,37 @@
         const char* serviceName,
         void* callbackHandle,
         void (*set)(void* handle, void* svc)
-);
+); //__attribute__((deprecated("Use celix_bundleContext_trackServiceSync instead!")));
 
 /**
  * track services with the provided serviceName.
  *
+ * The service tracker will be created async on the Celix event loop thread. This means that the function can return
+ * before the tracker is created.
+ *
  * @param ctx The bundle context.
  * @param serviceName The required service name to track
+ *                    If NULL is all service are tracked.
+ * @param callbackHandle The data pointer, which will be used in the callbacks
+ * @param add is a required callback, which will be called when a service is added and initially for the existing service.
+ * @param remove is a required callback, which will be called when a service is removed
+ * @return the tracker id (>=0) or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackServicesAsync(
+        celix_bundle_context_t* ctx,
+        const char* serviceName,
+        void* callbackHandle,
+        void (*add)(void* handle, void* svc),
+        void (*remove)(void* handle, void* svc)
+);
+
+/**
+ * track services with the provided serviceName.
+ * Note: Please use the celix_bundleContext_trackServicesAsync instead.
+ *
+ * @param ctx The bundle context.
+ * @param serviceName The required service name to track
+ *                    If NULL is all service are tracked.
  * @param callbackHandle The data pointer, which will be used in the callbacks
  * @param add is a required callback, which will be called when a service is added and initially for the existing service.
  * @param remove is a required callback, which will be called when a service is removed
@@ -284,7 +437,7 @@
         void* callbackHandle,
         void (*add)(void* handle, void* svc),
         void (*remove)(void* handle, void* svc)
-);
+); //__attribute__((deprecated("Use celix_bundleContext_trackServicesAsync instead!")));;
 
 /**
  * Service Tracker Options used to fine tune which services to track and the callback to be used for the tracked services.
@@ -362,6 +515,17 @@
     * and the bundle owning the service will also be provided to the callback.
     */
     void (*removeWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) OPTS_INIT;
+
+
+    /**
+     * Data for the trackerCreatedCallback.
+     */
+    void *trackerCreatedCallbackData OPTS_INIT;
+
+    /**
+     * The callback called when the tracker has ben created (and is active) when using a async call.
+     */
+    void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) OPTS_INIT;
 } celix_service_tracking_options_t;
 
 /**
@@ -382,30 +546,74 @@
     .removeWithProperties = NULL, \
     .setWithOwner = NULL, \
     .addWithOwner = NULL, \
-    .removeWithOwner = NULL}
+    .removeWithOwner = NULL, \
+    .trackerCreatedCallbackData = NULL, \
+    .trackerCreatedCallback = NULL }
 #endif
 
 /**
  * Tracks services using the provided tracker options.
  * The tracker options are only using during this call and can safely be freed/reused after this call returns.
  *
+ * The service tracker will be created async on the Celix event loop thread. This means that the function can return
+ * before the tracker is created.
+ *
  * @param ctx The bundle context.
  * @param opts The pointer to the tracker options.
  * @return the tracker id (>=0) or < 0 if unsuccessful.
  */
-long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts);
+long celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts);
+
+/**
+ * Tracks services using the provided tracker options.
+ * The tracker options are only using during this call and can safely be freed/reused after this call returns.
+ * Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead.
+ *
+ *
+ * @param ctx The bundle context.
+ * @param opts The pointer to the tracker options.
+ * @return the tracker id (>=0) or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts); //__attribute__((deprecated("Use celix_bundleContext_trackServicesWithOptionsAsync instead!")));
 
 /**
  * Stop the tracker with the provided track id.
  * Could be a service tracker, bundle tracker or service tracker tracker.
  * Only works for the trackers owned by the bundle of the bundle context.
  *
+ * The service tracker will be destroyed async on the Celix event loop thread. This means that the function can return
+ * before the tracker is destroyed.
+ *
+ * if the doneCallback is not NULL, this will be called when the destruction of the service tracker is done.
+ * (will be called on the event loop thread).
+ *
  * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0.
  */
-void celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId);
+void celix_bundleContext_stopTrackerAsync(
+        celix_bundle_context_t *ctx,
+        long trackerId,
+        void *doneCallbackData,
+        void (*doneCallback)(void* doneCallbackData));
 
+/**
+ * Wait for (async) creation of tracker
+ */
+void celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t* ctx, long trackerId);
 
+/**
+ * Wait for (async) stopping of tracking.
+ */
+void celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t* ctx, long trackerId);
 
+/**
+ * Stop the tracker with the provided track id.
+ * Could be a service tracker, bundle tracker or service tracker tracker.
+ * Only works for the trackers owned by the bundle of the bundle context.
+ * Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead.
+ *
+ * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0.
+ */
+void celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId); //__attribute__((deprecated("Use celix_bundleContext_stopTrackerAsync instead!")));
 
 
 
@@ -655,10 +863,33 @@
  */
 char* celix_bundleContext_getBundleSymbolicName(celix_bundle_context_t *ctx, long bndId);
 
+
 /**
  * track bundles
  * The add bundle callback will also be called for already installed bundles.
  *
+ * The bundle tracker will be created async on the Celix event loop thread. This means that the function can return
+ * before the tracker is created.
+ *
+ * @param ctx               The bundle context.
+ * @param callbackHandle    The data pointer, which will be used in the callbacks
+ * @param add               The callback which will be called for started bundles.
+ * @param remove            The callback which will be called when bundles are stopped.
+ * @return                  The bundle tracker id or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackBundlesAsync(
+        celix_bundle_context_t* ctx,
+        void* callbackHandle,
+        void (*onStarted)(void* handle, const celix_bundle_t *bundle),
+        void (*onStopped)(void *handle, const celix_bundle_t *bundle)
+);
+
+/**
+ * track bundles
+ * The add bundle callback will also be called for already installed bundles.
+ *
+ * Note: please use celix_bundleContext_trackBundlesAsync instead.
+ *
  * @param ctx               The bundle context.
  * @param callbackHandle    The data pointer, which will be used in the callbacks
  * @param add               The callback which will be called for started bundles.
@@ -670,7 +901,7 @@
         void* callbackHandle,
         void (*onStarted)(void* handle, const celix_bundle_t *bundle),
         void (*onStopped)(void *handle, const celix_bundle_t *bundle)
-);
+); //__attribute__((deprecated("Use celix_bundleContext_trackBundlesAsync instead!")));
 
 
 /**
@@ -718,13 +949,24 @@
      * This is done, because the framework bundle is a special bundle which is generally not needed in the callbacks.
      */
     bool includeFrameworkBundle OPTS_INIT;
+
+    /**
+     * Data for the trackerCreatedCallback.
+     */
+    void *trackerCreatedCallbackData OPTS_INIT;
+
+    /**
+     * The callback called when the tracker has ben created (and is active) when using the
+     * track bundles ascync calls.
+     */
+    void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) OPTS_INIT;
 } celix_bundle_tracking_options_t;
 
 /**
  * C Macro to create a empty celix_service_filter_options_t type.
  */
 #ifndef __cplusplus
-#define CELIX_EMPTY_BUNDLE_TRACKING_OPTIONS {.callbackHandle = NULL, .onInstalled = NULL, .onStarted = NULL, .onStopped = NULL, .onBundleEvent = NULL, .includeFrameworkBundle = false}
+#define CELIX_EMPTY_BUNDLE_TRACKING_OPTIONS {.callbackHandle = NULL, .onInstalled = NULL, .onStarted = NULL, .onStopped = NULL, .onBundleEvent = NULL, .includeFrameworkBundle = false, .trackerCreatedCallbackData = NULL, .trackerCreatedCallback = NULL}
 #endif
 
 /**
@@ -732,6 +974,25 @@
  * The tracker options are only using during this call and can safely be freed/reused after this call returns.
  * (i.e. can be on the stack)
  *
+ * The bundle tracker will be created async on the Celix event loop thread. This means that the function can return
+ * before the tracker is created.
+ *
+ * @param ctx   The bundle context.
+ * @param opts  The pointer to the bundle tracker options.
+ * @return      The bundle tracker id (>=0) or < 0 if unsuccessful.
+ */
+long celix_bundleContext_trackBundlesWithOptionsAsync(
+        celix_bundle_context_t* ctx,
+        const celix_bundle_tracking_options_t *opts
+);
+
+/**
+ * Tracks bundles using the provided bundle tracker options.
+ * The tracker options are only using during this call and can safely be freed/reused after this call returns.
+ * (i.e. can be on the stack)
+ *
+ * Note: please use celix_bundleContext_trackBundlesWithOptionsAsync instead;
+ *
  * @param ctx   The bundle context.
  * @param opts  The pointer to the bundle tracker options.
  * @return      The bundle tracker id (>=0) or < 0 if unsuccessful.
@@ -739,7 +1000,7 @@
 long celix_bundleContext_trackBundlesWithOptions(
         celix_bundle_context_t* ctx,
         const celix_bundle_tracking_options_t *opts
-);
+); //__attribute__((deprecated("Use celix_bundleContext_trackBundlesWithOptionsAsync instead!")));
 
 /**
  * Use the bundle with the provided bundle id if it is in the active (started) state
@@ -813,8 +1074,43 @@
  *
  * This tracker can be stopped with the celix_bundleContext_stopTracker function.
  *
+ * The service tracker tracker will be created async on the Celix event loop thread. This means that the function can return
+ * before the tracker is created.
+ *
  * @param ctx The bundle context
  * @param serviceName The target service name for the service tracker to track.
+ *                      If NULL is provided, add/remove callbacks will be called for all service trackers in the framework.
+ * @param callbackHandle The callback handle which will be provided as handle in the trackerAdd and trackerRemove callback.
+ * @param trackerAdd Called when a service tracker is added, which tracks the provided service name. Will also be called
+ *                   for all existing service tracker when this tracker is started.
+ * @param trackerRemove Called when a service tracker is removed, which tracks the provided service name
+ * @param doneCallbackData call back data argument provided to the done callback function.
+ * @param doneCallback If not NULL will be called when the service tracker tracker is created.
+ * @return The tracker id or <0 if something went wrong (will log an error).
+ */
+long celix_bundleContext_trackServiceTrackersAsync(
+        celix_bundle_context_t *ctx,
+        const char *serviceName,
+        void *callbackHandle,
+        void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info),
+        void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info),
+        void *doneCallbackData,
+        void (*doneCallback)(void* doneCallbackData));
+
+/**
+ * Track the service tracker targeting the provided service name. This can be used to track if there is an interest
+ * in a certain service and ad-hoc act on that interest.
+ *
+ * Note that the celix_service_tracker_info_t pointer in the trackerAdd/trackerRemove callbacks are only valid during
+ * the callback.
+ *
+ * Note: Please use celix_bundleContext_trackServiceTrackersAsync instead.
+ *
+ * This tracker can be stopped with the celix_bundleContext_stopTracker function.
+ *
+ * @param ctx The bundle context
+ * @param serviceName The target service name for the service tracker to track.
+ *                      If NULL is provided, add/remove callbacks will be called for all service trackers in the framework.
  * @param callbackHandle The callback handle which will be provided as handle in the trackerAdd and trackerRemove callback.
  * @param trackerAdd Called when a service tracker is added, which tracks the provided service name. Will also be called
  *                   for all existing service tracker when this tracker is started.
@@ -826,7 +1122,7 @@
         const char *serviceName,
         void *callbackHandle,
         void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info),
-        void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info));
+        void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info)); //__attribute__((deprecated("Use celix_bundleContext_trackServiceTrackersAsync instead!")));
 
 /**
  * Gets the dependency manager for this bundle context.
@@ -837,6 +1133,12 @@
 
 
 /**
+ * Wait till there are event for the bundle of this bundle context.
+ */
+void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx);
+
+
+/**
  * Returns the bundle for this bundle context.
  */
 celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx);
diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h
index 7af1e2c..6e1afbe 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -156,6 +156,44 @@
 void celix_framework_setLogCallback(celix_framework_t* fw, void* logHandle, void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *function, int line, const char *format, va_list formatArgs));
 
 
+/**
+ * wait till all events for the bundle identified by the bndId are processed.
+ */
+void celix_framework_waitUntilNoEventsForBnd(celix_framework_t* fw, long bndId);
+
+/**
+ * Returns whether the current thread is the Celix framework event loop thread.
+ */
+bool celix_framework_isCurrentThreadTheEventLoop(celix_framework_t* fw);
+
+
+/**
+ * Fire a generic event. The event will be added to the event loop and handled on the event loop thread.
+ *
+ * if bndId >=0 the bundle usage count will be increased while the event is not yet processed or finished processing.
+ * The eventName is expected to be const char* valid during til the event is finished processing.
+ *
+ * if eventId >=0 this will be used, otherwise a new event id will be generated
+ * return eventId
+ */
+long celix_framework_fireGenericEvent(celix_framework_t* fw, long eventId, long bndId, const char *eventName, void* processData, void (*processCallback)(void *data), void* doneData, void (*doneCallback)(void* doneData));
+
+/**
+ * Get the next event id.
+ *
+ * This can be used to ensure celix_framework_waitForGenericEvent can be used to wait for an event.
+ * The returned event id will not be used by the framework itself unless followed up with a
+ * celix_framework_fireGenericEvent call using the returned event id.
+ */
+long celix_framework_nextEventId(celix_framework_t *fw);
+
+/**
+ * Wait til a event with the provided event id is completely handled.
+ * This function will directly return if the provided event id is not in the event loop (already done or never issued).
+ */
+void celix_framework_waitForGenericEvent(celix_framework_t *fw, long eventId);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/include/service_registry.h b/libs/framework/include/service_registry.h
index db93cb5..275f707 100644
--- a/libs/framework/include/service_registry.h
+++ b/libs/framework/include/service_registry.h
@@ -60,8 +60,6 @@
 celix_status_t
 serviceRegistry_unregisterService(service_registry_pt registry, celix_bundle_t *bundle, service_registration_pt registration);
 
-celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt registry, celix_bundle_t *bundle);
-
 celix_status_t serviceRegistry_getServiceReference(service_registry_pt registry, celix_bundle_t *bundle,
                                                    service_registration_pt registration,
                                                    service_reference_pt *reference);
@@ -95,6 +93,17 @@
 
 celix_status_t celix_serviceRegistry_removeServiceListener(celix_service_registry_t *reg, celix_service_listener_t *listener);
 
+bool celix_serviceRegistry_isServiceRegistered(celix_service_registry_t* reg, long serviceId);
+
+celix_status_t
+celix_serviceRegistry_registerService(
+        celix_service_registry_t *reg,
+        const celix_bundle_t *bnd,
+        const char *serviceName,
+        void* service,
+        celix_properties_t* props,
+        long reserveId,
+        service_registration_t **registration);
 
 celix_status_t
 celix_serviceRegistry_registerServiceFactory(
@@ -103,6 +112,7 @@
         const char *serviceName,
         celix_service_factory_t *factory,
         celix_properties_t* props,
+        long reserveId,
         service_registration_t **registration);
 
 /**
@@ -134,6 +144,37 @@
 long celix_serviceRegistry_nextSvcId(celix_service_registry_t* registry);
 
 
+/**
+ * Unregister service for the provided service id (owned by bnd).
+ * Will print an error if the service id is invalid
+ */
+void celix_serviceRegistry_unregisterService(celix_service_registry_t* registry, celix_bundle_t* bnd, long serviceId);
+
+
+/**
+ * Create a LDAP filter for the provided filter parts.
+ * @param serviceName       The optional service name
+ * @param versionRange      The optional version range
+ * @param filter            The optional filter
+ * @param serviceLanguage   The optional service lang. if NULL, lang C will be used.
+ * @param ignoreServiceLanguage   The whether the service lang filter needs to be added to the filter.
+ * @return a LDAP filter. Caller is responsible for freeing the filter.
+ */
+char* celix_serviceRegistry_createFilterFor(
+        celix_service_registry_t* registry,
+        const char* serviceName,
+        const char* versionRange,
+        const char* additionalFilter,
+        const char* serviceLanguage,
+        bool ignoreServiceLanguage);
+
+/**
+ * Find services and return a array list of service ids (long).
+ * Caller is responsible for freeing the returned array list.
+ */
+celix_array_list_t* celix_serviceRegisrty_findServices(celix_service_registry_t* registry, const char* filter);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/include/service_tracker.h b/libs/framework/include/service_tracker.h
index 4e69621..8c377e2 100644
--- a/libs/framework/include/service_tracker.h
+++ b/libs/framework/include/service_tracker.h
@@ -113,7 +113,6 @@
 bool celix_serviceTracker_useHighestRankingService(
         celix_service_tracker_t *tracker,
         const char *serviceName /*sanity*/,
-        double waitTimeoutInSeconds /*0 -> do not wait */,
         void *callbackHandle,
         void (*use)(void *handle, void *svc),
         void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props),
@@ -134,16 +133,6 @@
         void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)
 );
 
-/**
- * blocks until all shutdown threads for the service tracker instances for the provided framework are done.
- */
-void celix_serviceTracker_syncForFramework(void *fw);
-
-/**
- * blocks until all shutdown threads for the service tracker instances for the provided bundle context are done.
- */
-void celix_serviceTracker_syncForContext(void *ctx);
-
 
 #ifdef __cplusplus
 }
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c
index 9994675..6d4eafc 100644
--- a/libs/framework/src/bundle.c
+++ b/libs/framework/src/bundle.c
@@ -173,7 +173,7 @@
 }
 
 celix_status_t bundle_getState(const_bundle_pt bundle, bundle_state_e *state) {
-	if(bundle==NULL){
+	if (bundle==NULL) {
 		*state = OSGI_FRAMEWORK_BUNDLE_UNKNOWN;
 		return CELIX_BUNDLE_EXCEPTION;
 	}
@@ -674,23 +674,25 @@
 
 celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd) {
     celix_array_list_t* result = celix_arrayList_create();
-    //FIXME: should not fall back to bundle context, but for now that is were the trackers are stored.
     celixThreadMutex_lock(&bnd->context->mutex);
     hash_map_iterator_t iter = hashMapIterator_construct(bnd->context->serviceTrackers);
     while (hashMapIterator_hasNext(&iter)) {
-        celix_service_tracker_t *tracker = hashMapIterator_nextValue(&iter);
-        celix_bundle_service_tracker_list_entry_t *entry = calloc(1, sizeof(*entry));
-        entry->filter = celix_utils_strdup(tracker->filter);
-        entry->nrOfTrackedServices = serviceTracker_nrOfTrackedServices(tracker);
-        entry->serviceName = celix_utils_strdup(tracker->serviceName);
-        entry->bundleOwner = celix_bundle_getId(bnd);
+        celix_bundle_context_service_tracker_entry_t *trkEntry = hashMapIterator_nextValue(&iter);
+        if (trkEntry->tracker != NULL) {
+            celix_bundle_service_tracker_list_entry_t *entry = calloc(1, sizeof(*entry));
+            entry->filter = celix_utils_strdup(trkEntry->tracker->filter);
+            entry->nrOfTrackedServices = serviceTracker_nrOfTrackedServices(trkEntry->tracker);
+            entry->serviceName = celix_utils_strdup(trkEntry->tracker->serviceName);
+            entry->bundleOwner = celix_bundle_getId(bnd);
 
-        if (entry->serviceName != NULL) {
-            celix_arrayList_add(result, entry);
-        } else {
-            framework_logIfError(bnd->framework->logger, CELIX_BUNDLE_EXCEPTION, NULL, "Failed to get service name from tracker. filter is %s", entry->filter);
-            free(entry->filter);
-            free(entry);
+            if (entry->serviceName != NULL) {
+                celix_arrayList_add(result, entry);
+            } else {
+                framework_logIfError(bnd->framework->logger, CELIX_BUNDLE_EXCEPTION, NULL,
+                                     "Failed to get service name from tracker. filter is %s", entry->filter);
+                free(entry->filter);
+                free(entry);
+            }
         }
     }
     celixThreadMutex_unlock(&bnd->context->mutex);
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index b7f5326..2f1473d 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -21,6 +21,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <utils.h>
+#include <assert.h>
+#include <unistd.h>
 
 #include "celix_utils.h"
 #include "celix_constants.h"
@@ -34,11 +36,15 @@
 #include "dm_dependency_manager_impl.h"
 #include "celix_array_list.h"
 #include "module.h"
+#include "service_tracker_private.h"
+#include "celix_array_list.h"
 
 static celix_status_t bundleContext_bundleChanged(void *handle, bundle_event_t *event);
 static void bundleContext_cleanupBundleTrackers(bundle_context_t *ct);
 static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx);
 static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx);
+static void bundleContext_cleanupServiceRegistration(bundle_context_t* ctx);
+static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts, bool async);
 
 celix_status_t bundleContext_create(framework_pt framework, celix_framework_logger_t*  logger, bundle_pt bundle, bundle_context_pt *bundle_context) {
 	celix_status_t status = CELIX_SUCCESS;
@@ -61,6 +67,7 @@
             context->bundleTrackers = hashMap_create(NULL,NULL,NULL,NULL);
             context->serviceTrackers = hashMap_create(NULL,NULL,NULL,NULL);
             context->metaTrackers =  hashMap_create(NULL,NULL,NULL,NULL);
+            context->stoppingTrackerEventIds = hashMap_create(NULL,NULL,NULL,NULL);
             context->nextTrackerId = 1L;
 
             *bundle_context = context;
@@ -77,18 +84,17 @@
 	celix_status_t status = CELIX_SUCCESS;
 
 	if (context != NULL) {
-	    celixThreadMutex_lock(&context->mutex);
+	    assert(hashMap_size(context->bundleTrackers) == 0);
+        hashMap_destroy(context->bundleTrackers, false, false);
+        assert(hashMap_size(context->serviceTrackers) == 0);
+        hashMap_destroy(context->serviceTrackers, false, false);
+        assert(hashMap_size(context->metaTrackers) == 0);
+        hashMap_destroy(context->metaTrackers, false, false);
+        assert(celix_arrayList_size(context->svcRegistrations) == 0);
+        celix_arrayList_destroy(context->svcRegistrations);
+        hashMap_destroy(context->stoppingTrackerEventIds, false, false);
 
-
-	    bundleContext_cleanupBundleTrackers(context);
-	    bundleContext_cleanupServiceTrackers(context);
-        bundleContext_cleanupServiceTrackerTrackers(context);
-
-	    //NOTE still present service registrations will be cleared during bundle stop in the
-	    //service registry (serviceRegistry_clearServiceRegistrations).
-        celixThreadMutex_unlock(&context->mutex);
-	    celixThreadMutex_destroy(&context->mutex); 
-	    arrayList_destroy(context->svcRegistrations);
+	    celixThreadMutex_destroy(&context->mutex);
 
 	    if (context->mng != NULL) {
 	        celix_dependencyManager_removeAllComponents(context->mng);
@@ -106,6 +112,15 @@
 	return status;
 }
 
+void celix_bundleContext_cleanup(celix_bundle_context_t *ctx) {
+    //NOTE not perfect, because stopping of registrations/tracker when the activator is destroyed can lead to segfault.
+    //but at least we can try to warn the bundle implementer that some cleanup is missing.
+    bundleContext_cleanupBundleTrackers(ctx);
+    bundleContext_cleanupServiceTrackers(ctx);
+    bundleContext_cleanupServiceTrackerTrackers(ctx);
+    bundleContext_cleanupServiceRegistration(ctx);
+}
+
 celix_status_t bundleContext_getBundle(bundle_context_pt context, bundle_pt *out) {
 	celix_status_t status = CELIX_SUCCESS;
     celix_bundle_t *bnd = celix_bundleContext_getBundle(context);
@@ -270,7 +285,9 @@
         status = CELIX_ILLEGAL_ARGUMENT;
     }
 
-    framework_logIfError(context->framework->logger, status, NULL, "Failed to get service");
+    if (status != CELIX_SUCCESS) {
+        fw_log(context->framework->logger, CELIX_LOG_LEVEL_ERROR, "Failed to get service");
+    }
 
     return status;
 }
@@ -431,6 +448,13 @@
  **********************************************************************************************************************
  **********************************************************************************************************************/
 
+long celix_bundleContext_registerServiceAsync(celix_bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties) {
+    celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+    opts.svc = svc;
+    opts.serviceName = serviceName;
+    opts.properties = properties;
+    return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
+}
 
 long celix_bundleContext_registerService(bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties) {
     celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
@@ -441,6 +465,14 @@
 }
 
 
+long celix_bundleContext_registerServiceFactoryAsync(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props) {
+    celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+    opts.factory = factory;
+    opts.serviceName = serviceName;
+    opts.properties = props;
+    return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
+}
+
 long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props) {
     celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
     opts.factory = factory;
@@ -449,9 +481,19 @@
     return celix_bundleContext_registerServiceWithOptions(ctx, &opts);
 }
 
-long celix_bundleContext_registerServiceWithOptions(bundle_context_t *ctx, const celix_service_registration_options_t *opts) {
-    long svcId = -1;
-    service_registration_t *reg = NULL;
+static long celix_bundleContext_registerServiceWithOptionsInternal(bundle_context_t *ctx, const celix_service_registration_options_t *opts, bool async) {
+    bool valid = opts->serviceName != NULL && strncmp("", opts->serviceName, 1) != 0;
+    if (!valid) {
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Required serviceName argument is NULL or empty");
+        return -1;
+    }
+    valid = opts->svc != NULL || opts->factory != NULL;
+    if (!valid) {
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Required svc or factory argument is NULL");
+        return -1;
+    }
+
+    //set properties
     celix_properties_t *props = opts->properties;
     if (props == NULL) {
         props = celix_properties_create();
@@ -461,52 +503,113 @@
     }
     const char *lang = opts->serviceLanguage != NULL && strncmp("", opts->serviceLanguage, 1) != 0 ? opts->serviceLanguage : CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
     celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
-    if (opts->serviceName != NULL && strncmp("", opts->serviceName, 1) != 0) {
-        if (opts->factory != NULL) {
-            reg = celix_framework_registerServiceFactory(ctx->framework, ctx->bundle, opts->serviceName, opts->factory, props);
-        } else {
-            bundleContext_registerService(ctx, opts->serviceName, opts->svc, props, &reg);
-        }
-        svcId = serviceRegistration_getServiceId(reg); //save to call with NULL
+
+    long svcId = -1;
+    if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+        /*
+         * Note already on event loop, cannot register the service async, because we cannot wait a future event (the
+         * service registration) the event loop.
+         *
+         * So in this case we handle the service registration the "traditional way" and call the sync fw service
+         * registrations versions on the event loop thread
+         */
+
+        svcId = celix_framework_registerService(ctx->framework, ctx->bundle, opts->serviceName, opts->svc, opts->factory, props);
     } else {
-        framework_logIfError(ctx->framework->logger, CELIX_ILLEGAL_ARGUMENT, NULL, "Required serviceName argument is NULL");
+        void (*asyncCallback)(void *data, long serviceId) = async ? opts->asyncCallback : NULL; //NOTE for not async call do not use the callback.
+        svcId = celix_framework_registerServiceAsync(ctx->framework, ctx->bundle, opts->serviceName, opts->svc, opts->factory, props, opts->asyncData, asyncCallback, NULL, NULL);
+        if (!async && svcId >= 0) {
+            //note on event loop thread, but in a sync call, so waiting till service registration is concluded
+            celix_bundleContext_waitForAsyncRegistration(ctx, svcId);
+        }
     }
+
+
     if (svcId < 0) {
         properties_destroy(props);
     } else {
         celixThreadMutex_lock(&ctx->mutex);
-        arrayList_add(ctx->svcRegistrations, reg);
+        celix_arrayList_addLong(ctx->svcRegistrations, svcId);
         celixThreadMutex_unlock(&ctx->mutex);
     }
     return svcId;
 }
 
-void celix_bundleContext_unregisterService(bundle_context_t *ctx, long serviceId) {
-    service_registration_t *found = NULL;
+long celix_bundleContext_registerServiceWithOptions(bundle_context_t *ctx, const celix_service_registration_options_t *opts) {
+    return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, false);
+}
+
+long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts) {
+    return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, true);
+}
+
+void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t* ctx, long serviceId) {
+    if (serviceId >= 0) {
+        celix_framework_waitForAsyncRegistration(ctx->framework, serviceId);
+    }
+}
+
+bool celix_bundleContext_isServiceRegistered(celix_bundle_context_t* ctx, long serviceId) {
+    return celix_serviceRegistry_isServiceRegistered(ctx->framework->registry, serviceId);
+}
+
+static void celix_bundleContext_unregisterServiceInternal(celix_bundle_context_t *ctx, long serviceId, bool async, void *data, void (*done)(void*)) {
+    long found = -1L;
     if (ctx != NULL && serviceId >= 0) {
         celixThreadMutex_lock(&ctx->mutex);
-        unsigned int size = arrayList_size(ctx->svcRegistrations);
-        for (unsigned int i = 0; i < size; ++i) {
-            service_registration_t *reg = arrayList_get(ctx->svcRegistrations, i);
-            if (reg != NULL) {
-                long svcId = serviceRegistration_getServiceId(reg);
-                if (svcId == serviceId) {
-                    found = reg;
-                    arrayList_remove(ctx->svcRegistrations, i);
-                    break;
-                }
+        int size = celix_arrayList_size(ctx->svcRegistrations);
+        for (int i = 0; i < size; ++i) {
+            long entryId = celix_arrayList_getLong(ctx->svcRegistrations, i);
+            if (entryId == serviceId) {
+                celix_arrayList_removeAt(ctx->svcRegistrations, i);
+                found = entryId;
+                break;
             }
         }
         celixThreadMutex_unlock(&ctx->mutex);
 
-        if (found != NULL) {
-            serviceRegistration_unregister(found);
+        if (found >= 0) {
+            if (async) {
+                celix_framework_unregisterAsync(ctx->framework, ctx->bundle, found, data, done);
+            } else if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+                /*
+                 * sync unregistration.
+                 * Note already on event loop, cannot unregister the service async, because we cannot wait a future event (the
+                 * service unregistration) the event loop.
+                 *
+                 * So in this case we handle the service unregistration the "traditional way" and call the sync fw service
+                 * unregistrations versions
+                 */
+                celix_framework_unregister(ctx->framework, ctx->bundle, found);
+                if (done != NULL) {
+                    done(data);
+                }
+            } else {
+                celix_framework_unregisterAsync(ctx->framework, ctx->bundle, found, data, done);
+                celix_bundleContext_waitForAsyncUnregistration(ctx, serviceId);
+            }
         } else {
-            framework_logIfError(ctx->framework->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));
+            framework_logIfError(ctx->framework->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));
         }
     }
 }
 
+void celix_bundleContext_unregisterServiceAsync(celix_bundle_context_t *ctx, long serviceId, void *data, void (*done)(void*)) {
+    return celix_bundleContext_unregisterServiceInternal(ctx, serviceId, true, data, done);
+}
+
+void celix_bundleContext_unregisterService(bundle_context_t *ctx, long serviceId) {
+    return celix_bundleContext_unregisterServiceInternal(ctx, serviceId, false, NULL, NULL);
+}
+
+void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t* ctx, long serviceId) {
+    if (serviceId >= 0) {
+        celix_framework_waitForAsyncUnregistration(ctx->framework, serviceId);
+    }
+}
+
 celix_dependency_manager_t* celix_bundleContext_getDependencyManager(bundle_context_t *ctx) {
     celix_dependency_manager_t* result = NULL;
     if (ctx != NULL) {
@@ -555,25 +658,63 @@
     return status;
 }
 
-long celix_bundleContext_trackBundlesWithOptions(
+void celix_bundleContext_trackBundlesWithOptionsCallback(void *data) {
+    celix_bundle_context_bundle_tracker_entry_t* entry = data;
+    assert(celix_framework_isCurrentThreadTheEventLoop(entry->ctx->framework));
+    fw_addBundleListener(entry->ctx->framework, entry->ctx->bundle, &entry->listener);
+}
+
+static long celix_bundleContext_trackBundlesWithOptionsInternal(
         bundle_context_t* ctx,
-        const celix_bundle_tracking_options_t *opts) {
+        const celix_bundle_tracking_options_t *opts,
+        bool async) {
     long trackerId = -1;
     celix_bundle_context_bundle_tracker_entry_t *entry = calloc(1, sizeof(*entry));
     memcpy(&entry->opts, opts, sizeof(*opts));
     entry->ctx = ctx;
+    entry->createEventId = celix_framework_nextEventId(ctx->framework);
     entry->listener.handle = entry;
     entry->listener.bundleChanged = bundleContext_bundleChanged;
-    fw_addBundleListener(ctx->framework, ctx->bundle, &entry->listener);
 
     celixThreadMutex_lock(&ctx->mutex);
     entry->trackerId = ctx->nextTrackerId++;
-    hashMap_put(ctx->bundleTrackers, (void*)entry->trackerId, entry);
-    celixThreadMutex_unlock(&ctx->mutex);
+    hashMap_put(ctx->bundleTrackers, (void*)(entry->trackerId), entry);
     trackerId = entry->trackerId;
+    celixThreadMutex_unlock(&ctx->mutex);
+
+    void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) = NULL;
+    if (async) { //note only using the async callback if this is a async call.
+        trackerCreatedCallback = opts->trackerCreatedCallback;
+    }
+    long id = celix_framework_fireGenericEvent(
+            ctx->framework,
+            entry->createEventId,
+            celix_bundle_getId(ctx->bundle),
+            "add bundle listener",
+            entry,
+            celix_bundleContext_trackBundlesWithOptionsCallback,
+            opts->trackerCreatedCallbackData,
+            trackerCreatedCallback);
+
+    if (!async) {
+        celix_framework_waitForGenericEvent(ctx->framework, id);
+    }
+
     return trackerId;
 }
 
+long celix_bundleContext_trackBundlesWithOptions(
+        bundle_context_t* ctx,
+        const celix_bundle_tracking_options_t *opts) {
+    return celix_bundleContext_trackBundlesWithOptionsInternal(ctx, opts, false);
+}
+
+long celix_bundleContext_trackBundlesWithOptionsAsync(
+        celix_bundle_context_t* ctx,
+        const celix_bundle_tracking_options_t *opts) {
+    return celix_bundleContext_trackBundlesWithOptionsInternal(ctx, opts, true);
+}
+
 long celix_bundleContext_trackBundles(
         bundle_context_t* ctx,
         void* callbackHandle,
@@ -587,6 +728,18 @@
     return celix_bundleContext_trackBundlesWithOptions(ctx, &opts);
 }
 
+long celix_bundleContext_trackBundlesAsync(
+        celix_bundle_context_t* ctx,
+        void* callbackHandle,
+        void (*onStarted)(void* handle, const celix_bundle_t *bundle),
+        void (*onStopped)(void *handle, const celix_bundle_t *bundle)) {
+    celix_bundle_tracking_options_t opts;
+    memset(&opts, 0, sizeof(opts));
+    opts.callbackHandle = callbackHandle;
+    opts.onStarted = onStarted;
+    opts.onStopped = onStopped;
+    return celix_bundleContext_trackBundlesWithOptionsAsync(ctx, &opts);
+}
 
 void celix_bundleContext_useBundles(
         bundle_context_t *ctx,
@@ -604,76 +757,293 @@
 }
 
 static void bundleContext_cleanupBundleTrackers(bundle_context_t *ctx) {
+    module_pt module;
+    const char *symbolicName;
+    bundle_getCurrentModule(ctx->bundle, &module);
+    module_getSymbolicName(module, &symbolicName);
+
+    celix_array_list_t* danglingTrkIds = NULL;
+
+    celixThreadMutex_lock(&ctx->mutex);
     hash_map_iterator_t iter = hashMapIterator_construct(ctx->bundleTrackers);
     while (hashMapIterator_hasNext(&iter)) {
-        celix_bundle_context_bundle_tracker_entry_t *tracker = hashMapIterator_nextValue(&iter);
-        fw_removeBundleListener(ctx->framework, ctx->bundle, &tracker->listener);
-        free(tracker);
+        long trkId = (long)hashMapIterator_nextKey(&iter);
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling bundle tracker with id %li for bundle %s. Add missing 'celix_bundleContext_stopTracker' calls.", trkId, symbolicName);
+        if (danglingTrkIds == NULL) {
+            danglingTrkIds = celix_arrayList_create();
+        }
+        celix_arrayList_addLong(danglingTrkIds, trkId);
     }
-    hashMap_destroy(ctx->bundleTrackers, false, false);
+    celixThreadMutex_unlock(&ctx->mutex);
+
+    if (danglingTrkIds != NULL) {
+        for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) {
+            long trkId = celix_arrayList_getLong(danglingTrkIds, i);
+            celix_bundleContext_stopTracker(ctx, trkId);
+        }
+        celix_arrayList_destroy(danglingTrkIds);
+    }
 }
 
 static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx) {
-    if(hashMap_size(ctx->serviceTrackers) > 0) {
-        module_pt module;
-        const char *symbolicName;
-        bundle_getCurrentModule(ctx->bundle, &module);
-        module_getSymbolicName(module, &symbolicName);
-        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_WARNING, "Dangling service tracker(s) for bundle %s.", symbolicName);
+    module_pt module;
+    const char *symbolicName;
+    bundle_getCurrentModule(ctx->bundle, &module);
+    module_getSymbolicName(module, &symbolicName);
+
+    celix_array_list_t* danglingTrkIds = NULL;
+
+    celixThreadMutex_lock(&ctx->mutex);
+    hash_map_iterator_t iter = hashMapIterator_construct(ctx->serviceTrackers);
+    while (hashMapIterator_hasNext(&iter)) {
+        long trkId = (long)hashMapIterator_nextKey(&iter);
+        celix_bundle_context_service_tracker_entry_t* entry = hashMap_get(ctx->serviceTrackers, (void*)trkId);
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling service tracker with trkId %li, for bundle %s and with filter %s. Add missing 'celix_bundleContext_stopTracker' calls.", trkId, symbolicName, entry->tracker->filter);
+        if (danglingTrkIds == NULL) {
+            danglingTrkIds = celix_arrayList_create();
+        }
+        celix_arrayList_addLong(danglingTrkIds, trkId);
     }
-    hashMap_destroy(ctx->serviceTrackers, false, false);
+    celixThreadMutex_unlock(&ctx->mutex);
+
+    if (danglingTrkIds != NULL) {
+        for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) {
+            long trkId = celix_arrayList_getLong(danglingTrkIds, i);
+            celix_bundleContext_stopTracker(ctx, trkId);
+        }
+        celix_arrayList_destroy(danglingTrkIds);
+    }
 }
 
 static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx) {
+    module_pt module;
+    const char *symbolicName;
+    bundle_getCurrentModule(ctx->bundle, &module);
+    module_getSymbolicName(module, &symbolicName);
+
+    celix_array_list_t* danglingTrkIds = NULL;
+
+    celixThreadMutex_lock(&ctx->mutex);
     hash_map_iterator_t iter = hashMapIterator_construct(ctx->metaTrackers);
     while (hashMapIterator_hasNext(&iter)) {
-        celix_bundle_context_service_tracker_tracker_entry_t *entry = hashMapIterator_nextValue(&iter);
-        serviceRegistration_unregister(entry->hookReg);
-        free(entry);
+        long trkId = (long)hashMapIterator_nextKey(&iter);
+        celix_bundle_context_service_tracker_tracker_entry_t *entry = hashMap_get(ctx->metaTrackers, (void*)trkId);
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling meta tracker (service tracker tracker) with trkId %li, for bundle %s and for the services %s. Add missing 'celix_bundleContext_stopTracker' calls.", trkId, symbolicName, entry->serviceName);
+        if (danglingTrkIds == NULL) {
+            danglingTrkIds = celix_arrayList_create();
+        }
+        celix_arrayList_addLong(danglingTrkIds, trkId);
     }
-    hashMap_destroy(ctx->metaTrackers, false, false);
+    celixThreadMutex_unlock(&ctx->mutex);
+
+    if (danglingTrkIds != NULL) {
+        for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) {
+            long trkId = celix_arrayList_getLong(danglingTrkIds, i);
+            celix_bundleContext_stopTracker(ctx, trkId);
+        }
+        celix_arrayList_destroy(danglingTrkIds);
+    }
 }
 
+static void bundleContext_cleanupServiceRegistration(bundle_context_t* ctx) {
+    module_pt module;
+    const char *symbolicName;
+    bundle_getCurrentModule(ctx->bundle, &module);
+    module_getSymbolicName(module, &symbolicName);
 
-void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) {
-    if (ctx != NULL && trackerId >0) {
-        bool found = false;
-        celix_bundle_context_bundle_tracker_entry_t *bundleTracker = NULL;
-        service_tracker_t *serviceTracker = NULL;
-        celix_bundle_context_service_tracker_tracker_entry_t *svcTrackerTracker = NULL;
+    celix_array_list_t* danglingSvcIds = NULL;
 
-        celixThreadMutex_lock(&ctx->mutex);
-        if (hashMap_containsKey(ctx->bundleTrackers, (void*)trackerId)) {
-            found = true;
-            bundleTracker = hashMap_remove(ctx->bundleTrackers, (void*)trackerId);
-        } else if (hashMap_containsKey(ctx->serviceTrackers, (void*)trackerId)) {
-            found = true;
-            serviceTracker = hashMap_remove(ctx->serviceTrackers, (void*)trackerId);
-        } else if (hashMap_containsKey(ctx->metaTrackers, (void*)trackerId)) {
-            found = true;
-            svcTrackerTracker = hashMap_remove(ctx->metaTrackers, (void*)trackerId);
+    celixThreadMutex_lock(&ctx->mutex);
+    for (int i = 0; i < celix_arrayList_size(ctx->svcRegistrations); ++i) {
+        service_registration_pt reg = celix_arrayList_get(ctx->svcRegistrations, i);
+        long svcId = serviceRegistration_getServiceId(reg);
+        const char* svcName = NULL;
+        serviceRegistration_getServiceName(reg, &svcName);
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling service registration with svcId %li, for bundle %s and with service name %s. Add missing 'celix_bundleContext_unregisterService' calls.", svcId, symbolicName, svcName);
+        if (danglingSvcIds == NULL) {
+            danglingSvcIds = celix_arrayList_create();
         }
-        celixThreadMutex_unlock(&ctx->mutex);
+        celix_arrayList_addLong(danglingSvcIds, svcId);
+    }
+    celixThreadMutex_unlock(&ctx->mutex);
+
+    if (danglingSvcIds != NULL) {
+        for (int i = 0; i < celix_arrayList_size(danglingSvcIds); ++i) {
+            long svcId = celix_arrayList_getLong(danglingSvcIds, i);
+            celix_bundleContext_unregisterService(ctx, svcId);
+        }
+        celix_arrayList_destroy(danglingSvcIds);
+    }
+}
+
+static void celix_bundleContext_removeBundleTracker(void *data) {
+    celix_bundle_context_bundle_tracker_entry_t *tracker = data;
+    fw_removeBundleListener(tracker->ctx->framework, tracker->ctx->bundle, &tracker->listener);
+    celixThreadMutex_lock(&tracker->ctx->mutex);
+    hashMap_remove(tracker->ctx->stoppingTrackerEventIds, (void*)tracker->trackerId);
+    celixThreadMutex_unlock(&tracker->ctx->mutex);
+    free(tracker);
+}
+
+static void celix_bundleContext_removeServiceTracker(void *data) {
+    celix_bundle_context_service_tracker_entry_t *tracker = data;
+    celix_serviceTracker_destroy(tracker->tracker);
+    celixThreadMutex_lock(&tracker->ctx->mutex);
+    hashMap_remove(tracker->ctx->stoppingTrackerEventIds, (void*)tracker->trackerId);
+    celixThreadMutex_unlock(&tracker->ctx->mutex);
+    free(tracker);
+}
+
+static void celix_bundleContext_removeServiceTrackerTracker(void *data) {
+    celix_bundle_context_service_tracker_tracker_entry_t *tracker = data;
+    celix_framework_unregister(tracker->ctx->framework, tracker->ctx->bundle, tracker->serviceId);
+    celixThreadMutex_lock(&tracker->ctx->mutex);
+    hashMap_remove(tracker->ctx->stoppingTrackerEventIds, (void*)tracker->trackerId);
+    celixThreadMutex_unlock(&tracker->ctx->mutex);
+    free(tracker->serviceName);
+    free(tracker);
+}
+
+static void celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long trackerId, bool async, void *doneData, void (*doneCallback)(void* doneData)) {
+    if (ctx == NULL || trackerId <= 0) {
+        return;
+    }
+
+    bool found = false;
+    celix_bundle_context_bundle_tracker_entry_t *bundleTracker = NULL;
+    celix_bundle_context_service_tracker_entry_t *serviceTracker = NULL;
+    celix_bundle_context_service_tracker_tracker_entry_t *svcTrackerTracker = NULL;
+
+    celixThreadMutex_lock(&ctx->mutex);
+
+    if (hashMap_containsKey(ctx->bundleTrackers, (void *) trackerId)) {
+        found = true;
+        bundleTracker = hashMap_remove(ctx->bundleTrackers, (void *) trackerId);
+    } else if (hashMap_containsKey(ctx->serviceTrackers, (void *) trackerId)) {
+        found = true;
+        serviceTracker = hashMap_remove(ctx->serviceTrackers, (void *) trackerId);
+    } else if (hashMap_containsKey(ctx->metaTrackers, (void *) trackerId)) {
+        found = true;
+        svcTrackerTracker = hashMap_remove(ctx->metaTrackers, (void *) trackerId);
+    }
+
+    if (found && !async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+        //already on the event loop, stop tracker "traditionally" to keep old behavior
+        celixThreadMutex_unlock(&ctx->mutex); //note calling remove/stops/unregister out side of locks
 
         if (bundleTracker != NULL) {
             fw_removeBundleListener(ctx->framework, ctx->bundle, &bundleTracker->listener);
             free(bundleTracker);
-        }
-        if (serviceTracker != NULL) {
-            celix_serviceTracker_destroy(serviceTracker);
-        }
-        if (svcTrackerTracker != NULL) {
-            serviceRegistration_unregister(svcTrackerTracker->hookReg);
+        } else if (serviceTracker != NULL) {
+            celix_serviceTracker_destroy(serviceTracker->tracker);
+            free(serviceTracker);
+        } else if (svcTrackerTracker != NULL) {
+            celix_framework_unregister(ctx->framework, ctx->bundle, svcTrackerTracker->serviceId);
             free(svcTrackerTracker->serviceName);
             free(svcTrackerTracker);
         }
 
-        if (!found) {
-            framework_logIfError(ctx->framework->logger, CELIX_ILLEGAL_ARGUMENT, NULL, "No tracker with id %li found'", trackerId);
+        if (doneCallback != NULL) {
+            doneCallback(doneData);
+        }
+    } else if (found && async) {
+        //NOTE: for async stopping of tracking we need to ensure we cant wait for the tracker destroy id event.
+        long eventId = celix_framework_nextEventId(ctx->framework);
+        hashMap_put(ctx->stoppingTrackerEventIds, (void*)trackerId, (void*)eventId);
+
+        if (bundleTracker != NULL) {
+            celix_framework_fireGenericEvent(ctx->framework, eventId, celix_bundle_getId(ctx->bundle), "stop tracker", bundleTracker, celix_bundleContext_removeBundleTracker, doneData, doneCallback);
+        } else if (serviceTracker != NULL) {
+            celix_framework_fireGenericEvent(ctx->framework, eventId, celix_bundle_getId(ctx->bundle), "stop tracker", serviceTracker, celix_bundleContext_removeServiceTracker, doneData, doneCallback);
+        } else if (svcTrackerTracker != NULL) {
+            celix_framework_fireGenericEvent(ctx->framework, eventId, celix_bundle_getId(ctx->bundle), "stop meta tracker", svcTrackerTracker, celix_bundleContext_removeServiceTrackerTracker, doneData, doneCallback);
+        } else {
+            fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Unexpected else branch");
+        }
+        celixThreadMutex_unlock(&ctx->mutex);
+    } else if (found) { /*sync, so waiting for events*/
+        long eventId = -1L;
+        if (bundleTracker != NULL) {
+            eventId = celix_framework_fireGenericEvent(ctx->framework, -1L, celix_bundle_getId(ctx->bundle), "stop tracker", bundleTracker, celix_bundleContext_removeBundleTracker, doneData, doneCallback);
+        } else if (serviceTracker != NULL) {
+            eventId = celix_framework_fireGenericEvent(ctx->framework, -1L, celix_bundle_getId(ctx->bundle), "stop tracker", serviceTracker, celix_bundleContext_removeServiceTracker, doneData, doneCallback);
+        } else if (svcTrackerTracker != NULL) {
+            eventId = celix_framework_fireGenericEvent(ctx->framework, -1L, celix_bundle_getId(ctx->bundle), "stop meta tracker", svcTrackerTracker, celix_bundleContext_removeServiceTrackerTracker, doneData, doneCallback);
+        } else {
+            fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Unexpected else branch");
+        }
+        celixThreadMutex_unlock(&ctx->mutex);
+        celix_framework_waitForGenericEvent(ctx->framework, eventId);
+    } else {
+        celixThreadMutex_unlock(&ctx->mutex);
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "No tracker with id %li found'", trackerId);
+    }
+}
+
+void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) {
+    return celix_bundleContext_stopTrackerInternal(ctx, trackerId, false, NULL, NULL);
+}
+
+void celix_bundleContext_stopTrackerAsync(celix_bundle_context_t *ctx, long trackerId, void *doneData, void (*doneCallback)(void* doneData)) {
+    return celix_bundleContext_stopTrackerInternal(ctx, trackerId, true, doneData, doneCallback);
+}
+
+static void celix_bundleContext_waitForTrackerInternal(celix_bundle_context_t* ctx, long trackerId, bool waitForStart) {
+    if (ctx == NULL || trackerId < 0) {
+        //silent ignore
+        return;
+    }
+
+
+    bool found = false;
+    long eventId = -1;
+    long svcId = -1;
+
+    if (waitForStart) {
+        celixThreadMutex_lock(&ctx->mutex);
+        if (hashMap_containsKey(ctx->bundleTrackers, (void *) trackerId)) {
+            found = true;
+            celix_bundle_context_bundle_tracker_entry_t* bundleTracker = hashMap_get(ctx->bundleTrackers, (void *) trackerId);
+            eventId = bundleTracker->createEventId;
+        } else if (hashMap_containsKey(ctx->serviceTrackers, (void *) trackerId)) {
+            found = true;
+            celix_bundle_context_service_tracker_entry_t* serviceTracker = hashMap_get(ctx->serviceTrackers, (void *) trackerId);
+            eventId = serviceTracker->createEventId;
+        } else if (hashMap_containsKey(ctx->metaTrackers, (void *) trackerId)) {
+            found = true;
+            celix_bundle_context_service_tracker_tracker_entry_t* svcTrackerTracker = hashMap_get(ctx->metaTrackers, (void *) trackerId);
+            svcId = svcTrackerTracker->serviceId;
+        }
+        celixThreadMutex_unlock(&ctx->mutex);
+    } else {
+        celixThreadMutex_lock(&ctx->mutex);
+        if (hashMap_containsKey(ctx->stoppingTrackerEventIds, (void*)trackerId)) {
+            found = true;
+            eventId = (long)hashMap_get(ctx->stoppingTrackerEventIds, (void*)trackerId);
+        }
+        celixThreadMutex_unlock(&ctx->mutex);
+    }
+
+    if (found) {
+        if (svcId >= 0 && waitForStart) {
+            celix_framework_waitForAsyncRegistration(ctx->framework, svcId);
+        } else if (svcId >= 0) {
+            celix_framework_waitForAsyncUnregistration(ctx->framework, svcId);
+        } else {
+            celix_framework_waitForGenericEvent(ctx->framework, eventId);
         }
     }
 }
 
+
+void celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t* ctx, long trackerId) {
+    return celix_bundleContext_waitForTrackerInternal(ctx, trackerId, true);
+}
+
+void celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t* ctx, long trackerId) {
+    return celix_bundleContext_waitForTrackerInternal(ctx, trackerId, false);
+}
+
 long celix_bundleContext_installBundle(bundle_context_t *ctx, const char *bundleLoc, bool autoStart) {
     return celix_framework_installBundle(ctx->framework, bundleLoc, autoStart);
 }
@@ -756,58 +1126,154 @@
     return celix_bundleContext_useServicesWithOptions(ctx, &opts);
 }
 
+typedef struct celix_bundle_context_use_service_data {
+    celix_bundle_context_t* ctx;
+    celix_service_use_options_t opts;
+
+    celix_thread_mutex_t mutex; //protects below
+    bool called;
+    size_t count;
+    celix_service_tracker_t * svcTracker;
+} celix_bundle_context_use_service_data_t;
+
+static void celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(void *data) {
+    celix_bundle_context_use_service_data_t* d = data;
+    assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
+
+    celix_service_tracking_options_t trkOpts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+    trkOpts.filter.serviceName = d->opts.filter.serviceName;
+    trkOpts.filter = d->opts.filter;
+    trkOpts.filter.versionRange = d->opts.filter.versionRange;
+    trkOpts.filter.serviceLanguage = d->opts.filter.serviceLanguage;
+
+    celixThreadMutex_lock(&d->mutex);
+    d->svcTracker = celix_serviceTracker_createWithOptions(d->ctx, &trkOpts);
+    celixThreadMutex_unlock(&d->mutex);
+}
+
+static void celix_bundleContext_useServiceWithOptions_2_UseService(void *data) {
+    celix_bundle_context_use_service_data_t* d = data;
+    assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
+
+    celixThreadMutex_lock(&d->mutex);
+    celix_service_tracker_t *tracker = d->svcTracker;
+    d->svcTracker = NULL;
+    celixThreadMutex_unlock(&d->mutex);
+
+    bool called = celix_serviceTracker_useHighestRankingService(tracker, d->opts.filter.serviceName, d->opts.callbackHandle, d->opts.use, d->opts.useWithProperties, d->opts.useWithOwner);
+    celix_serviceTracker_destroy(tracker);
+
+    celixThreadMutex_lock(&d->mutex);
+    d->called = called;
+    celixThreadMutex_unlock(&d->mutex);
+}
 
 bool celix_bundleContext_useServiceWithOptions(
         celix_bundle_context_t *ctx,
         const celix_service_use_options_t *opts) {
-    bool called = false;
-    celix_service_tracking_options_t trkOpts;
-    memset(&trkOpts, 0, sizeof(trkOpts));
-
-    if (opts != NULL) {
-        trkOpts.filter.serviceName = opts->filter.serviceName;
-        trkOpts.filter = opts->filter;
-        trkOpts.filter.versionRange = opts->filter.versionRange;
-        trkOpts.filter.serviceLanguage = opts->filter.serviceLanguage;
-
-        service_tracker_t *trk = celix_serviceTracker_createWithOptions(ctx, &trkOpts);
-        if (trk != NULL) {
-            if (opts->use != NULL) {
-
-            }
-            if (opts->useWithProperties != NULL) {
-
-            }
-            if (opts->useWithOwner != NULL) {
-
-            }
-            called = celix_serviceTracker_useHighestRankingService(trk, opts->filter.serviceName, opts->waitTimeoutInSeconds, opts->callbackHandle, opts->use, opts->useWithProperties, opts->useWithOwner);
-            celix_serviceTracker_destroy(trk);
-        }
+    if (opts == NULL) {
+        return false;
     }
+
+    celix_bundle_context_use_service_data_t data = {0};
+    data.ctx = ctx;
+    data.opts = *opts;
+    celixThreadMutex_create(&data.mutex, NULL);
+
+    struct timespec startTime = celix_gettime(CLOCK_MONOTONIC);
+
+    bool useServiceIsDone = false;
+    do {
+        if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+            celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(&data);
+            celix_bundleContext_useServiceWithOptions_2_UseService(&data);
+        } else {
+            long eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "create service tracker", &data, celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker, NULL, NULL);
+            celix_framework_waitForGenericEvent(ctx->framework, eventId);
+
+            eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServiceWithOptions_2_UseService, NULL, NULL);
+            celix_framework_waitForGenericEvent(ctx->framework, eventId);
+        }
+
+        bool timeoutNotUsed = opts->waitTimeoutInSeconds == 0;
+        bool timeoutExpired = celix_elapsedtime(CLOCK_MONOTONIC, startTime) > opts->waitTimeoutInSeconds;
+        celixThreadMutex_lock(&data.mutex);
+        bool called = data.called;
+        celixThreadMutex_unlock(&data.mutex);
+
+        useServiceIsDone = timeoutNotUsed || timeoutExpired || called;
+        if (!useServiceIsDone) {
+            usleep(10);
+        }
+    } while (!useServiceIsDone);
+
+    celixThreadMutex_lock(&data.mutex);
+    bool called = data.called;
+    celixThreadMutex_unlock(&data.mutex);
+    celixThreadMutex_destroy(&data.mutex);
+
     return called;
 }
 
+static void celix_bundleContext_useServicesWithOptions_1_CreateServiceTracker(void *data) {
+    celix_bundle_context_use_service_data_t* d = data;
+    assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
 
+    celix_service_tracking_options_t trkOpts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+    trkOpts.filter.serviceName = d->opts.filter.serviceName;
+    trkOpts.filter = d->opts.filter;
+    trkOpts.filter.versionRange = d->opts.filter.versionRange;
+    trkOpts.filter.serviceLanguage = d->opts.filter.serviceLanguage;
+
+    celixThreadMutex_lock(&d->mutex);
+    d->svcTracker = celix_serviceTracker_createWithOptions(d->ctx, &trkOpts);
+    celixThreadMutex_unlock(&d->mutex);
+}
+
+static void celix_bundleContext_useServicesWithOptions_2_UseServices(void *data) {
+    celix_bundle_context_use_service_data_t* d = data;
+    assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
+
+    celixThreadMutex_lock(&d->mutex);
+    celix_service_tracker_t *tracker = d->svcTracker;
+    d->svcTracker = NULL;
+    celixThreadMutex_unlock(&d->mutex);
+
+    size_t count = celix_serviceTracker_useServices(tracker, d->opts.filter.serviceName, d->opts.callbackHandle, d->opts.use, d->opts.useWithProperties, d->opts.useWithOwner);
+    celix_serviceTracker_destroy(tracker);
+
+    celixThreadMutex_lock(&d->mutex);
+    d->count = count;
+    celixThreadMutex_unlock(&d->mutex);
+}
 
 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;
-        trkOpts.filter.versionRange = opts->filter.versionRange;
-        trkOpts.filter.serviceLanguage = opts->filter.serviceLanguage;
-        trkOpts.filter.ignoreServiceLanguage = opts->filter.ignoreServiceLanguage;
-
-        service_tracker_t *trk = celix_serviceTracker_createWithOptions(ctx, &trkOpts);
-        if (trk != NULL) {
-            count = celix_serviceTracker_useServices(trk, opts->filter.serviceName, opts->callbackHandle, opts->use, opts->useWithProperties, opts->useWithOwner);
-            celix_serviceTracker_destroy(trk);
-        }
+    if (opts == NULL) {
+        return 0;
     }
+
+    celix_bundle_context_use_service_data_t data = {0};
+    data.ctx = ctx;
+    data.opts = *opts;
+
+    if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+        celix_bundleContext_useServicesWithOptions_1_CreateServiceTracker(&data);
+        celix_bundleContext_useServicesWithOptions_2_UseServices(&data);
+    } else {
+        long eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "create service tracker", &data, celix_bundleContext_useServicesWithOptions_1_CreateServiceTracker, NULL, NULL);
+        celix_framework_waitForGenericEvent(ctx->framework, eventId);
+
+        eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServicesWithOptions_2_UseServices, NULL, NULL);
+        celix_framework_waitForGenericEvent(ctx->framework, eventId);
+    }
+
+    celixThreadMutex_lock(&data.mutex);
+    size_t count = data.count;
+    celixThreadMutex_unlock(&data.mutex);
+    celixThreadMutex_destroy(&data.mutex);
+
     return count;
 }
 
@@ -821,7 +1287,19 @@
     opts.filter.serviceName = serviceName;
     opts.callbackHandle = callbackHandle;
     opts.set = set;
-    return celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, false);
+}
+
+long celix_bundleContext_trackServiceAsync(
+        bundle_context_t* ctx,
+        const char* serviceName,
+        void* callbackHandle,
+        void (*set)(void* handle, void* svc)) {
+    celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+    opts.filter.serviceName = serviceName;
+    opts.callbackHandle = callbackHandle;
+    opts.set = set;
+    return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, true);
 }
 
 
@@ -836,20 +1314,107 @@
     opts.callbackHandle = callbackHandle;
     opts.add = add;
     opts.remove = remove;
-    return celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, false);
+}
+
+long celix_bundleContext_trackServicesAsync(
+        celix_bundle_context_t* ctx,
+        const char* serviceName,
+        void* callbackHandle,
+        void (*add)(void* handle, void* svc),
+        void (*remove)(void* handle, void* svc)) {
+    celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+    opts.filter.serviceName = serviceName;
+    opts.callbackHandle = callbackHandle;
+    opts.add = add;
+    opts.remove = remove;
+    return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, true);
 }
 
 
-long celix_bundleContext_trackServicesWithOptions(bundle_context_t *ctx, const celix_service_tracking_options_t *opts) {
-    long trackerId = -1;
-    celix_service_tracker_t *tracker = celix_serviceTracker_createWithOptions(ctx, opts);
+static void celix_bundleContext_createTrackerOnEventLoop(void *data) {
+    celix_bundle_context_service_tracker_entry_t* entry = data;
+    assert(celix_framework_isCurrentThreadTheEventLoop(entry->ctx->framework));
+    celix_service_tracker_t *tracker = celix_serviceTracker_createWithOptions(entry->ctx, &entry->opts);
     if (tracker != NULL) {
-        celixThreadMutex_lock(&ctx->mutex);
-        trackerId = ctx->nextTrackerId++;
-        hashMap_put(ctx->serviceTrackers, (void*)trackerId, tracker);
-        celixThreadMutex_unlock(&ctx->mutex);
+        celixThreadMutex_lock(&entry->ctx->mutex);
+        entry->tracker = tracker;
+        celixThreadMutex_unlock(&entry->ctx->mutex);
+    } else {
+        fw_log(entry->ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot create tracker for bnd %s (%li)", celix_bundle_getSymbolicName(entry->ctx->bundle), celix_bundle_getId(entry->ctx->bundle));
     }
-    return trackerId;
+}
+
+static void celix_bundleContext_doneCreatingTrackerOnEventLoop(void *data) {
+    celix_bundle_context_service_tracker_entry_t* entry = data;
+    if (entry->trackerCreatedCallback != NULL) {
+        entry->trackerCreatedCallback(entry->trackerCreatedCallbackData);
+    }
+}
+
+
+
+static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts, bool async) {
+    if (ctx == NULL) {
+        return -1L;
+    } else if (opts == NULL) {
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot track services with a NULL service tracking options argument");
+        return -1L;
+    }
+
+    if (opts->filter.serviceName == NULL) {
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Starting a tracker for any services");
+    }
+
+    if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+        //already in event loop thread. To keep the old behavior just create the tracker traditionally (chained in the current thread).
+        celix_service_tracker_t *tracker = celix_serviceTracker_createWithOptions(ctx, opts);
+        long trackerId = -1L;
+        if (tracker != NULL) {
+            celix_bundle_context_service_tracker_entry_t* entry = calloc(1, sizeof(*entry));
+            entry->ctx = ctx;
+            entry->tracker = tracker;
+            entry->opts = *opts;
+            entry->createEventId = -1;
+            celixThreadMutex_lock(&ctx->mutex);
+            entry->trackerId = ctx->nextTrackerId++;
+            trackerId = entry->trackerId;
+            hashMap_put(ctx->serviceTrackers, (void *) trackerId, entry);
+            celixThreadMutex_unlock(&ctx->mutex);
+        }
+        return trackerId;
+    } else {
+        celix_bundle_context_service_tracker_entry_t* entry = calloc(1, sizeof(*entry));
+        entry->ctx = ctx;
+        entry->createEventId = celix_framework_nextEventId(ctx->framework);
+        entry->tracker = NULL; //will be set async
+        entry->opts = *opts;
+        if (async) { //note only setting the async callback if this is a async call
+            entry->trackerCreatedCallbackData = opts->trackerCreatedCallbackData;
+            entry->trackerCreatedCallback = opts->trackerCreatedCallback;
+        }
+        celixThreadMutex_lock(&ctx->mutex);
+        entry->trackerId = ctx->nextTrackerId++;
+        long trackerId = entry->trackerId;
+        hashMap_put(ctx->serviceTrackers, (void *)entry->trackerId, entry);
+        celixThreadMutex_unlock(&ctx->mutex);
+
+        long id = celix_framework_fireGenericEvent(ctx->framework, entry->createEventId, celix_bundle_getId(ctx->bundle), "create service tracker event", entry, celix_bundleContext_createTrackerOnEventLoop, entry, celix_bundleContext_doneCreatingTrackerOnEventLoop);
+
+        if (!async) {
+            celix_framework_waitForGenericEvent(ctx->framework, id);
+        }
+
+        return trackerId;
+    }
+}
+
+long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts) {
+    return celix_bundleContext_trackServicesWithOptionsInternal(ctx, opts, false);
+}
+
+long celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts) {
+    return celix_bundleContext_trackServicesWithOptionsInternal(ctx, opts, true);
 }
 
 long celix_bundleContext_findService(celix_bundle_context_t *ctx, const char *serviceName) {
@@ -858,19 +1423,20 @@
     return celix_bundleContext_findServiceWithOptions(ctx, &opts);
 }
 
-static void bundleContext_retrieveSvcId(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    long *svcId = handle;
-    *svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-}
-
 long celix_bundleContext_findServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) {
-    long svcId = -1L;
-    celix_service_use_options_t useOpts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-    memcpy(&useOpts.filter, opts, sizeof(useOpts.filter));
-    useOpts.callbackHandle = &svcId;
-    useOpts.useWithProperties = bundleContext_retrieveSvcId;
-    celix_bundleContext_useServiceWithOptions(ctx, &useOpts);
-    return svcId;
+    long result = -1L;
+    char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage);
+    if (filter != NULL) {
+        celix_array_list_t *svcIds = celix_serviceRegisrty_findServices(ctx->framework->registry, filter);
+        if (svcIds != NULL && celix_arrayList_size(svcIds) > 0) {
+            result = celix_arrayList_getLong(svcIds, 0);
+        }
+        if (svcIds != NULL) {
+            celix_arrayList_destroy(svcIds);
+        }
+        free(filter);
+    }
+    return result;
 }
 
 
@@ -880,22 +1446,14 @@
     return celix_bundleContext_findServicesWithOptions(ctx, &opts);
 }
 
-static void bundleContext_retrieveSvcIds(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    celix_array_list_t *list = handle;
-    if (list != NULL) {
-        long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        celix_arrayList_addLong(list, svcId);
-    }
-}
-
 celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) {
-    celix_array_list_t* list = celix_arrayList_create();
-    celix_service_use_options_t useOpts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-    memcpy(&useOpts.filter, opts, sizeof(useOpts.filter));
-    useOpts.callbackHandle = list;
-    useOpts.useWithProperties = bundleContext_retrieveSvcIds;
-    celix_bundleContext_useServicesWithOptions(ctx, &useOpts);
-    return list;
+    celix_array_list_t* result = NULL;
+    char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage);
+    if (filter != NULL) {
+        result = celix_serviceRegisrty_findServices(ctx->framework->registry, filter);
+        free(filter);
+    }
+    return result;
 }
 
 static celix_status_t bundleContext_callServicedTrackerTrackerCallback(void *handle, celix_array_list_t *listeners, bool add) {
@@ -915,9 +1473,11 @@
             trkInfo.serviceLanguage = celix_filter_findAttribute(trkInfo.filter, CELIX_FRAMEWORK_SERVICE_LANGUAGE);
             const char *filterSvcName = celix_filter_findAttribute(trkInfo.filter, OSGI_FRAMEWORK_OBJECTCLASS);
 
-            if (add && entry->add != NULL && filterSvcName != NULL && strncmp(filterSvcName, entry->serviceName, 1024*1024) == 0) {
+            bool match = entry->serviceName == NULL || (filterSvcName != NULL && strncmp(filterSvcName, entry->serviceName, 1024*1024) == 0);
+
+            if (add && entry->add != NULL && match) {
                 entry->add(entry->callbackHandle, &trkInfo);
-            } else if (entry->remove != NULL && filterSvcName != NULL && strncmp(filterSvcName, entry->serviceName, 1024*1024) == 0) {
+            } else if (!add && entry->remove != NULL && match) {
                 entry->remove(entry->callbackHandle, &trkInfo);
             }
             celix_filter_destroy(trkInfo.filter);
@@ -934,43 +1494,79 @@
     return bundleContext_callServicedTrackerTrackerCallback(handle, listeners, false);
 }
 
+long celix_bundleContext_trackServiceTrackersInternal(
+        celix_bundle_context_t *ctx,
+        const char *serviceName,
+        void *callbackHandle,
+        void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info),
+        void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info),
+        bool async,
+        void *doneData,
+        void (*doneCallback)(void*)) {
+    if (serviceName == NULL) {
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Note starting a meta tracker for all services", __FUNCTION__);
+    }
+
+    celix_bundle_context_service_tracker_tracker_entry_t *entry = calloc(1, sizeof(*entry));
+    celixThreadMutex_lock(&ctx->mutex);
+    entry->trackerId = ctx->nextTrackerId++;
+    celixThreadMutex_unlock(&ctx->mutex);
+    entry->ctx = ctx;
+    entry->callbackHandle = callbackHandle;
+    entry->add = trackerAdd;
+    entry->remove = trackerRemove;
+    entry->serviceName = celix_utils_strdup(serviceName);
+    entry->hook.handle = entry;
+    entry->hook.added = bundleContext_callServicedTrackerTrackerAdd;
+    entry->hook.removed = bundleContext_callServicedTrackerTrackerRemove;
+
+    if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+        //already on event loop, registering the "traditional way" i.e. chaining on the current thread
+        service_registration_t* reg = NULL;
+        bundleContext_registerService(ctx, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, &reg);
+        entry->serviceId = serviceRegistration_getServiceId(reg);
+    } else if (async) {
+        entry->serviceId = celix_framework_registerServiceAsync(ctx->framework, ctx->bundle, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, NULL, NULL, NULL, doneData, doneCallback);
+    } else {
+        entry->serviceId = celix_framework_registerServiceAsync(ctx->framework, ctx->bundle, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, NULL, NULL, NULL, doneData, doneCallback);
+        celix_framework_waitForAsyncRegistration(ctx->framework, entry->serviceId);
+    }
+
+    if (entry->serviceId >= 0) {
+        celixThreadMutex_lock(&ctx->mutex);
+        hashMap_put(ctx->metaTrackers, (void*)entry->trackerId, entry);
+        long trkId = entry->trackerId;
+        celixThreadMutex_unlock(&ctx->mutex);
+        return trkId;
+    } else {
+        framework_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error registering service listener hook for service tracker tracker\n");
+        free(entry);
+        return -1L;
+    }
+}
+
 long celix_bundleContext_trackServiceTrackers(
         celix_bundle_context_t *ctx,
         const char *serviceName,
         void *callbackHandle,
         void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info),
         void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info)) {
+    return celix_bundleContext_trackServiceTrackersInternal(ctx, serviceName, callbackHandle, trackerAdd, trackerRemove, false, NULL, NULL);
+}
 
-    long trackerId = -1L;
+long celix_bundleContext_trackServiceTrackersAsync(
+        celix_bundle_context_t *ctx,
+        const char *serviceName,
+        void *callbackHandle,
+        void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info),
+        void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info),
+        void *doneCallbackData,
+        void (*doneCallback)(void* doneCallbackData)) {
+    return celix_bundleContext_trackServiceTrackersInternal(ctx, serviceName, callbackHandle, trackerAdd, trackerRemove, true, doneCallbackData, doneCallback);
+}
 
-    if (serviceName == NULL) {
-        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Required serviceName not provided for function ", __FUNCTION__);
-        return trackerId;
-    }
-
-    celix_bundle_context_service_tracker_tracker_entry_t *entry = calloc(1, sizeof(*entry));
-
-    entry->callbackHandle = callbackHandle;
-    entry->add = trackerAdd;
-    entry->remove = trackerRemove;
-    entry->serviceName = strndup(serviceName, 1024*1024);
-
-    entry->hook.handle = entry;
-    entry->hook.added = bundleContext_callServicedTrackerTrackerAdd;
-    entry->hook.removed = bundleContext_callServicedTrackerTrackerRemove;
-    bundleContext_registerService(ctx, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, &entry->hookReg);
-
-    if (entry->hookReg != NULL) {
-        celixThreadMutex_lock(&ctx->mutex);
-        entry->trackerId = ctx->nextTrackerId++;
-        hashMap_put(ctx->metaTrackers, (void*)entry->trackerId, entry);
-        trackerId = entry->trackerId;
-        celixThreadMutex_unlock(&ctx->mutex);
-    } else {
-        framework_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error registering service listener hook for service tracker tracker\n");
-        free(entry);
-    }
-    return trackerId;
+void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx) {
+    celix_framework_waitUntilNoEventsForBnd(ctx->framework, celix_bundle_getId(ctx->bundle));
 }
 
 celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx) {
@@ -1052,4 +1648,4 @@
     char *name = NULL;
     celix_framework_useBundle(ctx->framework, false, bndId, &name, celix_bundleContext_getBundleSymbolicNameCallback);
     return name;
-}
\ No newline at end of file
+}
diff --git a/libs/framework/src/bundle_context_private.h b/libs/framework/src/bundle_context_private.h
index e3b7619..1b77bf5 100644
--- a/libs/framework/src/bundle_context_private.h
+++ b/libs/framework/src/bundle_context_private.h
@@ -25,24 +25,45 @@
 #include "bundle_listener.h"
 #include "celix_bundle_context.h"
 #include "listener_hook_service.h"
+#include "service_tracker.h"
 
 typedef struct celix_bundle_context_bundle_tracker_entry {
 	celix_bundle_context_t *ctx;
 	long trackerId;
 	bundle_listener_t listener;
 	celix_bundle_tracking_options_t opts;
+
+	//used for sync
+	long createEventId;
 } celix_bundle_context_bundle_tracker_entry_t;
 
+typedef struct celix_bundle_context_service_tracker_entry {
+	celix_bundle_context_t *ctx;
+	long trackerId;
+    celix_service_tracking_options_t opts;
+	celix_service_tracker_t* tracker;
+    void *trackerCreatedCallbackData;
+    void (*trackerCreatedCallback)(void *trackerCreatedCallbackData);
+
+
+    //used for sync
+    long createEventId;
+} celix_bundle_context_service_tracker_entry_t;
+
 typedef struct celix_bundle_context_service_tracker_tracker_entry {
+	celix_bundle_context_t* ctx;
 	long trackerId;
 
 	struct listener_hook_service hook;
-	service_registration_t *hookReg;
+	long serviceId;
 
 	char *serviceName;
 	void *callbackHandle;
 	void (*add)(void *handle, const celix_service_tracker_info_t *info);
 	void (*remove)(void *handle, const celix_service_tracker_info_t *info);
+
+    //used for sync
+    long createEventId;
 } celix_bundle_context_service_tracker_tracker_entry_t;
 
 struct celix_bundle_context {
@@ -50,13 +71,17 @@
 	celix_bundle_t *bundle;
 
 	celix_thread_mutex_t mutex; //protects fields below (NOTE/FIXME also used by bundle.c for listing service tracker usage)
-	array_list_t *svcRegistrations;
+	array_list_t *svcRegistrations; //serviceIds
 	celix_dependency_manager_t *mng;
 	long nextTrackerId;
 	hash_map_t *bundleTrackers; //key = trackerId, value = celix_bundle_context_bundle_tracker_entry_t*
 	hash_map_t *serviceTrackers; //key = trackerId, value = celix_service_tracker_t*
 	hash_map_t *metaTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_tracker_entry_t*
+    hash_map_t *stoppingTrackerEventIds; //key = trackerId, value = eventId for stopping the tracker. Note id are only present if the stop tracking is queued.
 };
 
 
+void celix_bundleContext_cleanup(celix_bundle_context_t *ctx);
+
+
 #endif /* BUNDLE_CONTEXT_PRIVATE_H_ */
diff --git a/libs/framework/src/celix_framework_factory.c b/libs/framework/src/celix_framework_factory.c
index 098f80e..bd138de 100644
--- a/libs/framework/src/celix_framework_factory.c
+++ b/libs/framework/src/celix_framework_factory.c
@@ -42,7 +42,6 @@
 void celix_frameworkFactory_destroyFramework(celix_framework_t *fw) {
     if (fw != NULL) {
         framework_stop(fw);
-        framework_waitForStop(fw);
         framework_destroy(fw);
     }
 }
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 152c921..1cf3e83 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -55,16 +55,6 @@
     destroy_function_fp destroy;
 };
 
-typedef struct celix_framework_bundle_entry {
-    celix_bundle_t *bnd;
-    long bndId;
-
-    celix_thread_mutex_t useMutex; //protects useCount
-    celix_thread_cond_t useCond;
-    size_t useCount;
-} celix_framework_bundle_entry_t;
-
-
 static inline celix_framework_bundle_entry_t* fw_bundleEntry_create(celix_bundle_t *bnd) {
     celix_framework_bundle_entry_t *entry = calloc(1, sizeof(*entry));
     entry->bnd = bnd;
@@ -79,10 +69,16 @@
 
 static inline void fw_bundleEntry_waitTillUseCountIs(celix_framework_bundle_entry_t *entry, size_t desiredUseCount) {
     celixThreadMutex_lock(&entry->useMutex);
+    time_t start = time(NULL);
+    bool warningPrinted = false;
     while (entry->useCount != desiredUseCount) {
         celixThreadCondition_timedwaitRelative(&entry->useCond, &entry->useMutex, 5, 0);
         if (entry->useCount != desiredUseCount) {
-            fw_log(celix_frameworkLogger_globalLogger(), CELIX_LOG_LEVEL_WARNING, "Bundle %s (%li) still in use. Use count is %u, desired is ", celix_bundle_getSymbolicName(entry->bnd), entry->bndId, entry->useCount, desiredUseCount);
+            time_t now = time(NULL);
+            if (!warningPrinted && (now-start) > 5) {
+                fw_log(celix_frameworkLogger_globalLogger(), CELIX_LOG_LEVEL_WARNING, "Bundle %s (%li) still in use. Use count is %u, desired is %li", celix_bundle_getSymbolicName(entry->bnd), entry->bndId, entry->useCount, desiredUseCount);
+                warningPrinted = true;
+            }
         }
     }
     celixThreadMutex_unlock(&entry->useMutex);
@@ -147,7 +143,6 @@
     return found;
 }
 
-celix_status_t framework_setBundleStateAndNotify(framework_pt framework, bundle_pt bundle, int state);
 celix_status_t framework_markBundleResolved(framework_pt framework, module_pt module);
 
 long framework_getNextBundleId(framework_pt framework);
@@ -159,8 +154,8 @@
 
 celix_status_t fw_populateDependentGraph(framework_pt framework, bundle_pt exporter, hash_map_pt *map);
 
-celix_status_t fw_fireBundleEvent(framework_pt framework, bundle_event_type_e, celix_framework_bundle_entry_t* entry);
-celix_status_t fw_fireFrameworkEvent(framework_pt framework, framework_event_type_e eventType, celix_status_t errorCode);
+void fw_fireBundleEvent(framework_pt framework, bundle_event_type_e, celix_framework_bundle_entry_t* entry);
+void fw_fireFrameworkEvent(framework_pt framework, framework_event_type_e eventType, celix_status_t errorCode);
 static void *fw_eventDispatcher(void *fw);
 
 celix_status_t fw_invokeBundleListener(framework_pt framework, bundle_listener_pt listener, bundle_event_pt event, bundle_pt bundle);
@@ -177,6 +172,7 @@
 static void framework_autoStartConfiguredBundles(bundle_context_t *fwCtx);
 static void framework_autoInstallConfiguredBundlesForList(bundle_context_t *fwCtx, const char *autoStart, celix_array_list_t *installedBundles);
 static void framework_autoStartConfiguredBundlesForList(bundle_context_t *fwCtx, const celix_array_list_t *installedBundles);
+static void celix_framework_addToEventQueue(celix_framework_t *fw, const celix_framework_event_t* event);
 
 struct fw_refreshHelper {
     framework_pt framework;
@@ -238,95 +234,93 @@
 
 typedef struct fw_frameworkListener * fw_framework_listener_pt;
 
-enum event_type {
-	FRAMEWORK_EVENT_TYPE,
-	BUNDLE_EVENT_TYPE,
-	EVENT_TYPE_SERVICE,
-};
 
-typedef enum event_type event_type_e;
+celix_status_t framework_create(framework_pt *out, properties_pt config) {
+    celix_framework_t* framework = calloc(1, sizeof(*framework));
+//    celix_thread_mutexattr_t attr;
+//    celixThreadMutexAttr_create(&attr);
+//    celixThreadMutexAttr_settype(&attr, CELIX_THREAD_MUTEX_RECURSIVE);
 
-struct request {
-	event_type_e type;
+    celixThreadCondition_init(&framework->shutdown.cond, NULL);
+    celixThreadMutex_create(&framework->shutdown.mutex, NULL);
+    celixThreadMutex_create(&framework->dispatcher.mutex, NULL);
+    celixThreadMutex_create(&framework->frameworkListenersLock, NULL);
+    celixThreadMutex_create(&framework->bundleListenerLock, NULL);
+    celixThreadMutex_create(&framework->installedBundles.mutex, NULL);
+    celixThreadCondition_init(&framework->dispatcher.cond, NULL);
+    framework->dispatcher.active = true;
+    framework->nextBundleId = 1L; //system bundle is 0
+    framework->installRequestMap = hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals);
+    framework->installedBundles.entries = celix_arrayList_create();
+    framework->configurationMap = config;
+    framework->bundleListeners = celix_arrayList_create();
+    framework->frameworkListeners = celix_arrayList_create();
+    framework->dispatcher.dynamicEventQueue = celix_arrayList_create();
 
-	int eventType;
-	celix_status_t errorCode;
-	const char *error;
+    //create and store framework uuid
+    char uuid[37];
+    uuid_t uid;
+    uuid_generate(uid);
+    uuid_unparse(uid, uuid);
+    properties_set(framework->configurationMap, (char*) OSGI_FRAMEWORK_FRAMEWORK_UUID, uuid);
 
-	char *filter;
-	celix_framework_bundle_entry_t* bndEntry;
-};
+    //setup framework logger
+    const char* logStr = getenv(CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME);
+    if (logStr == NULL) {
+        logStr = celix_properties_get(config, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_DEFAULT_VALUE);
+    }
+    framework->logger = celix_frameworkLogger_create(celix_logUtils_logLevelFromString(logStr, CELIX_LOG_LEVEL_INFO));
 
-typedef struct request request_t;
+    celix_status_t status =bundle_create(&framework->bundle);
+    status = CELIX_DO_IF(status, bundle_getBundleId(framework->bundle, &framework->bundleId));
+    status = CELIX_DO_IF(status, bundle_setFramework(framework->bundle, framework));
+    status = CELIX_DO_IF(status, bundleCache_create(uuid, framework->configurationMap, &framework->cache));
+    status = CELIX_DO_IF(status, serviceRegistry_create(framework, &framework->registry));
+    bundle_context_t *context = NULL;
+    status = CELIX_DO_IF(status, bundleContext_create(framework, framework->logger, framework->bundle, &context));
+    status = CELIX_DO_IF(status, bundle_setContext(framework->bundle, context));
 
+    //create framework bundle entry
+    long bndId = -1L;
+    bundle_getBundleId(framework->bundle, &bndId);
+    celix_framework_bundle_entry_t *entry = fw_bundleEntry_create(framework->bundle);
+    celixThreadMutex_lock(&framework->installedBundles.mutex);
+    celix_arrayList_add(framework->installedBundles.entries, entry);
+    celixThreadMutex_unlock(&framework->installedBundles.mutex);
 
-celix_status_t framework_create(framework_pt *framework, properties_pt config) {
-    celix_status_t status = CELIX_SUCCESS;
-
-    *framework = (framework_pt) malloc(sizeof(**framework));
-    if (*framework != NULL) {
-        celix_thread_mutexattr_t attr;
-        celixThreadMutexAttr_create(&attr);
-        celixThreadMutexAttr_settype(&attr, CELIX_THREAD_MUTEX_RECURSIVE);
-
-        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)->frameworkListenersLock, &attr));
-        status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->bundleListenerLock, NULL));
-        status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->installedBundles.mutex, NULL));
-        status = CELIX_DO_IF(status, celixThreadCondition_init(&(*framework)->dispatcher.cond, NULL));
-        if (status == CELIX_SUCCESS) {
-            (*framework)->bundle = NULL;
-            (*framework)->registry = NULL;
-            (*framework)->shutdown.done = false;
-            (*framework)->shutdown.initialized = false;
-            (*framework)->dispatcher.active = true;
-            (*framework)->nextBundleId = 1L; //system bundle is 0
-            (*framework)->cache = NULL;
-            (*framework)->installRequestMap = hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals);
-            (*framework)->installedBundles.entries = celix_arrayList_create();
-            (*framework)->bundleListeners = NULL;
-            (*framework)->frameworkListeners = NULL;
-            (*framework)->dispatcher.requests = NULL;
-            (*framework)->dispatcher.nrOfLocalRequest = 0;
-            (*framework)->configurationMap = config;
-
-            const char* logStr = getenv(CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME);
-            if (logStr == NULL) {
-                logStr = celix_properties_get(config, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_DEFAULT_VALUE);
-            }
-            (*framework)->logger = celix_frameworkLogger_create(celix_logUtils_logLevelFromString(logStr, CELIX_LOG_LEVEL_INFO));
-
-            status = CELIX_DO_IF(status, bundle_create(&(*framework)->bundle));
-            status = CELIX_DO_IF(status, bundle_getBundleId((*framework)->bundle, &(*framework)->bundleId));
-            status = CELIX_DO_IF(status, bundle_setFramework((*framework)->bundle, (*framework)));
-            if (status == CELIX_SUCCESS) {
-                //nop
-            } else {
-                status = CELIX_FRAMEWORK_EXCEPTION;
-                fw_logCode((*framework)->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not create framework");
-            }
-        } else {
-            status = CELIX_FRAMEWORK_EXCEPTION;
-            fw_logCode((*framework)->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not create framework");
-        }
-    } else {
-        status = CELIX_FRAMEWORK_EXCEPTION;
-        fw_logCode((*framework)->logger, CELIX_LOG_LEVEL_ERROR, CELIX_ENOMEM, "Could not create framework");
+    if (status != CELIX_SUCCESS) {
+        fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not create framework");
+        free(framework);
+        framework = NULL;
     }
 
+    *out = framework;
     return status;
 }
 
 celix_status_t framework_destroy(framework_pt framework) {
     celix_status_t status = CELIX_SUCCESS;
 
+    celixThreadMutex_lock(&framework->shutdown.mutex);
+    bool shutdownInitialized = framework->shutdown.initialized;
+    celixThreadMutex_unlock(&framework->shutdown.mutex);
+
+    if (shutdownInitialized) {
+        framework_waitForStop(framework);
+    } else {
+        fw_log(framework->logger, CELIX_LOG_LEVEL_FATAL, "Cannot destroy framework. framework is not stopped or stopping!");
+        return CELIX_ILLEGAL_STATE;
+    }
+
     //Note the shutdown thread can not be joined on the framework_shutdown (which is normally more logical),
     //because a shutdown can be initiated from a bundle.
     //A bundle cannot be stopped when it is waiting for a framework shutdown -> hence a shutdown thread which
     //has not been joined yet.
-    celixThread_join(framework->shutdown.thread, NULL);
+    if (!framework->shutdown.joined) {
+        celixThread_join(framework->shutdown.thread, NULL);
+        framework->shutdown.joined = true;
+    }
+
 
     serviceRegistry_destroy(framework->registry);
 
@@ -341,7 +335,7 @@
             const char *bndName = celix_bundle_getSymbolicName(bnd);
             fw_log(framework->logger, CELIX_LOG_LEVEL_FATAL, "Cannot destroy framework. The use count of bundle %s (bnd id %li) is not 0, but %u.", bndName, entry->bndId, count);
             celixThreadMutex_lock(&framework->dispatcher.mutex);
-            int nrOfRequests = celix_arrayList_size(framework->dispatcher.requests);
+            int nrOfRequests = framework->dispatcher.eventQueueSize + celix_arrayList_size(framework->dispatcher.dynamicEventQueue);
             celixThreadMutex_unlock(&framework->dispatcher.mutex);
             fw_log(framework->logger, CELIX_LOG_LEVEL_WARNING, "nr of request left: %i (should be 0).", nrOfRequests);
         }
@@ -375,6 +369,7 @@
         bundle_destroy(bnd);
 
     }
+    celixThreadMutex_unlock(&framework->installedBundles.mutex);
     celix_arrayList_destroy(framework->installedBundles.entries);
     celixThreadMutex_destroy(&framework->installedBundles.mutex);
 
@@ -387,8 +382,8 @@
         arrayList_destroy(framework->frameworkListeners);
     }
 
-    assert(celix_arrayList_size(framework->dispatcher.requests) == 0);
-    celix_arrayList_destroy(framework->dispatcher.requests);
+    assert(celix_arrayList_size(framework->dispatcher.dynamicEventQueue) == 0);
+    celix_arrayList_destroy(framework->dispatcher.dynamicEventQueue);
 
 	bundleCache_destroy(&framework->cache);
 
@@ -409,66 +404,26 @@
 }
 
 celix_status_t fw_init(framework_pt framework) {
-	bundle_state_e state = OSGI_FRAMEWORK_BUNDLE_UNKNOWN;
-	const char *location = NULL;
-	module_pt module = NULL;
-	linked_list_pt wires = NULL;
-	array_list_pt archives = NULL;
-	bundle_archive_pt archive = NULL;
+    celixThreadMutex_lock(&framework->dispatcher.mutex);
+    framework->dispatcher.active = true;
+    celixThreadMutex_unlock(&framework->dispatcher.mutex);
 
-    /*create and store framework uuid*/
-    char uuid[37];
+    celixThreadMutex_lock(&framework->shutdown.mutex);
+    framework->shutdown.done = false;
+    framework->shutdown.joined = false;
+    framework->shutdown.initialized = false;
+    celixThreadMutex_unlock(&framework->shutdown.mutex);
 
-    uuid_t uid;
-    uuid_generate(uid);
-    uuid_unparse(uid, uuid);
 
-    properties_set(framework->configurationMap, (char*) OSGI_FRAMEWORK_FRAMEWORK_UUID, uuid);
+	celixThread_create(&framework->dispatcher.thread, NULL, fw_eventDispatcher, framework);
 
-	celix_status_t status = CELIX_SUCCESS;
-	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));
-	status = CELIX_DO_IF(status, celixThread_create(&framework->dispatcher.thread, NULL, fw_eventDispatcher, framework));
-	status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
-	if (status == CELIX_SUCCESS) {
-	    if ((state == OSGI_FRAMEWORK_BUNDLE_INSTALLED) || (state == OSGI_FRAMEWORK_BUNDLE_RESOLVED)) {
-	        status = CELIX_DO_IF(status, bundleCache_create(uuid, framework->configurationMap,&framework->cache));
-	        status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
-	        if (status == CELIX_SUCCESS) {
-	            if (state == OSGI_FRAMEWORK_BUNDLE_INSTALLED) {
-	                const char *clean = properties_get(framework->configurationMap, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME);
-	                bool cleanCache = clean == NULL ? true : strcmp(clean, "false") != 0;
-	                if (cleanCache) {
-	                    bundleCache_delete(framework->cache);
-	                }
-	            }
-            }
-        }
-	}
-
-    status = CELIX_DO_IF(status, bundle_getArchive(framework->bundle, &archive));
-    status = CELIX_DO_IF(status, bundleArchive_getLocation(archive, &location));
-    if (status == CELIX_SUCCESS) {
-        long bndId = -1L;
-        bundle_getBundleId(framework->bundle, &bndId);
-        celix_framework_bundle_entry_t *entry = fw_bundleEntry_create(framework->bundle);
-        celixThreadMutex_lock(&framework->installedBundles.mutex);
-        celix_arrayList_add(framework->installedBundles.entries, entry);
-        celixThreadMutex_unlock(&framework->installedBundles.mutex);
-    }
-    status = CELIX_DO_IF(status, bundle_getCurrentModule(framework->bundle, &module));
-    if (status == CELIX_SUCCESS) {
-        wires = resolver_resolve(module);
-        if (wires != NULL) {
-            framework_markResolvedModules(framework, wires);
-        } else {
-            status = CELIX_BUNDLE_EXCEPTION;
-            fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Unresolved constraints in System Bundle");
-        }
+    bool cleanCache = celix_properties_getAsBool(framework->configurationMap, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT);
+    if (cleanCache) {
+        bundleCache_delete(framework->cache);
     }
 
-    status = CELIX_DO_IF(status, bundleCache_getArchives(framework->cache, &archives));
+    celix_array_list_t* archives = NULL;
+    celix_status_t status = bundleCache_getArchives(framework->cache, &archives);
     if (status == CELIX_SUCCESS) {
         unsigned int arcIdx;
         for (arcIdx = 0; arcIdx < arrayList_size(archives); arcIdx++) {
@@ -491,12 +446,9 @@
         arrayList_destroy(archives);
     }
 
-    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;
-    status = CELIX_DO_IF(status, bundleContext_create(framework, framework->logger, framework->bundle, &context));
-    status = CELIX_DO_IF(status, bundle_setContext(framework->bundle, context));
+    status = CELIX_DO_IF(status, bundle_setState(framework->bundle, OSGI_FRAMEWORK_BUNDLE_STARTING));
+
     if (status == CELIX_SUCCESS) {
         celix_bundle_activator_t *activator = calloc(1,(sizeof(*activator)));
         if (activator != NULL) {
@@ -515,19 +467,11 @@
             status = CELIX_DO_IF(status, bundle_getContext(framework->bundle, &validateContext));
 
             if (status == CELIX_SUCCESS) {
-                /* This code part is in principle dead, but in future it may do something.
-                 * That's why it's outcommented and not deleted
-		        if (create != NULL) {
-                    create(context, &userData);
-                }
-                */
                 activator->userData = userData;
-
                 if (start != NULL) {
                     start(userData, validateContext);
                 }
-            }
-            else{
+            } else {
             	free(activator);
             }
         } else {
@@ -554,17 +498,15 @@
 	}
 
 	status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
-	if (status == CELIX_SUCCESS) {
-	    if (state == OSGI_FRAMEWORK_BUNDLE_STARTING) {
-	        status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_ACTIVE));
-	    }
+	if (status == CELIX_SUCCESS && state == OSGI_FRAMEWORK_BUNDLE_STARTING) {
+        bundle_setState(framework->bundle, OSGI_FRAMEWORK_BUNDLE_ACTIVE);
 	}
 
 	celix_framework_bundle_entry_t* entry = fw_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, framework->bundleId);
-	status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
+	CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
     fw_bundleEntry_decreaseUseCount(entry);
 
-	status = CELIX_DO_IF(status, fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId));
+	CELIX_DO_IF(status, fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId));
 
 	if (status != CELIX_SUCCESS) {
        status = CELIX_BUNDLE_EXCEPTION;
@@ -903,8 +845,8 @@
 
                         status = CELIX_DO_IF(status, bundle_setActivator(entry->bnd, activator));
 
-                        status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_STARTING));
-                        status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTING, entry));
+                        status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_STARTING));
+                        CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTING, entry));
 
                         status = CELIX_DO_IF(status, bundle_getContext(entry->bnd, &context));
 
@@ -922,8 +864,8 @@
                             }
                         }
 
-                        status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_ACTIVE));
-                        status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
+                        status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_ACTIVE));
+                        CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
 
                         if (status != CELIX_SUCCESS) {
                             //state is still STARTING, back to resolved
@@ -935,7 +877,7 @@
                             bundle_setActivator(entry->bnd, NULL);
                             bundleContext_destroy(context);
                             free(activator);
-                            framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED);
+                            status = bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED);
                         }
                     }
                 }
@@ -986,7 +928,7 @@
 	status = CELIX_DO_IF(status, bundle_revise(bundle, location, inputFile));
 
 	status = CELIX_DO_IF(status, bundleArchive_setLastModified(archive, time(NULL)));
-	status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED));
+	status = CELIX_DO_IF(status, bundle_setState(bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED));
 
 	bundle_revision_pt revision = NULL;
 	array_list_pt handles = NULL;
@@ -1001,8 +943,8 @@
     }
 
 
-	status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, entry));
-	status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UPDATED, entry));
+	CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, entry));
+	CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UPDATED, entry));
 
     // Refresh packages?
 
@@ -1080,10 +1022,10 @@
 	}
 
 
-	status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_STOPPING));
-	status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING, entry));
+	CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_STOPPING));
+	CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING, entry));
 	if (status == CELIX_SUCCESS) {
-	    if (wasActive || (bndId == 0)) {
+	    if (wasActive) {
 	        activator = bundle_getActivator(entry->bnd);
 
 	        status = CELIX_DO_IF(status, bundle_getContext(entry->bnd, &context));
@@ -1103,8 +1045,7 @@
 	        }
 
             if (bndId > 0) {
-	            celix_serviceTracker_syncForContext(entry->bnd->context);
-                status = CELIX_DO_IF(status, serviceRegistry_clearServiceRegistrations(framework->registry, entry->bnd));
+	            celix_bundleContext_cleanup(entry->bnd->context);
                 if (status == CELIX_SUCCESS) {
                     module_pt module = NULL;
                     const char *symbolicName = NULL;
@@ -1112,8 +1053,6 @@
                     bundle_getCurrentModule(entry->bnd, &module);
                     module_getSymbolicName(module, &symbolicName);
                     bundle_getBundleId(entry->bnd, &id);
-
-                    serviceRegistry_clearReferencesFor(framework->registry, entry->bnd);
                 }
 
                 if (context != NULL) {
@@ -1121,10 +1060,14 @@
                     status = CELIX_DO_IF(status, bundle_setContext(entry->bnd, NULL));
                 }
 
-                status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+                status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+                CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED, entry));
             } else if (bndId == 0) {
                 //framework bundle
-                celix_serviceTracker_syncForContext(framework->bundle->context);
+                celix_bundleContext_cleanup(entry->bnd->context);
+
+                status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+                CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED, entry));
             }
 	    }
 
@@ -1151,7 +1094,6 @@
  	}
 
 	fw_bundleEntry_decreaseUseCount(entry);
-    celix_serviceTracker_syncForFramework(framework);
 
 	return status;
 }
@@ -1184,12 +1126,12 @@
             }
         }
 
-        status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, entry));
+        CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, entry));
 
-        status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bnd, OSGI_FRAMEWORK_BUNDLE_UNINSTALLED));
+        status = CELIX_DO_IF(status, bundle_setState(bnd, OSGI_FRAMEWORK_BUNDLE_UNINSTALLED));
         status = CELIX_DO_IF(status, bundleArchive_setLastModified(archive, time(NULL)));
 
-        status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED, entry));
+        CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED, entry));
 
         //NOTE wait outside installedBundles.mutex
         fw_bundleEntry_decreaseUseCount(entry);
@@ -1301,7 +1243,7 @@
         bundle_refresh(entry->bnd);
 
         if (fire) {
-            framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_INSTALLED);
+            bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_INSTALLED);
             fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, entry);
         }
 
@@ -1761,8 +1703,8 @@
                 status = CELIX_DO_IF(status, framework_loadBundleLibraries(framework, bundle));
             }
 
-            status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
-            status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_RESOLVED, entry));
+            status = CELIX_DO_IF(status, bundle_setState(bundle, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+            CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_RESOLVED, entry));
         }
 
         if (status != CELIX_SUCCESS) {
@@ -1823,17 +1765,16 @@
     return bnd;
 }
 
-celix_status_t framework_setBundleStateAndNotify(framework_pt framework, bundle_pt bundle, int state) {
-    int ret = CELIX_SUCCESS;
-    bundle_setState(bundle, state);
-    return ret;
-}
-
 celix_status_t framework_waitForStop(framework_pt framework) {
     celixThreadMutex_lock(&framework->shutdown.mutex);
     while (!framework->shutdown.done) {
         celixThreadCondition_wait(&framework->shutdown.cond, &framework->shutdown.mutex);
     }
+    if (!framework->shutdown.joined) {
+        celixThread_join(framework->shutdown.thread, NULL);
+        framework->shutdown.joined = true;
+    }
+
     celixThreadMutex_unlock(&framework->shutdown.mutex);
 
     return CELIX_SUCCESS;
@@ -1894,6 +1835,15 @@
         fw_bundleEntry_decreaseUseCount(fwEntry);
     }
 
+    //join dispatcher thread
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    fw->dispatcher.active = false;
+    celixThreadCondition_broadcast(&fw->dispatcher.cond);
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+    celixThread_join(fw->dispatcher.thread, NULL);
+    fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "Joined event loop thread for framework %s", celix_framework_getUUID(framework));
+
+
     celixThreadMutex_lock(&fw->shutdown.mutex);
     fw->shutdown.done = true;
     celixThreadCondition_broadcast(&fw->shutdown.cond);
@@ -1923,88 +1873,67 @@
     return result;
 }
 
-celix_status_t fw_fireBundleEvent(framework_pt framework, bundle_event_type_e eventType, celix_framework_bundle_entry_t* entry) {
-    celix_status_t status = CELIX_SUCCESS;
-
+void fw_fireBundleEvent(framework_pt framework, bundle_event_type_e eventType, celix_framework_bundle_entry_t* entry) {
     if (eventType == OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING || eventType == OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED || eventType == OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED) {
         if (entry->bndId == framework->bundleId) {
             //NOTE for framework bundle not triggering events while framework is stopped (and as result in use)
-            return CELIX_SUCCESS;
+            return;
         }
     }
 
-    request_t* request = (request_t*) calloc(1, sizeof(*request));
-    if (!request) {
-        status = CELIX_ENOMEM;
-    } else {
-        fw_bundleEntry_increaseUseCount(entry);
+    fw_bundleEntry_increaseUseCount(entry);
 
-        request->eventType = eventType;
-        request->filter = NULL;
-        request->type = BUNDLE_EVENT_TYPE;
-        request->error = NULL;
-        request->bndEntry = entry;
-
-        celixThreadMutex_lock(&framework->dispatcher.mutex);
-        if (framework->dispatcher.active) {
-            //fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Adding dispatcher bundle event request for bnd id %li with event type %i", entry->bndId, eventType);
-            celix_arrayList_add(framework->dispatcher.requests, request);
-            celixThreadCondition_broadcast(&framework->dispatcher.cond);
-        } else {
-            /*
-             * NOTE because stopping the framework is done through stopping the framework bundle,
-             * most bundle stopping / stopped events cannot be fired.
-             *
-             * TBD if this needs to addressed.
-             */
-            fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Cannot fire event dispatcher not active. Event is %x for bundle %s", eventType, celix_bundle_getSymbolicName(entry->bnd));
-            fw_bundleEntry_decreaseUseCount(entry);
-            free(request);
-        }
-        celixThreadMutex_unlock(&framework->dispatcher.mutex);
-    }
-
-    framework_logIfError(framework->logger, status, NULL, "Failed to fire bundle event");
-
-    return status;
+    celix_framework_event_t event;
+    memset(&event, 0, sizeof(event));
+    event.type = CELIX_BUNDLE_EVENT_TYPE;
+    event.bndEntry = entry;
+    event.bundleEvent = eventType;
+    celix_framework_addToEventQueue(framework, &event);
 }
 
-celix_status_t fw_fireFrameworkEvent(framework_pt framework, framework_event_type_e eventType, celix_status_t errorCode) {
-    celix_status_t status = CELIX_SUCCESS;
-
-    request_t* request = calloc(1, sizeof(*request));
-    if (!request) {
-        status = CELIX_ENOMEM;
-    } else {
-        request->eventType = eventType;
-        request->filter = NULL;
-        request->type = FRAMEWORK_EVENT_TYPE;
-        request->errorCode = errorCode;
-        request->error = "";
-
-        if (errorCode != CELIX_SUCCESS) {
-            request->error = celix_strerror(errorCode);
-        }
-
-        celixThreadMutex_lock(&framework->dispatcher.mutex);
-        if (framework->dispatcher.active) {
-            //fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Adding dispatcher framework event request for event type %i", eventType);
-            celix_arrayList_add(framework->dispatcher.requests, request);
-            celixThreadCondition_broadcast(&framework->dispatcher.cond);
-        } else {
-            free(request);
-        }
-        celixThreadMutex_unlock(&framework->dispatcher.mutex);
+void fw_fireFrameworkEvent(framework_pt framework, framework_event_type_e eventType, celix_status_t errorCode) {
+    celix_framework_event_t event;
+    memset(&event, 0, sizeof(event));
+    event.type = CELIX_FRAMEWORK_EVENT_TYPE;
+    event.fwEvent = eventType;
+    event.errorCode = errorCode;
+    event.error = "";
+    if (errorCode != CELIX_SUCCESS) {
+        event.error = celix_strerror(errorCode);
     }
 
-    framework_logIfError(framework->logger, status, NULL, "Failed to fire framework event");
-
-    return status;
+    celix_framework_addToEventQueue(framework, &event);
 }
 
+static void celix_framework_addToEventQueue(celix_framework_t *fw, const celix_framework_event_t* event) {
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    //try to add to static queue
+    if (celix_arrayList_size(fw->dispatcher.dynamicEventQueue) > 0) { //always to dynamic queue if not empty (to ensure order)
+        celix_framework_event_t *e = malloc(sizeof(*e));
+        *e = *event; //shallow copy
+        celix_arrayList_add(fw->dispatcher.dynamicEventQueue, e);
+        if (celix_arrayList_size(fw->dispatcher.dynamicEventQueue) % 100 == 0) {
+            fw_log(fw->logger, CELIX_LOG_LEVEL_WARNING, "dynamic event queue size is %i. Is there a bundle blocking on the event loop thread?", celix_arrayList_size(fw->dispatcher.dynamicEventQueue));
+        }
+    } else if (fw->dispatcher.eventQueueSize < CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE) {
+        size_t index = (fw->dispatcher.eventQueueFirstEntry + fw->dispatcher.eventQueueSize) %
+                       CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+        fw->dispatcher.eventQueue[index] = *event; //shallow copy
+        fw->dispatcher.eventQueueSize += 1;
+    } else {
+        //static queue is full, dynamics queue is empty. Add first entry to dynamic queue
+        fw_log(fw->logger, CELIX_LOG_LEVEL_WARNING,
+               "Static event queue for celix framework is full, falling back to dynamic allocated events. Increase static event queue size, current size is %i", CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE);
+        celix_framework_event_t *e = malloc(sizeof(*e));
+        *e = *event; //shallow copy
+        celix_arrayList_add(fw->dispatcher.dynamicEventQueue, e);
+    }
+    celixThreadCondition_broadcast(&fw->dispatcher.cond);
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
 
-static void fw_handleEventRequest(celix_framework_t *framework, request_t* request) {
-    if (request->type == BUNDLE_EVENT_TYPE) {
+static void fw_handleEventRequest(celix_framework_t *framework, celix_framework_event_t* event) {
+    if (event->type == CELIX_BUNDLE_EVENT_TYPE) {
         celix_array_list_t *localListeners = celix_arrayList_create();
         celixThreadMutex_lock(&framework->bundleListenerLock);
         for (int i = 0; i < celix_arrayList_size(framework->bundleListeners); ++i) {
@@ -2016,67 +1945,108 @@
         for (int i = 0; i < celix_arrayList_size(localListeners); ++i) {
             fw_bundle_listener_pt listener = arrayList_get(localListeners, i);
 
-            bundle_event_t event;
-            memset(&event, 0, sizeof(event));
-            event.bnd = request->bndEntry->bnd;
-            event.type = request->eventType;
-            fw_invokeBundleListener(framework, listener->listener, &event, listener->bundle);
+            bundle_event_t bEvent;
+            memset(&bEvent, 0, sizeof(bEvent));
+            bEvent.bnd = event->bndEntry->bnd;
+            bEvent.type = event->bundleEvent;
+            fw_invokeBundleListener(framework, listener->listener, &bEvent, listener->bundle);
 
             fw_bundleListener_decreaseUseCount(listener);
         }
         celix_arrayList_destroy(localListeners);
-    } else  if (request->type == FRAMEWORK_EVENT_TYPE) {
+    } else if (event->type == CELIX_FRAMEWORK_EVENT_TYPE) {
         celixThreadMutex_lock(&framework->frameworkListenersLock);
-        //TODO refactor use of framework listeners to use a useCount + conditition.
         for (int i = 0; i < celix_arrayList_size(framework->frameworkListeners); ++i) {
             fw_framework_listener_pt listener = celix_arrayList_get(framework->frameworkListeners, i);
-            framework_event_t event;
-            memset(&event, 0, sizeof(event));
-            event.type = request->eventType;
-            event.error = request->error;
-            event.errorCode = request->errorCode;
+            framework_event_t fEvent;
+            memset(&fEvent, 0, sizeof(fEvent));
+            fEvent.type = event->fwEvent;
+            fEvent.error = event->error;
+            fEvent.errorCode = event->errorCode;
 
-            fw_invokeFrameworkListener(framework, listener->listener, &event, listener->bundle);
+            fw_invokeFrameworkListener(framework, listener->listener, &fEvent, listener->bundle);
         }
         celixThreadMutex_unlock(&framework->frameworkListenersLock);
+    } else if (event->type == CELIX_REGISTER_SERVICE_EVENT) {
+        service_registration_t* reg = NULL;
+        celix_status_t status;
+        if (event->factory != NULL) {
+            status = celix_serviceRegistry_registerServiceFactory(framework->registry, event->bndEntry->bnd, event->serviceName, event->factory, event->properties, event->registerServiceId, &reg);
+        } else {
+            status = celix_serviceRegistry_registerService(framework->registry, event->bndEntry->bnd, event->serviceName, event->svc, event->properties, event->registerServiceId, &reg);
+        }
+        if (status != CELIX_SUCCESS) {
+            fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Could not register service async. svc name is %s, error is %s", event->serviceName, celix_strerror(status));
+        } else if (event->registerCallback != NULL) {
+            event->registerCallback(event->registerData, serviceRegistration_getServiceId(reg));
+        }
+    } else if (event->type == CELIX_UNREGISTER_SERVICE_EVENT) {
+        celix_serviceRegistry_unregisterService(framework->registry, event->bndEntry->bnd, event->unregisterServiceId);
+    } else if (event->type == CELIX_GENERIC_EVENT) {
+        if (event->genericProcess != NULL) {
+            event->genericProcess(event->genericProcessData);
+        }
+    }
+
+    if (event->doneCallback != NULL) {
+        event->doneCallback(event->doneData);
     }
 }
 
-static inline void fw_handleEvents(celix_framework_t* framework, celix_array_list_t* localRequests) {
+static inline celix_framework_event_t* fw_topEventFromQueue(celix_framework_t* fw) {
+    celix_framework_event_t* e = NULL;
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    if (fw->dispatcher.eventQueueSize > 0) {
+        e = &fw->dispatcher.eventQueue[fw->dispatcher.eventQueueFirstEntry];
+    } else if (celix_arrayList_size(fw->dispatcher.dynamicEventQueue) > 0) {
+        e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, 0);
+    }
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+    return e;
+}
+
+static inline bool fw_removeTopEventFromQueue(celix_framework_t* fw) {
+    bool dynamicallyAllocated = false;
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    if (fw->dispatcher.eventQueueSize > 0) {
+        fw->dispatcher.eventQueueFirstEntry = (fw->dispatcher.eventQueueFirstEntry+1) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+        fw->dispatcher.eventQueueSize -= 1;
+    } else if (celix_arrayList_size(fw->dispatcher.dynamicEventQueue) > 0) {
+        celix_arrayList_removeAt(fw->dispatcher.dynamicEventQueue, 0);
+        dynamicallyAllocated = true;
+    }
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+    return dynamicallyAllocated;
+}
+
+
+static inline void fw_handleEvents(celix_framework_t* framework) {
     celixThreadMutex_lock(&framework->dispatcher.mutex);
-    if (celix_arrayList_size(framework->dispatcher.requests) == 0) {
-        //TODO needs a timed wait, because this loop sometimes misses the active=false/broadcast.
-        //FIXME an go back to 'normal' cond wait.
+    int size = framework->dispatcher.eventQueueSize + celix_arrayList_size(framework->dispatcher.dynamicEventQueue);
+    if (size == 0) {
         celixThreadCondition_timedwaitRelative(&framework->dispatcher.cond, &framework->dispatcher.mutex, 1, 0);
     }
-    for (int i = 0; i < celix_arrayList_size(framework->dispatcher.requests); ++i) {
-        request_t* r = celix_arrayList_get(framework->dispatcher.requests, i);
-        celix_arrayList_add(localRequests, r);
-//        if (r->type == BUNDLE_EVENT_TYPE) {
-//            fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE,
-//                   "Removing dispatcher bundle event request for bnd id %li with event type %i", r->bndEntry->bndId, r->eventType);
-//        } else {
-//            fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE,
-//                   "Removing dispatcher framework event request for event type %i", r->eventType);
-//        }
-    }
-    celix_arrayList_clear(framework->dispatcher.requests);
-    framework->dispatcher.nrOfLocalRequest = celix_arrayList_size(localRequests);
+    size = framework->dispatcher.eventQueueSize + celix_arrayList_size(framework->dispatcher.dynamicEventQueue);
     celixThreadMutex_unlock(&framework->dispatcher.mutex);
 
-    for (int i = 0; i < celix_arrayList_size(localRequests); ++i) {
-        request_t* request = celix_arrayList_get(localRequests, i);
-        fw_handleEventRequest(framework, request);
-        if (request->bndEntry != NULL) {
-            fw_bundleEntry_decreaseUseCount(request->bndEntry);
+    while (size > 0) {
+        celix_framework_event_t* topEvent = fw_topEventFromQueue(framework);
+        fw_handleEventRequest(framework, topEvent);
+        bool dynamiclyAllocatedEvent = fw_removeTopEventFromQueue(framework);
+
+        if (topEvent->bndEntry != NULL) {
+            fw_bundleEntry_decreaseUseCount(topEvent->bndEntry);
         }
-        free(request);
-    }
-    celix_arrayList_clear(localRequests);
+        free(topEvent->serviceName);
+        if (dynamiclyAllocatedEvent) {
+            free(topEvent);
+        }
 
-    celixThreadMutex_lock(&framework->dispatcher.mutex);
-    framework->dispatcher.nrOfLocalRequest = 0;
-    celixThreadMutex_unlock(&framework->dispatcher.mutex);
+        celixThreadMutex_lock(&framework->dispatcher.mutex);
+        size = framework->dispatcher.eventQueueSize + celix_arrayList_size(framework->dispatcher.dynamicEventQueue);
+        celixThreadCondition_broadcast(&framework->dispatcher.cond);
+        celixThreadMutex_unlock(&framework->dispatcher.mutex);
+    }
 }
 
 static void *fw_eventDispatcher(void *fw) {
@@ -2086,27 +2056,21 @@
     bool active = framework->dispatcher.active;
     celixThreadMutex_unlock(&framework->dispatcher.mutex);
 
-    celix_array_list_t *localRequests = celix_arrayList_create();
-
     while (active) {
-        fw_handleEvents(framework, localRequests);
-
+        fw_handleEvents(framework);
         celixThreadMutex_lock(&framework->dispatcher.mutex);
-        celixThreadCondition_broadcast(&framework->dispatcher.cond); //trigger threads waiting for an empty event queue (after local events are handled)
         active = framework->dispatcher.active;
         celixThreadMutex_unlock(&framework->dispatcher.mutex);
     }
 
     //not active any more, last run for possible request left overs
     celixThreadMutex_lock(&framework->dispatcher.mutex);
-    bool needLastRun = celix_arrayList_size(framework->dispatcher.requests) > 0;
+    bool needLastRun = framework->dispatcher.eventQueueSize > 0 || celix_arrayList_size(framework->dispatcher.dynamicEventQueue) > 0;
     celixThreadMutex_unlock(&framework->dispatcher.mutex);
     if (needLastRun) {
-        fw_handleEvents(framework, localRequests);
+        fw_handleEvents(framework);
     }
 
-
-    celix_arrayList_destroy(localRequests);
     celixThread_exit(NULL);
     return NULL;
 
@@ -2153,14 +2117,7 @@
         celixThreadMutex_unlock(&framework->shutdown.mutex);
 
         if (!alreadyInitialized) {
-            celixThreadMutex_lock(&framework->dispatcher.mutex);
-            framework->dispatcher.active = false;
-            celixThreadCondition_broadcast(&framework->dispatcher.cond);
-            celixThreadMutex_unlock(&framework->dispatcher.mutex);
-            celixThread_join(framework->dispatcher.thread, NULL);
-            fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Joined shutdown thread for framework %s", celix_framework_getUUID(framework));
-
-            celixThread_create(&framework->shutdown.thread, NULL, &framework_shutdown, framework);
+            celixThread_create(&framework->shutdown.thread, NULL, framework_shutdown, framework);
         }
     } else {
         status = CELIX_FRAMEWORK_EXCEPTION;
@@ -2385,9 +2342,9 @@
     return called;
 }
 
-service_registration_t* celix_framework_registerServiceFactory(framework_t *fw , const celix_bundle_t *bnd, const char* serviceName, celix_service_factory_t *factory, celix_properties_t *properties) {
+long celix_framework_registerService(framework_t *fw, celix_bundle_t *bnd, const char* serviceName, void* svc, celix_service_factory_t *factory, celix_properties_t *properties) {
     const char *error = NULL;
-    celix_status_t status = CELIX_SUCCESS;
+    celix_status_t status;
     service_registration_t *reg = NULL;
 
     long bndId = celix_bundle_getId(bnd);
@@ -2395,14 +2352,166 @@
 
 
     if (serviceName != NULL && factory != NULL) {
-        status = CELIX_DO_IF(status, celix_serviceRegistry_registerServiceFactory(fw->registry, bnd, serviceName, factory, properties, &reg));
+        status = celix_serviceRegistry_registerServiceFactory(fw->registry, bnd, serviceName, factory, properties, 0, &reg);
+    } else if (serviceName != NULL) {
+        status = celix_serviceRegistry_registerService(fw->registry, bnd, serviceName, svc, properties, 0, &reg);
+    } else {
+        fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Invalid arguments serviceName", serviceName);
+        status = CELIX_ILLEGAL_ARGUMENT;
     }
 
     fw_bundleEntry_decreaseUseCount(entry);
 
-    framework_logIfError(fw->logger, status, error, "Cannot register service factory: %s", serviceName);
+    framework_logIfError(fw->logger, status, error, "Cannot register %s '%s'", factory == NULL ? "service" : "service factory", serviceName);
 
-    return reg;
+    return serviceRegistration_getServiceId(reg);
+}
+
+long celix_framework_registerServiceAsync(
+        framework_t *fw,
+        celix_bundle_t *bnd,
+        const char* serviceName,
+        void* svc,
+        celix_service_factory_t* factory,
+        celix_properties_t *properties,
+        void* registerDoneData,
+        void(*registerDoneCallback)(void *registerDoneData, long serviceId),
+        void* eventDoneData,
+        void (*eventDoneCallback)(void* eventDoneData)) {
+    long bndId = celix_bundle_getId(bnd);
+    celix_framework_bundle_entry_t *entry = fw_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId);
+
+    long svcId = celix_serviceRegistry_nextSvcId(fw->registry);
+
+    celix_framework_event_t event;
+    memset(&event, 0, sizeof(event));
+    event.type = CELIX_REGISTER_SERVICE_EVENT;
+    event.bndEntry = entry;
+    event.registerServiceId = svcId;
+    event.serviceName = celix_utils_strdup(serviceName);
+    event.properties = properties;
+    event.svc = svc;
+    event.factory = factory;
+    event.registerData = registerDoneData;
+    event.registerCallback = registerDoneCallback;
+    event.doneData = eventDoneData;
+    event.doneCallback = eventDoneCallback;
+    celix_framework_addToEventQueue(fw, &event);
+
+    return svcId;
+}
+
+void celix_framework_unregisterAsync(celix_framework_t* fw, celix_bundle_t* bnd, long serviceId, void *doneData, void (*doneCallback)(void*)) {
+    long bndId = celix_bundle_getId(bnd);
+    celix_framework_bundle_entry_t *entry = fw_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId);
+
+    celix_framework_event_t event;
+    memset(&event, 0, sizeof(event));
+    event.type = CELIX_UNREGISTER_SERVICE_EVENT;
+    event.bndEntry = entry;
+    event.unregisterServiceId = serviceId;
+    event.doneData = doneData;
+    event.doneCallback = doneCallback;
+
+    celix_framework_addToEventQueue(fw, &event);
+}
+
+void celix_framework_unregister(celix_framework_t* fw, celix_bundle_t* bnd, long serviceId) {
+    celix_serviceRegistry_unregisterService(fw->registry, bnd, serviceId);
+}
+
+void celix_framework_waitForAsyncRegistration(framework_t *fw, long svcId) {
+    assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
+
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    bool registrationsInProgress = true;
+    while (registrationsInProgress) {
+        registrationsInProgress = false;
+        for (int i = 0; i < fw->dispatcher.eventQueueSize; ++i) {
+            int index = (fw->dispatcher.eventQueueFirstEntry + i) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+            celix_framework_event_t* e = &fw->dispatcher.eventQueue[index];
+            if (e->type == CELIX_REGISTER_SERVICE_EVENT && e->registerServiceId == svcId) {
+                registrationsInProgress = true;
+                break;
+            }
+        }
+        for (int i = 0; !registrationsInProgress && i < celix_arrayList_size(fw->dispatcher.dynamicEventQueue); ++i) {
+            celix_framework_event_t* e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, i);
+            if (e->type == CELIX_REGISTER_SERVICE_EVENT && e->registerServiceId == svcId) {
+                registrationsInProgress = true;
+                break;
+            }
+        }
+        if (registrationsInProgress) {
+            celixThreadCondition_timedwaitRelative(&fw->dispatcher.cond, &fw->dispatcher.mutex, 5, 0);
+        }
+    }
+
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
+
+void celix_framework_waitForAsyncUnregistration(framework_t *fw, long svcId) {
+    assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
+
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    bool registrationsInProgress = true;
+    while (registrationsInProgress) {
+        registrationsInProgress = false;
+        for (int i = 0; i < fw->dispatcher.eventQueueSize; ++i) {
+            int index = (fw->dispatcher.eventQueueFirstEntry + i) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+            celix_framework_event_t* e = &fw->dispatcher.eventQueue[index];
+            if (e->type == CELIX_UNREGISTER_SERVICE_EVENT && e->unregisterServiceId == svcId) {
+                registrationsInProgress = true;
+                break;
+            }
+        }
+        for (int i = 0; !registrationsInProgress && i < celix_arrayList_size(fw->dispatcher.dynamicEventQueue); ++i) {
+            celix_framework_event_t* e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, i);
+            if (e->type == CELIX_UNREGISTER_SERVICE_EVENT && e->unregisterServiceId == svcId) {
+                registrationsInProgress = true;
+                break;
+            }
+        }
+        if (registrationsInProgress) {
+            celixThreadCondition_timedwaitRelative(&fw->dispatcher.cond, &fw->dispatcher.mutex, 5, 0);
+        }
+    }
+
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
+
+void celix_framework_waitForAsyncRegistrations(framework_t *fw, long bndId) {
+    assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
+
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    bool registrationsInProgress = true;
+    while (registrationsInProgress) {
+        registrationsInProgress = false;
+        for (int i = 0; i < fw->dispatcher.eventQueueSize; ++i) {
+            int index = (fw->dispatcher.eventQueueFirstEntry + i) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+            celix_framework_event_t* e = &fw->dispatcher.eventQueue[index];
+            if ((e->type == CELIX_REGISTER_SERVICE_EVENT || e->type == CELIX_UNREGISTER_SERVICE_EVENT) && e->bndEntry->bndId == bndId) {
+                registrationsInProgress = true;
+                break;
+            }
+        }
+        for (int i = 0; i < !registrationsInProgress && celix_arrayList_size(fw->dispatcher.dynamicEventQueue); ++i) {
+            celix_framework_event_t* e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, i);
+            if ((e->type == CELIX_REGISTER_SERVICE_EVENT || e->type == CELIX_UNREGISTER_SERVICE_EVENT) && e->bndEntry->bndId == bndId) {
+                registrationsInProgress = true;
+                break;
+            }
+        }
+        if (registrationsInProgress) {
+            celixThreadCondition_timedwaitRelative(&fw->dispatcher.cond, &fw->dispatcher.mutex, 5, 0);
+        }
+    }
+
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
+
+bool celix_framework_isCurrentThreadTheEventLoop(framework_t* fw) {
+    return celixThread_equals(celixThread_self(), fw->dispatcher.thread);
 }
 
 const char* celix_framework_getUUID(const celix_framework_t *fw) {
@@ -2462,6 +2571,12 @@
     return isActive;
 }
 
+static void celix_framework_waitForBundleEvents(celix_framework_t *fw, long bndId) {
+    if (bndId >= 0 && !celix_framework_isCurrentThreadTheEventLoop(fw)) {
+        celix_framework_waitUntilNoEventsForBnd(fw, bndId);
+    }
+}
+
 long celix_framework_installBundle(celix_framework_t *fw, const char *bundleLoc, bool autoStart) {
     long bundleId = -1;
     bundle_t *bnd = NULL;
@@ -2471,9 +2586,11 @@
         status = bundle_getBundleId(bnd, &bundleId);
         if (status == CELIX_SUCCESS && autoStart) {
             status = bundle_start(bnd);
+
         }
     }
 
+    celix_framework_waitForBundleEvents(fw, bundleId);
     framework_logIfError(fw->logger, status, NULL, "Failed to install bundle '%s'", bundleLoc);
 
     return bundleId;
@@ -2495,6 +2612,7 @@
             uninstalled = status == CELIX_SUCCESS;
         }
     }
+    celix_framework_waitForBundleEvents(fw, bndId);
     return uninstalled;
 }
 
@@ -2511,6 +2629,7 @@
         }
         fw_bundleEntry_decreaseUseCount(entry);
     }
+    celix_framework_waitForBundleEvents(fw, bndId);
     return stopped;
 }
 
@@ -2525,17 +2644,112 @@
         }
         fw_bundleEntry_decreaseUseCount(entry);
     }
+    celix_framework_waitForBundleEvents(fw, bndId);
     return started;
 }
 
 void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw) {
+    assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
+
     celixThreadMutex_lock(&fw->dispatcher.mutex);
-    while ((celix_arrayList_size(fw->dispatcher.requests) + fw->dispatcher.nrOfLocalRequest) != 0) {
+    while (fw->dispatcher.eventQueueSize > 0 || celix_arrayList_size(fw->dispatcher.dynamicEventQueue) > 0) {
         celixThreadCondition_wait(&fw->dispatcher.cond, &fw->dispatcher.mutex);
     }
     celixThreadMutex_unlock(&fw->dispatcher.mutex);
 }
 
+void celix_framework_waitUntilNoEventsForBnd(celix_framework_t* fw, long bndId) {
+    assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
+
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    bool eventInProgress = true;
+    while (eventInProgress) {
+        eventInProgress = false;
+        for (int i = 0; i < fw->dispatcher.eventQueueSize; ++i) {
+            int index = (fw->dispatcher.eventQueueFirstEntry + i) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+            celix_framework_event_t* e = &fw->dispatcher.eventQueue[index];
+            if (e->bndEntry != NULL && e->bndEntry->bndId == bndId) {
+                eventInProgress = true;
+                break;
+            }
+        }
+        for (int i = 0; !eventInProgress && i < celix_arrayList_size(fw->dispatcher.dynamicEventQueue); ++i) {
+            celix_framework_event_t* e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, i);
+            if (e->bndEntry != NULL && e->bndEntry->bndId == bndId) {
+                eventInProgress = true;
+                break;
+            }
+        }
+        if (eventInProgress) {
+            celixThreadCondition_timedwaitRelative(&fw->dispatcher.cond, &fw->dispatcher.mutex, 5, 0);
+        }
+    }
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
+
+
 void celix_framework_setLogCallback(celix_framework_t* fw, void* logHandle, void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *function, int line, const char *format, va_list formatArgs)) {
     celix_frameworkLogger_setLogCallback(fw->logger, logHandle, logFunction);
 }
+
+long celix_framework_fireGenericEvent(framework_t* fw, long eventId, long bndId, const char *eventName, void* processData, void (*processCallback)(void *data), void* doneData, void (*doneCallback)(void* doneData)) {
+    celix_framework_bundle_entry_t* bndEntry = NULL;
+    if (bndId >=0) {
+        bndEntry = fw_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId);
+        if (bndEntry == NULL) {
+            fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Cannot find bundle for id %li", bndId);
+            return -1L;
+        }
+    }
+
+    if (eventId < 0) {
+        eventId = celix_framework_nextEventId(fw);
+    }
+
+    celix_framework_event_t event;
+    memset(&event, 0, sizeof(event));
+    event.type = CELIX_GENERIC_EVENT;
+    event.bndEntry = bndEntry;
+    event.genericEventId = eventId;
+    event.genericEventName = eventName;
+    event.genericProcessData = processData;
+    event.genericProcess = processCallback;
+    event.doneData = doneData;
+    event.doneCallback = doneCallback;
+    celix_framework_addToEventQueue(fw, &event);
+
+    return eventId;
+}
+
+long celix_framework_nextEventId(framework_t *fw) {
+    return __atomic_fetch_add(&fw->nextGenericEventId, 1, __ATOMIC_RELAXED);
+}
+
+void celix_framework_waitForGenericEvent(framework_t *fw, long eventId) {
+    assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
+
+    celixThreadMutex_lock(&fw->dispatcher.mutex);
+    bool eventInProgress = true;
+    while (eventInProgress) {
+        eventInProgress = false;
+        for (int i = 0; i < fw->dispatcher.eventQueueSize; ++i) {
+            int index = (fw->dispatcher.eventQueueFirstEntry + i) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+            celix_framework_event_t* e = &fw->dispatcher.eventQueue[index];
+            if (e->type == CELIX_GENERIC_EVENT && e->genericEventId == eventId) {
+                eventInProgress = true;
+                break;
+            }
+        }
+        for (int i = 0; !eventInProgress && i < celix_arrayList_size(fw->dispatcher.dynamicEventQueue); ++i) {
+            celix_framework_event_t* e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, i);
+            if (e->type == CELIX_GENERIC_EVENT && e->genericEventId == eventId) {
+                eventInProgress = true;
+                break;
+            }
+        }
+        if (eventInProgress) {
+            celixThreadCondition_timedwaitRelative(&fw->dispatcher.cond, &fw->dispatcher.mutex, 5, 0);
+        }
+    }
+    celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
\ No newline at end of file
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index 4c0b517..7eaa0c7 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -41,10 +41,65 @@
 #include "celix_threads.h"
 #include "service_registry.h"
 
+#define CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE 256
+
+typedef struct celix_framework_bundle_entry {
+    celix_bundle_t *bnd;
+    long bndId;
+
+    celix_thread_mutex_t useMutex; //protects useCount
+    celix_thread_cond_t useCond;
+    size_t useCount;
+} celix_framework_bundle_entry_t;
+
+enum celix_framework_event_type {
+    CELIX_FRAMEWORK_EVENT_TYPE      = 0x01,
+    CELIX_BUNDLE_EVENT_TYPE         = 0x11,
+    CELIX_REGISTER_SERVICE_EVENT    = 0x21,
+    CELIX_UNREGISTER_SERVICE_EVENT  = 0x22,
+    CELIX_GENERIC_EVENT             = 0x30
+};
+
+typedef enum celix_framework_event_type celix_framework_event_type_e;
+
+struct celix_framework_event {
+    celix_framework_event_type_e type;
+    celix_framework_bundle_entry_t* bndEntry;
+
+    void *doneData;
+    void (*doneCallback)(void*);
+
+    //for framework event
+    framework_event_type_e fwEvent;
+    celix_status_t errorCode;
+    const char *error;
+
+    //for bundle event
+    bundle_event_type_e bundleEvent;
+
+    //for register event
+    long registerServiceId;
+    char *serviceName;
+    void *svc;
+    celix_service_factory_t* factory;
+    celix_properties_t* properties;
+    void* registerData;
+    void (*registerCallback)(void *data, long serviceId);
+
+    //for unregister event
+    long unregisterServiceId;
+
+    //for the generic event
+    long genericEventId;
+    const char* genericEventName;
+    void *genericProcessData;
+    void (*genericProcess)(void*);
+
+};
+
+typedef struct celix_framework_event celix_framework_event_t;
+
 struct celix_framework {
-#ifdef WITH_APR
-    apr_pool_t *pool;
-#endif
     celix_bundle_t *bundle;
     long bundleId; //the bundle id of the framework (normally 0)
     hash_map_pt installRequestMap;
@@ -63,6 +118,7 @@
         celix_thread_mutex_t mutex;
         celix_thread_cond_t cond;
         bool done; //true is shutdown is done
+        bool joined; //true if shutdown thread is joined
         bool initialized; //true is a shutdown is initialized
         celix_thread_t thread;
     } shutdown;
@@ -80,13 +136,17 @@
     struct {
         celix_thread_cond_t cond;
         celix_thread_t thread;
-        celix_thread_mutex_t mutex; //protect active and requests
+        celix_thread_mutex_t mutex; //protects below
         bool active;
-        celix_array_list_t *requests;
-        size_t nrOfLocalRequest;
+        celix_framework_event_t eventQueue[CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE]; //ring buffer
+        int eventQueueSize;
+        int eventQueueFirstEntry;
+        celix_array_list_t *dynamicEventQueue; //entry = celix_framework_event_t*. Used when the eventQueue is full
     } dispatcher;
 
     celix_framework_logger_t* logger;
+
+    long nextGenericEventId;
 };
 
 FRAMEWORK_EXPORT celix_status_t fw_getProperty(framework_pt framework, const char* name, const char* defaultValue, const char** value);
@@ -151,6 +211,56 @@
  **********************************************************************************************************************
  **********************************************************************************************************************/
 
-service_registration_t* celix_framework_registerServiceFactory(framework_t *fw , const celix_bundle_t *bnd, const char* serviceName, celix_service_factory_t *factory, celix_properties_t *properties);
+/**
+ * register service or service factory. Will return a svc id directly and return a service registration in a callback.
+ * callback is called on the fw event loop thread
+ */
+long celix_framework_registerService(framework_t *fw, celix_bundle_t *bnd, const char* serviceName, void* svc, celix_service_factory_t *factory, celix_properties_t *properties);
+
+/**
+ * register service or service factory async. Will return a svc id directly and return a service registration in a callback.
+ * callback is called on the fw event loop thread
+ */
+long celix_framework_registerServiceAsync(
+        framework_t *fw,
+        celix_bundle_t *bnd,
+        const char* serviceName,
+        void* svc,
+        celix_service_factory_t* factory,
+        celix_properties_t *properties,
+        void* registerDoneData,
+        void(*registerDoneCallback)(void *registerDoneData, long serviceId),
+        void* eventDoneData,
+        void (*eventDoneCallback)(void* eventDoneData));
+
+/**
+ * Unregister service async on the event loop thread.
+ */
+void celix_framework_unregisterAsync(celix_framework_t* fw, celix_bundle_t* bnd, long serviceId, void *doneData, void (*doneCallback)(void*));
+
+/**
+ * Unregister service
+ */
+void celix_framework_unregister(celix_framework_t* fw, celix_bundle_t* bnd, long serviceId);
+
+/**
+ * Wait til all service registration or unregistration events for a specific bundle are no longer present in the event queue.
+ */
+void celix_framework_waitForAsyncRegistrations(celix_framework_t *fw, long bndId);
+
+/**
+ * Wait til the async service registration for the provided service id is no longer present in the event queue.
+ */
+void celix_framework_waitForAsyncRegistration(celix_framework_t *fw, long svcId);
+
+/**
+ * Wait til the async service unregistration for the provided service id is no longer present in the event queue.
+ */
+void celix_framework_waitForAsyncUnregistration(framework_t *fw, long svcId);
+
+/**
+ * Returns whether the current thread is the Celix framework event loop thread.
+ */
+bool celix_framework_isCurrentThreadTheEventLoop(framework_t* fw);
 
 #endif /* FRAMEWORK_PRIVATE_H_ */
diff --git a/libs/framework/src/resolver.c b/libs/framework/src/resolver.c
index ac34609..5b68632 100644
--- a/libs/framework/src/resolver.c
+++ b/libs/framework/src/resolver.c
@@ -288,6 +288,9 @@
 }
 
 void resolver_removeModule(module_pt module) {
+    if (m_modules == NULL) {
+        return;
+    }
     linked_list_pt caps = NULL;
     linkedList_removeElement(m_modules, module);
     caps = module_getCapabilities(module);
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index e9b8d01..1b2924c 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -30,23 +30,10 @@
 #include "service_reference_private.h"
 #include "framework_private.h"
 
-#ifdef DEBUG
-#define CHECK_DELETED_REFERENCES true
-#else
-#define CHECK_DELETED_REFERENCES false
-#endif
-
-static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, enum celix_service_type svcType, service_registration_pt *registration);
+static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, long reservedId, enum celix_service_type svcType, service_registration_pt *registration);
 static celix_status_t serviceRegistry_addHooks(service_registry_pt registry, const char* serviceName, const void *serviceObject, service_registration_pt registration);
 static celix_status_t serviceRegistry_removeHook(service_registry_pt registry, service_registration_pt registration);
 static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry, bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount);
-static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry, service_registration_pt reg);
-static celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt ref,
-                                                     reference_status_t *refStatus);
-static void serviceRegistry_logIllegalReference(service_registry_pt registry, service_reference_pt reference,
-                                                   reference_status_t refStatus);
-static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt registry, service_reference_pt reference,
-                                                  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);
@@ -79,11 +66,8 @@
 
 		reg->serviceRegistrations = hashMap_create(NULL, NULL, NULL, NULL);
 		reg->framework = framework;
-		reg->nextServiceId = 1L;
-		reg->serviceReferences = hashMap_create(NULL, NULL, NULL, NULL);
-
-        reg->checkDeletedReferences = CHECK_DELETED_REFERENCES;
-        reg->deletedServiceReferences = hashMap_create(NULL, NULL, NULL, NULL);
+        reg->nextServiceId = 1L;
+        reg->serviceReferences = hashMap_create(NULL, NULL, NULL, NULL);
 
 		reg->listenerHooks = celix_arrayList_create();
 		reg->serviceListeners = celix_arrayList_create();
@@ -155,8 +139,6 @@
     }
     celix_arrayList_destroy(registry->listenerHooks);
 
-    hashMap_destroy(registry->deletedServiceReferences, false, false);
-
     size = hashMap_size(registry->pendingRegisterEvents.map);
     assert(size == 0);
     celixThreadMutex_destroy(&registry->pendingRegisterEvents.mutex);
@@ -198,16 +180,16 @@
 }
 
 celix_status_t serviceRegistry_registerService(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void* serviceObject, properties_pt dictionary, service_registration_pt *registration) {
-    return serviceRegistry_registerServiceInternal(registry, bundle, serviceName, serviceObject, dictionary, CELIX_PLAIN_SERVICE, registration);
+    return serviceRegistry_registerServiceInternal(registry, bundle, serviceName, serviceObject, dictionary, 0 /*TODO*/, CELIX_PLAIN_SERVICE, registration);
 }
 
 celix_status_t serviceRegistry_registerServiceFactory(service_registry_pt registry, bundle_pt bundle, const char* serviceName, service_factory_pt factory, properties_pt dictionary, service_registration_pt *registration) {
-    return serviceRegistry_registerServiceInternal(registry, bundle, serviceName, (const void *) factory, dictionary, CELIX_DEPRECATED_FACTORY_SERVICE, registration);
+    return serviceRegistry_registerServiceInternal(registry, bundle, serviceName, (const void *) factory, dictionary, 0 /*TODO*/, CELIX_DEPRECATED_FACTORY_SERVICE, registration);
 }
 
-static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, enum celix_service_type svcType, service_registration_pt *registration) {
+static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, long reservedId, enum celix_service_type svcType, service_registration_pt *registration) {
 	array_list_pt regs;
-	long svcId = celix_serviceRegistry_nextSvcId(registry);
+	long svcId = reservedId > 0 ? reservedId : celix_serviceRegistry_nextSvcId(registry);
 
 	if (svcType == CELIX_DEPRECATED_FACTORY_SERVICE) {
         *registration = serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName,
@@ -299,50 +281,6 @@
 	return CELIX_SUCCESS;
 }
 
-celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt registry, bundle_pt bundle) {
-    celix_status_t status = CELIX_SUCCESS;
-    array_list_pt registrations = NULL;
-    bool registrationsLeft;
-
-    celixThreadRwlock_writeLock(&registry->lock);
-    registrations = hashMap_get(registry->serviceRegistrations, bundle);
-    registrationsLeft = (registrations != NULL);
-    if (registrationsLeft) {
-        registrationsLeft = (arrayList_size(registrations) > 0);
-    }
-    celixThreadRwlock_unlock(&registry->lock);
-
-    while (registrationsLeft) {
-        service_registration_pt reg = arrayList_get(registrations, 0);
-
-        serviceRegistry_logWarningServiceRegistration(registry, reg);
-
-        if (serviceRegistration_isValid(reg)) {
-            serviceRegistration_unregister(reg);
-        }
-        else {
-            arrayList_remove(registrations, 0);
-        }
-
-        // not removed by last unregister call?
-        celixThreadRwlock_writeLock(&registry->lock);
-        registrations = hashMap_get(registry->serviceRegistrations, bundle);
-        registrationsLeft = (registrations != NULL);
-        if (registrationsLeft) {
-            registrationsLeft = (arrayList_size(registrations) > 0);
-        }
-        celixThreadRwlock_unlock(&registry->lock);
-    }
-
-    return status;
-}
-
-static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry __attribute__((unused)), service_registration_pt reg) {
-    const char *servName = NULL;
-    serviceRegistration_getServiceName(reg, &servName);
-    fw_log(registry->framework->logger, CELIX_LOG_LEVEL_WARNING, "Dangling service registration for service %s. Look for missing bundleContext_unregisterService/serviceRegistration_unregister calls.", servName);
-}
-
 celix_status_t serviceRegistry_getServiceReference(service_registry_pt registry, bundle_pt owner,
                                                    service_registration_pt registration, service_reference_pt *out) {
 	celix_status_t status = CELIX_SUCCESS;
@@ -378,7 +316,6 @@
         }
         if (status == CELIX_SUCCESS) {
             hashMap_put(references, (void*)registration->serviceId, ref);
-            hashMap_put(registry->deletedServiceReferences, ref, (void *)false);
         }
     } else {
         serviceReference_retain(ref);
@@ -479,21 +416,15 @@
 
 celix_status_t serviceRegistry_retainServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference) {
     celix_status_t status = CELIX_SUCCESS;
-    reference_status_t refStatus;
     bundle_pt refBundle = NULL;
     
     celixThreadRwlock_writeLock(&registry->lock);
-    serviceRegistry_checkReference(registry, reference, &refStatus);
-    if (refStatus == REF_ACTIVE) {
-        serviceReference_getOwner(reference, &refBundle);
-        if (refBundle == bundle) {
-            serviceReference_retain(reference);
-        } else {
-            status = CELIX_ILLEGAL_ARGUMENT;
-            fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, "cannot retain a service reference from an other bundle (in ref %p) (provided %p).", refBundle, bundle);
-        }
+    serviceReference_getOwner(reference, &refBundle);
+    if (refBundle == bundle) {
+        serviceReference_retain(reference);
     } else {
-        serviceRegistry_logIllegalReference(registry, reference, refStatus);
+        status = CELIX_ILLEGAL_ARGUMENT;
+        fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, "cannot retain a service reference from an other bundle (in ref %p) (provided %p).", refBundle, bundle);
     }
     celixThreadRwlock_unlock(&registry->lock);
 
@@ -505,97 +436,54 @@
     celix_status_t status = CELIX_SUCCESS;
     bool destroyed = false;
     size_t count = 0;
-    reference_status_t refStatus;
 
     celixThreadRwlock_writeLock(&registry->lock);
-    serviceRegistry_checkReference(registry, reference, &refStatus);
-    if (refStatus == REF_ACTIVE) {
-        serviceReference_getUsageCount(reference, &count);
-        serviceReference_release(reference, &destroyed);
-        if (destroyed) {
+    serviceReference_getUsageCount(reference, &count);
+    serviceReference_release(reference, &destroyed);
+    if (destroyed) {
 
-            if (count > 0) {
-                serviceRegistry_logWarningServiceReferenceUsageCount(registry, bundle, reference, count, 0);
-            }
+        if (count > 0) {
+            serviceRegistry_logWarningServiceReferenceUsageCount(registry, bundle, reference, count, 0);
+        }
 
-            hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
+        hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
 
-            unsigned long refId = 0UL;
-            service_reference_pt ref = NULL;
+        unsigned long refId = 0UL;
+        service_reference_pt ref = NULL;
 
-            if (refsMap != NULL) {
-                hash_map_iterator_t iter = hashMapIterator_construct(refsMap);
-                while (hashMapIterator_hasNext(&iter)) {
-                    hash_map_entry_pt entry = hashMapIterator_nextEntry(&iter);
-                    refId = (unsigned long) hashMapEntry_getKey(entry); //note could be invalid e.g. freed
-                    ref = hashMapEntry_getValue(entry);
+        if (refsMap != NULL) {
+            hash_map_iterator_t iter = hashMapIterator_construct(refsMap);
+            while (hashMapIterator_hasNext(&iter)) {
+                hash_map_entry_pt entry = hashMapIterator_nextEntry(&iter);
+                refId = (unsigned long) hashMapEntry_getKey(entry); //note could be invalid e.g. freed
+                ref = hashMapEntry_getValue(entry);
 
-                    if (ref == reference) {
-                        break;
-                    } else {
-                        ref = NULL;
-                        refId = 0UL;
-                    }
+                if (ref == reference) {
+                    break;
+                } else {
+                    ref = NULL;
+                    refId = 0UL;
                 }
             }
-
-            if (ref != NULL) {
-                hashMap_remove(refsMap, (void*)refId);
-                int size = hashMap_size(refsMap);
-                if (size == 0) {
-                    hashMap_destroy(refsMap, false, false);
-                    hashMap_remove(registry->serviceReferences, bundle);
-                }
-                serviceRegistry_setReferenceStatus(registry, reference, true);
-            } else {
-                fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot find reference %p in serviceReferences map",
-                       reference);
-            }
         }
-    } else {
-        serviceRegistry_logIllegalReference(registry, reference, refStatus);
+
+        if (ref != NULL) {
+            hashMap_remove(refsMap, (void*)refId);
+            int size = hashMap_size(refsMap);
+            if (size == 0) {
+                hashMap_destroy(refsMap, false, false);
+                hashMap_remove(registry->serviceReferences, bundle);
+            }
+        } else {
+            fw_log(registry->framework->logger, CELIX_LOG_LEVEL_FATAL, "Cannot find reference %p in serviceReferences map",
+                   reference);
+        }
     }
     celixThreadRwlock_unlock(&registry->lock);
 
     return status;
 }
 
-static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt registry, service_reference_pt reference,
-                                                  bool deleted) {
-    //precondition write locked on registry->lock
-    if (registry->checkDeletedReferences) {
-        hashMap_put(registry->deletedServiceReferences, reference, (void *) deleted);
-    }
-    return CELIX_SUCCESS;
-}
-
-static void serviceRegistry_logIllegalReference(service_registry_pt registry __attribute__((unused)), service_reference_pt reference,
-                                                   reference_status_t refStatus) {
-    fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR,
-           "Error handling service reference %p, status is %i",reference, refStatus);
-}
-
-static celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt ref,
-                                              reference_status_t *out) {
-    //precondition read or write locked on registry->lock
-    celix_status_t status = CELIX_SUCCESS;
-
-    if (registry->checkDeletedReferences) {
-        reference_status_t refStatus = REF_UNKNOWN;
-
-        if (hashMap_containsKey(registry->deletedServiceReferences, ref)) {
-            bool deleted = (bool) hashMap_get(registry->deletedServiceReferences, ref);
-            refStatus = deleted ? REF_DELETED : REF_ACTIVE;
-        }
-
-        *out = refStatus;
-    } else {
-        *out = REF_ACTIVE;
-    }
-
-    return status;
-}
-
 static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry __attribute__((unused)), bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount) {
     if (usageCount > 0) {
         fw_log(registry->framework->logger, CELIX_LOG_LEVEL_WARNING, "Service Reference destroyed with usage count is %zu, expected 0. Look for missing bundleContext_ungetService calls.", usageCount);
@@ -651,8 +539,6 @@
             while (!destroyed) {
                 serviceReference_release(ref, &destroyed);
             }
-            serviceRegistry_setReferenceStatus(registry, ref, true);
-
         }
         hashMapIterator_destroy(iter);
         hashMap_destroy(refsMap, false, false);
@@ -697,78 +583,53 @@
     size_t count = 0;
     const void *service = NULL;
     bool valid = false;
-    reference_status_t refStatus;
 
 
     celixThreadRwlock_readLock(&registry->lock);
-    serviceRegistry_checkReference(registry, reference, &refStatus);
-    if (refStatus == REF_ACTIVE) {
-        serviceReference_getServiceRegistration(reference, &registration);
-        valid = serviceRegistration_isValid(registration);
-        if (valid) {
-            serviceRegistration_retain(registration);
-            serviceReference_increaseUsage(reference, &count);
-        } else {
-            *out = NULL; //invalid service registration
-        }
+    serviceReference_getServiceRegistration(reference, &registration);
+    valid = serviceRegistration_isValid(registration);
+    if (valid) {
+        serviceRegistration_retain(registration);
+        serviceReference_increaseUsage(reference, &count);
+    } else {
+        *out = NULL; //invalid service registration
     }
     celixThreadRwlock_unlock(&registry->lock);
 
-    if (valid && refStatus == REF_ACTIVE) {
-        if (count == 1) {
-            serviceRegistration_getService(registration, bundle, &service);
-            serviceReference_setService(reference, service);
-        }
-        serviceRegistration_release(registration);
-
-        /* NOTE the out argument of sr_getService should be 'const void**'
-           To ensure backwards compatibility a cast is made instead.
-        */
-        serviceReference_getService(reference, (void **)out);
-    } else {
-        if (refStatus != REF_ACTIVE) {
-            serviceRegistry_logIllegalReference(registry, reference, refStatus);
-        }
-        status = CELIX_BUNDLE_EXCEPTION;
+    if (count == 1) {
+        serviceRegistration_getService(registration, bundle, &service);
+        serviceReference_setService(reference, service);
     }
+    serviceRegistration_release(registration);
+
+    /* NOTE the out argument of sr_getService should be 'const void**'
+       To ensure backwards compatibility a cast is made instead.
+    */
+    serviceReference_getService(reference, (void **)out);
 
 	return status;
 }
 
 celix_status_t serviceRegistry_ungetService(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference, bool *result) {
-	celix_status_t status = CELIX_SUCCESS;
     service_registration_pt reg = NULL;
     const void *service = NULL;
     size_t count = 0;
-    celix_status_t subStatus = CELIX_SUCCESS;
-    reference_status_t refStatus;
 
     celixThreadRwlock_readLock(&registry->lock);
-    serviceRegistry_checkReference(registry, reference, &refStatus);
     celixThreadRwlock_unlock(&registry->lock);
 
-    if (refStatus == REF_ACTIVE) {
-        subStatus = serviceReference_decreaseUsage(reference, &count);
-        if (count == 0) {
-            /*NOTE the argument service of sr_getService should be 'const void**'
-              To ensure backwards compatibility a cast is made instead.
-              */
-            serviceReference_getService(reference, (void**)&service);
-            serviceReference_getServiceRegistration(reference, &reg);
-            if (reg != NULL) {
-                serviceRegistration_ungetService(reg, bundle, &service);
-            }
+    celix_status_t status = serviceReference_decreaseUsage(reference, &count);
+    if (count == 0) {
+        /*NOTE the argument service of sr_getService should be 'const void**'
+          To ensure backwards compatibility a cast is made instead.
+          */
+        serviceReference_getService(reference, (void**)&service);
+        serviceReference_getServiceRegistration(reference, &reg);
+        if (reg != NULL) {
+            serviceRegistration_ungetService(reg, bundle, &service);
         }
-    } else {
-        serviceRegistry_logIllegalReference(registry, reference, refStatus);
-        status = CELIX_BUNDLE_EXCEPTION;
     }
 
-    if (result) {
-        *result = (subStatus == CELIX_SUCCESS);
-    }
-
-
 	return status;
 }
 
@@ -804,6 +665,7 @@
             celix_increaseCountServiceListener(listenerEntry);
             celix_arrayList_add(listeners, listenerEntry);
 		}
+		celixThreadRwlock_unlock(&registry->lock);
 	}
 
 	if (infos != NULL && listeners != NULL) {
@@ -963,8 +825,21 @@
         const char *serviceName,
         celix_service_factory_t *factory,
         celix_properties_t* props,
+        long reserveId,
         service_registration_t **registration) {
-    return serviceRegistry_registerServiceInternal(reg, (celix_bundle_t*)bnd, serviceName, (const void *) factory, props, CELIX_FACTORY_SERVICE, registration);
+    return serviceRegistry_registerServiceInternal(reg, (celix_bundle_t*)bnd, serviceName, (const void *) factory, props, reserveId, CELIX_FACTORY_SERVICE, registration);
+}
+
+celix_status_t
+celix_serviceRegistry_registerService(
+        celix_service_registry_t *reg,
+        const celix_bundle_t *bnd,
+        const char *serviceName,
+        void* service,
+        celix_properties_t* props,
+        long reserveId,
+        service_registration_t **registration) {
+    return serviceRegistry_registerServiceInternal(reg, (celix_bundle_t*)bnd, serviceName, (const void *) service, props, reserveId, CELIX_PLAIN_SERVICE, registration);
 }
 
 static celix_service_registry_listener_hook_entry_t* celix_createHookEntry(long svcId, celix_listener_hook_service_t *hook) {
@@ -1046,6 +921,128 @@
     free(entry);
 }
 
+char* celix_serviceRegistry_createFilterFor(celix_service_registry_t* registry, const char* serviceName, const char* versionRangeStr, const char* additionalFilterIn, const char* lang, bool ignoreServiceLanguage) {
+    char* filter = NULL;
+
+    //setting lang
+    if (lang == NULL || strncmp("", lang, 1) == 0) {
+        lang = CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
+    }
+
+    if (serviceName == NULL) {
+        serviceName = "*";
+    }
+
+    char* versionRange = NULL;
+    if (versionRangeStr != NULL) {
+        version_range_pt range;
+        celix_status_t status = versionRange_parse(versionRangeStr, &range);
+        if(status != CELIX_SUCCESS) {
+            framework_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                          "Error incorrect version range.");
+            return NULL;
+        }
+        versionRange = versionRange_createLDAPFilter(range, CELIX_FRAMEWORK_SERVICE_VERSION);
+        versionRange_destroy(range);
+        if (versionRange == NULL) {
+            framework_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                          "Error creating LDAP filter.");
+            return NULL;
+        }
+    }
+
+    //setting filter
+    if (ignoreServiceLanguage) {
+        if (additionalFilterIn != NULL && versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange, additionalFilterIn);
+        } else if (versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange);
+        } else if (additionalFilterIn != NULL) {
+            asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, additionalFilterIn);
+        } else {
+            asprintf(&filter, "(&(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName);
+        }
+    } else {
+        if (additionalFilterIn != NULL && versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange, additionalFilterIn);
+        } else if (versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange);
+        } else if (additionalFilterIn != NULL) {
+            asprintf(&filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, additionalFilterIn);
+        } else {
+            asprintf(&filter, "(&(%s=%s)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
+        }
+    }
+
+    if (versionRange != NULL){
+        free(versionRange);
+    }
+
+    return filter;
+}
+
+static int celix_serviceRegistry_compareRegistrations(const void *a, const void *b) {
+    const service_registration_t* regA = a;
+    const service_registration_t* regB = b;
+
+    celix_properties_t* propsA = NULL;
+    celix_properties_t* propsB = NULL;
+    serviceRegistration_getProperties((service_registration_t*)regA, &propsA);
+    serviceRegistration_getProperties((service_registration_t*)regB, &propsB);
+
+    long servIdA = celix_properties_getAsLong(propsA, OSGI_FRAMEWORK_SERVICE_ID, 0);
+    long servIdB = celix_properties_getAsLong(propsB, OSGI_FRAMEWORK_SERVICE_ID, 0);
+
+    long servRankingA = celix_properties_getAsLong(propsA, OSGI_FRAMEWORK_SERVICE_RANKING, 0);
+    long servRankingB = celix_properties_getAsLong(propsB, OSGI_FRAMEWORK_SERVICE_RANKING, 0);
+
+    return utils_compareServiceIdsAndRanking(servIdA, servRankingA, servIdB, servRankingB);
+}
+
+celix_array_list_t* celix_serviceRegisrty_findServices(
+        celix_service_registry_t* registry,
+        const char* filterStr) {
+
+    celix_filter_t* filter = celix_filter_create(filterStr);
+    if (filter == NULL) {
+        framework_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                      "Error incorrect filter.");
+        return NULL;
+    }
+
+    celix_array_list_t *result = celix_arrayList_create();
+    celix_array_list_t* matchedRegistrations = celix_arrayList_create();
+
+    celixThreadRwlock_readLock(&registry->lock);
+
+    hash_map_iterator_t iter = hashMapIterator_construct(registry->serviceRegistrations);
+    while (hashMapIterator_hasNext(&iter)) {
+        celix_array_list_t *regs = hashMapIterator_nextValue(&iter);
+        for (int i = 0; i < celix_arrayList_size(regs); ++i) {
+            service_registration_t *reg = celix_arrayList_get(regs, i);
+            celix_properties_t* svcProps = NULL;
+            serviceRegistration_getProperties(reg, &svcProps);
+            if (svcProps != NULL && celix_filter_match(filter, svcProps)) {
+                celix_arrayList_add(matchedRegistrations, reg);
+            }
+        }
+    }
+
+    //sort matched registration and add the svc id to the result list.
+    if (celix_arrayList_size(matchedRegistrations) > 1) {
+        celix_arrayList_sort(matchedRegistrations, celix_serviceRegistry_compareRegistrations);
+    }
+    for (int i = 0; i < celix_arrayList_size(matchedRegistrations); ++i) {
+        service_registration_t* reg = celix_arrayList_get(matchedRegistrations, i);
+        celix_arrayList_addLong(result, serviceRegistration_getServiceId(reg));
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    celix_filter_destroy(filter);
+    celix_arrayList_destroy(matchedRegistrations);
+    return result;
+}
+
 
 celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId) {
     celix_array_list_t *result = celix_arrayList_create();
@@ -1121,7 +1118,7 @@
     celixThreadMutex_create(&entry->mutex, NULL);
     celixThreadCondition_init(&entry->cond, NULL);
 
-    celix_array_list_t *registrations =  celix_arrayList_create();
+    celix_array_list_t *references =  celix_arrayList_create();
 
     celixThreadRwlock_writeLock(&registry->lock);
     celix_arrayList_add(registry->serviceListeners, entry); //use count 1
@@ -1137,7 +1134,9 @@
             if (celix_filter_match(filter, props)) {
                 serviceRegistration_retain(registration);
                 long svcId = serviceRegistration_getServiceId(registration);
-                celix_arrayList_add(registrations, registration);
+                service_reference_pt ref = NULL;
+                serviceRegistry_getServiceReference_internal(registry, bundle, registration, &ref);
+                celix_arrayList_add(references, ref);
                 //update pending register event count
                 celix_increasePendingRegisteredEvent(registry, svcId);
             }
@@ -1150,24 +1149,23 @@
     //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;
-        celixThreadRwlock_writeLock(&registry->lock);
-        serviceRegistry_getServiceReference_internal(registry, bundle, reg, &ref);
-        celixThreadRwlock_unlock(&registry->lock);
+    for (int i = 0; i < celix_arrayList_size(references); ++i) {
+        service_reference_pt ref = celix_arrayList_get(references, i);
+        long svcId = serviceReference_getServiceId(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);
+
+        service_registration_t* reg = NULL;
+        serviceReference_getServiceRegistration(ref, &reg);
         serviceRegistration_release(reg);
 
         //update pending register event count
         celix_decreasePendingRegisteredEvent(registry, svcId);
     }
-    celix_arrayList_destroy(registrations);
+    celix_arrayList_destroy(references);
 
     serviceRegistry_callHooksForListenerFilter(registry, bundle, entry->filter, false);
 
@@ -1288,6 +1286,46 @@
 }
 
 long celix_serviceRegistry_nextSvcId(celix_service_registry_t* registry) {
-    long scvId = __atomic_fetch_add(&registry->nextServiceId, 1, __ATOMIC_SEQ_CST);
+    long scvId = __atomic_fetch_add(&registry->nextServiceId, 1, __ATOMIC_RELAXED);
     return scvId;
+}
+
+bool celix_serviceRegistry_isServiceRegistered(celix_service_registry_t* reg, long serviceId) {
+    bool isRegistered = false;
+    if (serviceId >= 0) {
+        celixThreadRwlock_readLock(&reg->lock);
+        hash_map_iterator_t iter = hashMapIterator_construct(reg->serviceRegistrations);
+        while (!isRegistered && hashMapIterator_hasNext(&iter)) {
+            celix_array_list_t *regs = hashMapIterator_nextValue(&iter);
+            for (int i = 0; i < celix_arrayList_size(regs); ++i) {
+                service_registration_t* r = celix_arrayList_get(regs, i);
+                if (serviceId == serviceRegistration_getServiceId(r)) {
+                    isRegistered = true;
+                    break;
+                }
+            }
+        }
+        celixThreadRwlock_unlock(&reg->lock);
+    }
+    return isRegistered;
+}
+
+void celix_serviceRegistry_unregisterService(celix_service_registry_t* registry, celix_bundle_t* bnd, long serviceId) {
+    service_registration_t *reg = NULL;
+    celixThreadRwlock_readLock(&registry->lock);
+    celix_array_list_t* registrations = hashMap_get(registry->serviceRegistrations, (void*)bnd);
+    for (int i = 0; i < celix_arrayList_size(registrations); ++i) {
+        service_registration_t *entry = celix_arrayList_get(registrations, i);
+        if (serviceRegistration_getServiceId(entry) == serviceId) {
+            reg = entry;
+            break;
+        }
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    if (reg != NULL) {
+        serviceRegistration_unregister(reg);
+    } else {
+        fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot unregister service for service id %li. This id is not present or owned by the provided bundle (bnd id %li)", serviceId, celix_bundle_getId(bnd));
+    }
 }
\ 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 fb8e37f..f181731 100644
--- a/libs/framework/src/service_registry_private.h
+++ b/libs/framework/src/service_registry_private.h
@@ -32,6 +32,27 @@
 #include "listener_hook_service.h"
 #include "service_reference.h"
 
+#define CELIX_SERVICE_REGISTRY_STATIC_EVENT_QUEUE_SIZE  64
+
+typedef struct celix_service_registry_event {
+    //TODO call from framework to ensure bundle entries usage count is increased
+    bool isRegistrationEvent;
+
+    //for register event
+    long serviceId;
+    char *serviceName;
+    void *svc;
+    celix_service_factory_t* factory;
+    celix_properties_t* properties;
+    void* registerData;
+    void (*registerCallback)(void *data, service_registration_t*);
+
+    //for unregister event
+    service_registration_t* registration;
+    void* unregisterData;
+    void (*unregisterCallback)(void *data);
+} celix_service_registry_event_t;
+
 struct celix_serviceRegistry {
 	framework_pt framework;
 	registry_callback_t callback;
@@ -41,9 +62,6 @@
 	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_t *deletedServiceReferences; //key = ref pointer, value = bool
-
 	long nextServiceId;
 
 	celix_array_list_t *listenerHooks; //celix_service_registry_listener_hook_entry_t*
@@ -82,12 +100,6 @@
     unsigned int useCount;
 } celix_service_registry_service_listener_entry_t;
 
-typedef enum reference_status_enum {
-	REF_ACTIVE,
-	REF_DELETED,
-	REF_UNKNOWN
-} reference_status_t;
-
 struct usageCount {
 	unsigned int count;
 	service_reference_pt reference;
diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c
index 53fd31a..4a47397 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -34,19 +34,14 @@
 #include "bundle_context_private.h"
 #include "celix_array_list.h"
 
-static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *tracker, service_reference_pt reference, celix_service_event_t *event);
-static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t *tracker, service_reference_pt reference, celix_service_event_t *event);
-static void serviceTracker_untrackTracked(celix_service_tracker_instance_t *tracker, celix_tracked_entry_t *tracked);
-static celix_status_t serviceTracker_invokeAddingService(celix_service_tracker_instance_t *tracker, service_reference_pt ref, void **svcOut);
-static celix_status_t serviceTracker_invokeAddService(celix_service_tracker_instance_t *tracker, celix_tracked_entry_t *tracked);
-static celix_status_t serviceTracker_invokeRemovingService(celix_service_tracker_instance_t *tracker, celix_tracked_entry_t *tracked);
+static celix_status_t serviceTracker_track(service_tracker_t *tracker, service_reference_pt reference, celix_service_event_t *event);
+static celix_status_t serviceTracker_untrack(service_tracker_t *tracker, service_reference_pt reference);
+static void serviceTracker_untrackTracked(service_tracker_t *tracker, celix_tracked_entry_t *tracked);
+static celix_status_t serviceTracker_invokeAddingService(service_tracker_t *tracker, service_reference_pt ref, void **svcOut);
+static celix_status_t serviceTracker_invokeAddService(service_tracker_t *tracker, celix_tracked_entry_t *tracked);
+static celix_status_t serviceTracker_invokeRemovingService(service_tracker_t *tracker, celix_tracked_entry_t *tracked);
 static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestSvc, const properties_t *props, const bundle_t *bnd);
-static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracker_instance_t *instance,
-                                                            const char *serviceName /*sanity*/,
-                                                            void *callbackHandle,
-                                                            void (*use)(void *handle, void *svc),
-                                                            void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props),
-                                                            void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner));
+
 
 #ifdef CELIX_SERVICE_TRACKER_USE_SHUTDOWN_THREAD
 static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance);
@@ -56,18 +51,6 @@
 
 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
-
-
-static celix_thread_mutex_t g_shutdownMutex;
-static celix_thread_cond_t g_shutdownCond;
-static celix_array_list_t *g_shutdownInstances = NULL; //value = celix_service_tracker_instance -> used for syncing with shutdown threads
-
-
-static void serviceTracker_once(void) {
-    celixThreadMutex_create(&g_shutdownMutex, NULL);
-    celixThreadCondition_init(&g_shutdownCond, NULL);
-}
 
 static inline celix_tracked_entry_t* tracked_create(service_reference_pt ref, void *svc, celix_properties_t *props, celix_bundle_t *bnd) {
     celix_tracked_entry_t *tracked = calloc(1, sizeof(*tracked));
@@ -128,332 +111,272 @@
 	return status;
 }
 
-celix_status_t serviceTracker_createWithFilter(bundle_context_pt context, const char * filter, service_tracker_customizer_pt customizer, service_tracker_pt *tracker) {
-	celix_status_t status = CELIX_SUCCESS;
-	*tracker = (service_tracker_pt) calloc(1, sizeof(**tracker));
-	if (!*tracker) {
-		status = CELIX_ENOMEM;
-	} else {
-		(*tracker)->context = context;
-		(*tracker)->filter = strdup(filter);
-        (*tracker)->customizer = customizer;
-	}
+celix_status_t serviceTracker_createWithFilter(bundle_context_pt context, const char * filter, service_tracker_customizer_pt customizer, service_tracker_pt *out) {
+	service_tracker_t* tracker = calloc(1, sizeof(*tracker));
+	*out = tracker;
+    tracker->context = context;
+    tracker->filter = celix_utils_strdup(filter);
+    tracker->customizer = *customizer;
+    free(customizer);
 
-	framework_logIfError(celix_frameworkLogger_globalLogger(), status, NULL, "Cannot create service tracker [filter=%s]", filter);
+    celixThreadMutex_create(&tracker->closeSync.mutex, NULL);
+    celixThreadCondition_init(&tracker->closeSync.cond, NULL);
 
-	return status;
+    celixThreadMutex_create(&tracker->mutex, NULL);
+    celixThreadCondition_init(&tracker->cond, NULL);
+    tracker->trackedServices = celix_arrayList_create();
+    tracker->untrackingServices = celix_arrayList_create();
+
+    celixThreadMutex_create(&tracker->mutex, NULL);
+    tracker->currentHighestServiceId = -1;
+
+    tracker->listener.handle = tracker;
+    tracker->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
+
+    tracker->callbackHandle = tracker->callbackHandle;
+
+    tracker->add = tracker->add;
+    tracker->addWithProperties = tracker->addWithProperties;
+    tracker->addWithOwner = tracker->addWithOwner;
+    tracker->set = tracker->set;
+    tracker->setWithProperties = tracker->setWithProperties;
+    tracker->setWithOwner = tracker->setWithOwner;
+    tracker->remove = tracker->remove;
+    tracker->removeWithProperties = tracker->removeWithProperties;
+    tracker->removeWithOwner = tracker->removeWithOwner;
+
+	return CELIX_SUCCESS;
 }
 
 celix_status_t serviceTracker_destroy(service_tracker_pt tracker) {
-    if (tracker->customizer != NULL) {
-	    serviceTrackerCustomizer_destroy(tracker->customizer);
-	}
-
     free(tracker->serviceName);
 	free(tracker->filter);
-	free(tracker);
-
+    celixThreadMutex_destroy(&tracker->closeSync.mutex);
+    celixThreadCondition_destroy(&tracker->closeSync.cond);
+    celixThreadMutex_destroy(&tracker->mutex);
+    celixThreadCondition_destroy(&tracker->cond);
+    celix_arrayList_destroy(tracker->trackedServices);
+    celix_arrayList_destroy(tracker->untrackingServices);
+    free(tracker);
 	return CELIX_SUCCESS;
 }
 
 celix_status_t serviceTracker_open(service_tracker_pt tracker) {
-    celix_service_listener_t *listener = NULL;
-    celix_service_tracker_instance_t *instance = NULL;
-    celix_status_t status = CELIX_SUCCESS;
+    celixThreadMutex_lock(&tracker->mutex);
+    bool alreadyOpen = tracker->open;
+    tracker->open = true;
+    celixThreadMutex_unlock(&tracker->mutex);
 
-    bool addListener = false;
-
-    celixThreadRwlock_writeLock(&tracker->instanceLock);
-    if (tracker->instance == NULL) {
-        instance = calloc(1, sizeof(*instance));
-        instance->context = tracker->context;
-
-        instance->closing = false;
-        instance->activeServiceChangeCalls = 0;
-        celixThreadMutex_create(&instance->closingLock, NULL);
-        celixThreadCondition_init(&instance->activeServiceChangeCallsCond, NULL);
-
-
-        celixThreadRwlock_create(&instance->lock, NULL);
-        instance->trackedServices = celix_arrayList_create();
-
-        celixThreadMutex_create(&instance->mutex, NULL);
-        instance->currentHighestServiceId = -1;
-
-        instance->listener.handle = instance;
-        instance->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
-        listener = &instance->listener;
-
-        instance->callbackHandle = tracker->callbackHandle;
-        instance->filter = strdup(tracker->filter);
-        if (tracker->customizer != NULL) {
-            memcpy(&instance->customizer, tracker->customizer, sizeof(instance->customizer));
-        }
-        instance->add = tracker->add;
-        instance->addWithProperties = tracker->addWithProperties;
-        instance->addWithOwner = tracker->addWithOwner;
-        instance->set = tracker->set;
-        instance->setWithProperties = tracker->setWithProperties;
-        instance->setWithOwner = tracker->setWithOwner;
-        instance->remove = tracker->remove;
-        instance->removeWithProperties = tracker->removeWithProperties;
-        instance->removeWithOwner = tracker->removeWithOwner;
-
-        tracker->instance = instance;
-
-        addListener = true;
-    } else {
-        //already open
-        framework_logIfError(tracker->context->framework->logger, status, NULL, "Tracker already open");
-
+    if (!alreadyOpen) {
+        bundleContext_addServiceListener(tracker->context, &tracker->listener, tracker->filter);
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
-
-	if (addListener) {
-	    bundleContext_addServiceListener(tracker->context, listener, tracker->filter);
-	}
 	return CELIX_SUCCESS;
 }
 
-celix_status_t serviceTracker_close(service_tracker_pt tracker) {
+celix_status_t serviceTracker_close(service_tracker_t* tracker) {
 	//put all tracked entries in tmp array list, so that the untrack (etc) calls are not blocked.
     //set state to close to prevent service listener events
 
-    celixThreadRwlock_writeLock(&tracker->instanceLock);
-    celix_service_tracker_instance_t *instance = tracker->instance;
-    tracker->instance = NULL;
-    if (instance != NULL) {
-        celixThreadMutex_lock(&instance->closingLock);
-        //prevent service listener events
-        instance->closing = true;
-        celixThreadMutex_unlock(&instance->closingLock);
+    celixThreadMutex_lock(&tracker->mutex);
+    bool open = tracker->open;
+    tracker->open = false;
+    celixThreadMutex_unlock(&tracker->mutex);
+
+    if (!open) {
+        return CELIX_SUCCESS;
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
 
-    if (instance != NULL) {
-        celixThreadRwlock_writeLock(&instance->lock);
-        unsigned int size = celix_arrayList_size(instance->trackedServices);
-        if(size > 0) {
-            celix_tracked_entry_t *trackedEntries[size];
-            for (unsigned int i = 0u; i < size; 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 (unsigned int i = 0u; i < size; i++) {
-                serviceTracker_untrackTracked(instance, trackedEntries[i]);
+    //indicate that the service tracking is closing and wait for the still pending service registration events.
+    celixThreadMutex_lock(&tracker->closeSync.mutex);
+    tracker->closeSync.closing = true;
+    while (tracker->closeSync.activeCalls > 0) {
+        celixThreadCondition_wait(&tracker->closeSync.cond, &tracker->closeSync.mutex);
+    }
+    celixThreadMutex_unlock(&tracker->closeSync.mutex);
+
+    int nrOfTrackedEntries;
+    do {
+        celixThreadMutex_lock(&tracker->mutex);
+        celix_tracked_entry_t* tracked = NULL;
+        nrOfTrackedEntries = celix_arrayList_size(tracker->trackedServices);
+        if (nrOfTrackedEntries > 0) {
+            tracked = celix_arrayList_get(tracker->trackedServices, 0);
+            celix_arrayList_removeAt(tracker->trackedServices, 0);
+            celix_arrayList_add(tracker->untrackingServices, tracked);
+        }
+        celixThreadMutex_unlock(&tracker->mutex);
+
+        if (tracked != NULL) {
+            int currentSize = nrOfTrackedEntries - 1;
+            if (currentSize == 0) {
+                serviceTracker_checkAndInvokeSetService(tracker, NULL, NULL, NULL);
+            } else {
+                celix_serviceTracker_useHighestRankingService(tracker, tracked->serviceName, tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
             }
-        } else {
-            celixThreadRwlock_unlock(&instance->lock);
+
+            serviceTracker_untrackTracked(tracker, tracked);
+            celixThreadMutex_lock(&tracker->mutex);
+            celix_arrayList_remove(tracker->untrackingServices, tracked);
+            celixThreadCondition_broadcast(&tracker->cond);
+            celixThreadMutex_unlock(&tracker->mutex);
         }
 
-        celixThreadMutex_lock(&instance->closingLock);
-        while (instance->activeServiceChangeCalls > 0) {
-            celixThreadCondition_wait(&instance->activeServiceChangeCallsCond, &instance->closingLock);
-        }
-        celixThreadMutex_unlock(&instance->closingLock);
+
+        celixThreadMutex_lock(&tracker->mutex);
+        nrOfTrackedEntries = celix_arrayList_size(tracker->trackedServices);
+        celixThreadMutex_unlock(&tracker->mutex);
+    } while (nrOfTrackedEntries > 0);
 
 
-#ifdef CELIX_SERVICE_TRACKER_USE_SHUTDOWN_THREAD
-        //NOTE Separate thread is needed to prevent deadlock where closing is triggered from a serviceChange event and the
-        // untrack -> removeServiceListener will try to remove a service listener which is being invoked and is the
-        // actual thread calling the removeServiceListener.
-        //
-        // This can be detached -> because service listener events are ignored (closing=true) and so no callbacks
-        // are made back to the celix framework / tracker owner.
-        serviceTracker_addInstanceFromShutdownList(instance);
-        celix_thread_t localThread;
-        celixThread_create(&localThread, NULL, shutdownServiceTrackerInstanceHandler, instance);
-        celixThread_detach(localThread);
-#else
-        fw_removeServiceListener(instance->context->framework, instance->context->bundle, &instance->listener);
-
-        celixThreadMutex_destroy(&instance->closingLock);
-        celixThreadCondition_destroy(&instance->activeServiceChangeCallsCond);
-        celixThreadMutex_destroy(&instance->mutex);
-        celixThreadRwlock_destroy(&instance->lock);
-        celix_arrayList_destroy(instance->trackedServices);
-        free(instance->filter);
-        free(instance);
-#endif
-    }
+    fw_removeServiceListener(tracker->context->framework, tracker->context->bundle, &tracker->listener);
 
 	return CELIX_SUCCESS;
 }
 
-service_reference_pt serviceTracker_getServiceReference(service_tracker_pt tracker) {
+service_reference_pt serviceTracker_getServiceReference(service_tracker_t* tracker) {
     //TODO deprecated warning -> not locked
-	celix_tracked_entry_t *tracked;
-    service_reference_pt result = NULL;
-	unsigned int i;
 
-	celixThreadRwlock_readLock(&tracker->instanceLock);
-	celix_service_tracker_instance_t *instance = tracker->instance;
-	if (instance != NULL) {
-        celixThreadRwlock_readLock(&instance->lock);
-        for (i = 0; i < arrayList_size(instance->trackedServices); ++i) {
-            tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
-            result = tracked->reference;
-            break;
-        }
-        celixThreadRwlock_unlock(&instance->lock);
+    service_reference_pt result = NULL;
+
+    celixThreadMutex_lock(&tracker->mutex);
+    for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); ++i) {
+        celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+        result = tracked->reference;
+        break;
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    celixThreadMutex_unlock(&tracker->mutex);
 
 	return result;
 }
 
-array_list_pt serviceTracker_getServiceReferences(service_tracker_pt tracker) {
+array_list_pt serviceTracker_getServiceReferences(service_tracker_t* tracker) {
     //TODO deprecated warning -> not locked
-    celix_tracked_entry_t *tracked;
-	unsigned int i;
 	array_list_pt references = NULL;
 	arrayList_create(&references);
 
-    celixThreadRwlock_readLock(&tracker->instanceLock);
-	celix_service_tracker_instance_t *instance = tracker->instance;
-	if (instance != NULL) {
-        celixThreadRwlock_readLock(&instance->lock);
-        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
-            tracked = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
-            arrayList_add(references, tracked->reference);
-        }
-        celixThreadRwlock_unlock(&instance->lock);
+    celixThreadMutex_lock(&tracker->mutex);
+    for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+        celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+        arrayList_add(references, tracked->reference);
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    celixThreadMutex_unlock(&tracker->mutex);
 
 	return references;
 }
 
-void *serviceTracker_getService(service_tracker_pt tracker) {
+void *serviceTracker_getService(service_tracker_t* tracker) {
     //TODO deprecated warning -> not locked
-    celix_tracked_entry_t* tracked;
     void *service = NULL;
-	unsigned int i;
 
-	celixThreadRwlock_readLock(&tracker->instanceLock);
-	celix_service_tracker_instance_t *instance = tracker->instance;
-	if (instance != NULL) {
-        celixThreadRwlock_readLock(&instance->lock);
-        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
-            tracked = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
-            service = tracked->service;
-            break;
-        }
-        celixThreadRwlock_unlock(&instance->lock);
+    celixThreadMutex_lock(&tracker->mutex);
+    for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+        celix_tracked_entry_t* tracked = celix_arrayList_get(tracker->trackedServices, i);
+        service = tracked->service;
+        break;
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    celixThreadMutex_unlock(&tracker->mutex);
 
     return service;
 }
 
-array_list_pt serviceTracker_getServices(service_tracker_pt tracker) {
+array_list_pt serviceTracker_getServices(service_tracker_t* tracker) {
     //TODO deprecated warning -> not locked, also make locked variant
-    celix_tracked_entry_t *tracked;
-	unsigned int i;
 	array_list_pt references = NULL;
 	arrayList_create(&references);
 
-    celixThreadRwlock_readLock(&tracker->instanceLock);
-    celix_service_tracker_instance_t *instance = tracker->instance;
-    if (instance != NULL) {
-        celixThreadRwlock_readLock(&instance->lock);
-        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
-            tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
-            arrayList_add(references, tracked->service);
-        }
-        celixThreadRwlock_unlock(&instance->lock);
+    celixThreadMutex_lock(&tracker->mutex);
+    for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+        celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+        arrayList_add(references, tracked->service);
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    celixThreadMutex_unlock(&tracker->mutex);
 
     return references;
 }
 
 void *serviceTracker_getServiceByReference(service_tracker_pt tracker, service_reference_pt reference) {
     //TODO deprecated warning -> not locked
-    celix_tracked_entry_t *tracked;
     void *service = NULL;
-	unsigned int i;
 
-    celixThreadRwlock_readLock(&tracker->instanceLock);
-    celix_service_tracker_instance_t *instance = tracker->instance;
-    if (instance != NULL) {
-        celixThreadRwlock_readLock(&instance->lock);
-        for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
-            bool equals = false;
-            tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
-            serviceReference_equals(reference, tracked->reference, &equals);
-            if (equals) {
-                service = tracked->service;
-                break;
-            }
+    celixThreadMutex_lock(&tracker->mutex);
+    for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+        bool equals = false;
+        celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+        serviceReference_equals(reference, tracked->reference, &equals);
+        if (equals) {
+            service = tracked->service;
+            break;
         }
-        celixThreadRwlock_unlock(&instance->lock);
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    celixThreadMutex_unlock(&tracker->mutex);
 
 	return service;
 }
 
 static void serviceTracker_serviceChanged(void *handle, celix_service_event_t *event) {
-	celix_service_tracker_instance_t *instance = handle;
+    service_tracker_t *tracker = handle;
 
-    celixThreadMutex_lock(&instance->closingLock);
-    bool closing = instance->closing;
+    celixThreadMutex_lock(&tracker->closeSync.mutex);
+    bool closing = tracker->closeSync.closing;
     if (!closing) {
-        instance->activeServiceChangeCalls += 1;
+        tracker->closeSync.activeCalls += 1;
     }
-    celixThreadMutex_unlock(&instance->closingLock);
+    celixThreadMutex_unlock(&tracker->closeSync.mutex);
 
     if (!closing) {
         switch (event->type) {
             case OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED:
-                serviceTracker_track(instance, event->reference, event);
+                serviceTracker_track(tracker, event->reference, event);
                 break;
             case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED:
-                serviceTracker_track(instance, event->reference, event);
+                serviceTracker_track(tracker, event->reference, event);
                 break;
             case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING:
-                serviceTracker_untrack(instance, event->reference, event);
+                serviceTracker_untrack(tracker, event->reference);
                 break;
-            case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH:
-                //TODO
+            default:
+                //nop
                 break;
         }
-        celixThreadMutex_lock(&instance->closingLock);
-        assert(instance->activeServiceChangeCalls > 0);
-        instance->activeServiceChangeCalls -= 1;
-        if (instance->activeServiceChangeCalls == 0) {
-            celixThreadCondition_broadcast(&instance->activeServiceChangeCallsCond);
+    } else {
+        switch (event->type) {
+            case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING:
+                //untrack the service reference, because after this call the registration can be gone
+                serviceTracker_untrack(tracker, event->reference);
+                break;
+            default:
+                //nop
+                break;
         }
-        celixThreadMutex_unlock(&instance->closingLock);
+    }
+
+    if (!closing) {
+        celixThreadMutex_lock(&tracker->closeSync.mutex);
+        tracker->closeSync.activeCalls -= 1;
+        celixThreadCondition_broadcast(&tracker->closeSync.cond);
+        celixThreadMutex_unlock(&tracker->closeSync.mutex);
     }
 }
 
 size_t serviceTracker_nrOfTrackedServices(service_tracker_t *tracker) {
-    size_t result = 0;
-    celixThreadRwlock_readLock(&tracker->instanceLock);
-    celixThreadRwlock_readLock(&tracker->instance->lock);
-    result = (size_t) arrayList_size(tracker->instance->trackedServices);
-    celixThreadRwlock_unlock(&tracker->instance->lock);
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    celixThreadMutex_lock(&tracker->mutex);
+    size_t result = (size_t) arrayList_size(tracker->trackedServices);
+    celixThreadMutex_unlock(&tracker->mutex);
     return result;
 }
 
-static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *instance, service_reference_pt reference, celix_service_event_t *event) {
+static celix_status_t serviceTracker_track(service_tracker_t* tracker, service_reference_pt reference, celix_service_event_t *event) {
 	celix_status_t status = CELIX_SUCCESS;
 
     celix_tracked_entry_t *found = NULL;
-    unsigned int i;
-    
-    bundleContext_retainServiceReference(instance->context, reference);
 
-    celixThreadRwlock_readLock(&instance->lock);
-    for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+    bundleContext_retainServiceReference(tracker->context, reference);
+
+    celixThreadMutex_lock(&tracker->mutex);
+    for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
         bool equals = false;
-        celix_tracked_entry_t *visit = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
+        celix_tracked_entry_t *visit = (celix_tracked_entry_t*) arrayList_get(tracker->trackedServices, i);
         serviceReference_equals(reference, visit->reference, &equals);
         if (equals) {
             //NOTE it is possible to get two REGISTERED events, second one can be ignored.
@@ -461,12 +384,12 @@
             break;
         }
     }
-    celixThreadRwlock_unlock(&instance->lock);
+    celixThreadMutex_unlock(&tracker->mutex);
 
     if (found == NULL) {
         //NEW entry
         void *service = NULL;
-        status = serviceTracker_invokeAddingService(instance, reference, &service);
+        status = serviceTracker_invokeAddingService(tracker, reference, &service);
         if (status == CELIX_SUCCESS && service != NULL) {
             assert(reference != NULL);
 
@@ -482,22 +405,24 @@
 
             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);
+            celixThreadMutex_lock(&tracker->mutex);
+            arrayList_add(tracker->trackedServices, tracked);
+            celixThreadMutex_unlock(&tracker->mutex);
 
-            serviceTracker_invokeAddService(instance, tracked);
-            serviceTracker_useHighestRankingServiceInternal(instance, tracked->serviceName, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+            serviceTracker_invokeAddService(tracker, tracked);
+            celix_serviceTracker_useHighestRankingService(tracker, tracked->serviceName, tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
         }
+    } else {
+        bundleContext_ungetServiceReference(tracker->context, reference);
     }
 
-    framework_logIfError(instance->context->framework->logger, status, NULL, "Cannot track reference");
+    framework_logIfError(tracker->context->framework->logger, status, NULL, "Cannot track reference");
 
     return status;
 }
 
 static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestSvc, const celix_properties_t *props, const celix_bundle_t *bnd) {
-    celix_service_tracker_instance_t *instance = handle;
+    service_tracker_t *tracker = handle;
     bool update = false;
     long svcId = -1;
     if (highestSvc == NULL) {
@@ -507,117 +432,131 @@
         svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1);
     }
     if (svcId >= 0) {
-        celixThreadMutex_lock(&instance->mutex);
-        if (instance->currentHighestServiceId != svcId) {
-            instance->currentHighestServiceId = svcId;
+        celixThreadMutex_lock(&tracker->mutex);
+        if (tracker->currentHighestServiceId != svcId) {
+            tracker->currentHighestServiceId = svcId;
             update = true;
             //update
         }
-        celixThreadMutex_unlock(&instance->mutex);
+        celixThreadMutex_unlock(&tracker->mutex);
     }
     if (update) {
-        void *h = instance->callbackHandle;
-        if (instance->set != NULL) {
-            instance->set(h, highestSvc);
+        void *h = tracker->callbackHandle;
+        if (tracker->set != NULL) {
+            tracker->set(h, highestSvc);
         }
-        if (instance->setWithProperties != NULL) {
-            instance->setWithProperties(h, highestSvc, props);
+        if (tracker->setWithProperties != NULL) {
+            tracker->setWithProperties(h, highestSvc, props);
         }
-        if (instance->setWithOwner != NULL) {
-            instance->setWithOwner(h, highestSvc, props, bnd);
+        if (tracker->setWithOwner != NULL) {
+            tracker->setWithOwner(h, highestSvc, props, bnd);
         }
     }
 }
 
-static celix_status_t serviceTracker_invokeAddService(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
+static celix_status_t serviceTracker_invokeAddService(service_tracker_t *tracker, celix_tracked_entry_t *tracked) {
     celix_status_t status = CELIX_SUCCESS;
 
     void *customizerHandle = NULL;
     added_callback_pt function = NULL;
 
-    serviceTrackerCustomizer_getHandle(&instance->customizer, &customizerHandle);
-    serviceTrackerCustomizer_getAddedFunction(&instance->customizer, &function);
+    serviceTrackerCustomizer_getHandle(&tracker->customizer, &customizerHandle);
+    serviceTrackerCustomizer_getAddedFunction(&tracker->customizer, &function);
     if (function != NULL) {
         function(customizerHandle, tracked->reference, tracked->service);
     }
 
-    void *handle = instance->callbackHandle;
-    if (instance->add != NULL) {
-        instance->add(handle, tracked->service);
+    void *handle = tracker->callbackHandle;
+    if (tracker->add != NULL) {
+        tracker->add(handle, tracked->service);
     }
-    if (instance->addWithProperties != NULL) {
-        instance->addWithProperties(handle, tracked->service, tracked->properties);
+    if (tracker->addWithProperties != NULL) {
+        tracker->addWithProperties(handle, tracked->service, tracked->properties);
     }
-    if (instance->addWithOwner != NULL) {
-        instance->addWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
+    if (tracker->addWithOwner != NULL) {
+        tracker->addWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
     }
     return status;
 }
 
-static celix_status_t serviceTracker_invokeAddingService(celix_service_tracker_instance_t *instance, service_reference_pt ref, void **svcOut) {
+static celix_status_t serviceTracker_invokeAddingService(service_tracker_t *tracker, service_reference_pt ref, void **svcOut) {
 	celix_status_t status = CELIX_SUCCESS;
 
     void *handle = NULL;
     adding_callback_pt function = NULL;
 
-    status = serviceTrackerCustomizer_getHandle(&instance->customizer, &handle);
+    status = serviceTrackerCustomizer_getHandle(&tracker->customizer, &handle);
 
     if (status == CELIX_SUCCESS) {
-        status = serviceTrackerCustomizer_getAddingFunction(&instance->customizer, &function);
+        status = serviceTrackerCustomizer_getAddingFunction(&tracker->customizer, &function);
     }
 
     if (status == CELIX_SUCCESS && function != NULL) {
         status = function(handle, ref, svcOut);
     } else if (status == CELIX_SUCCESS) {
-        status = bundleContext_getService(instance->context, ref, svcOut);
+        status = bundleContext_getService(tracker->context, ref, svcOut);
     }
 
-    framework_logIfError(instance->context->framework->logger, status, NULL, "Cannot handle addingService");
+    framework_logIfError(tracker->context->framework->logger, status, NULL, "Cannot handle addingService");
 
     return status;
 }
 
-static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t* instance, service_reference_pt reference, celix_service_event_t *event) {
+static celix_status_t serviceTracker_untrack(service_tracker_t* tracker, service_reference_pt reference) {
     celix_status_t status = CELIX_SUCCESS;
     celix_tracked_entry_t *remove = NULL;
-    unsigned int i;
-    unsigned int size;
     const char *serviceName = NULL;
 
-    celixThreadRwlock_writeLock(&instance->lock);
-    size = arrayList_size(instance->trackedServices);
-    for (i = 0; i < size; i++) {
+    celixThreadMutex_lock(&tracker->mutex);
+    for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
         bool equals;
-        celix_tracked_entry_t *tracked = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
+        celix_tracked_entry_t *tracked = (celix_tracked_entry_t*) arrayList_get(tracker->trackedServices, i);
         serviceName = tracked->serviceName;
         serviceReference_equals(reference, tracked->reference, &equals);
         if (equals) {
             remove = tracked;
             //remove from trackedServices to prevent getting this service, but don't destroy yet, can be in use
-            arrayList_remove(instance->trackedServices, i);
+            celix_arrayList_removeAt(tracker->trackedServices, i);
+            celix_arrayList_add(tracker->untrackingServices, remove);
             break;
         }
     }
-    size = arrayList_size(instance->trackedServices); //updated size
-    celixThreadRwlock_unlock(&instance->lock);
+    int size = celix_arrayList_size(tracker->trackedServices); //updated size
+    celixThreadMutex_unlock(&tracker->mutex);
 
-    if (size == 0) {
-        serviceTracker_checkAndInvokeSetService(instance, NULL, NULL, NULL);
-    } else {
-        serviceTracker_useHighestRankingServiceInternal(instance, serviceName, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+    if (remove != NULL) {
+        if (size == 0) {
+            serviceTracker_checkAndInvokeSetService(tracker, NULL, NULL, NULL);
+        } else {
+            celix_serviceTracker_useHighestRankingService(tracker, serviceName, tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+        }
     }
 
-    serviceTracker_untrackTracked(instance, remove);
+    //note also syncing on untracking entries, to ensure no untrack is parallel in progress
+    if (remove != NULL) {
+        serviceTracker_untrackTracked(tracker, remove);
+        celixThreadMutex_lock(&tracker->mutex);
+        celix_arrayList_remove(tracker->untrackingServices, remove);
+        celixThreadMutex_unlock(&tracker->mutex);
+    } else {
+        //ensure no untrack is still happening (to ensure it safe to unregister service)
+        celixThreadMutex_lock(&tracker->mutex);
+        while (celix_arrayList_size(tracker->untrackingServices) > 0) {
+            celixThreadCondition_wait(&tracker->cond, &tracker->mutex);
+        }
+        celixThreadMutex_unlock(&tracker->mutex);
+    }
 
-    framework_logIfError(instance->context->framework->logger, status, NULL, "Cannot untrack reference");
+    framework_logIfError(tracker->context->framework->logger, status, NULL, "Cannot untrack reference");
 
     return status;
 }
 
-static void serviceTracker_untrackTracked(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
+static void serviceTracker_untrackTracked(service_tracker_t *tracker, celix_tracked_entry_t *tracked) {
     if (tracked != NULL) {
-        serviceTracker_invokeRemovingService(instance, tracked);
-        bundleContext_ungetServiceReference(instance->context, tracked->reference);
+        serviceTracker_invokeRemovingService(tracker, tracked);
+
+        bundleContext_ungetServiceReference(tracker->context, tracked->reference);
         tracked_release(tracked);
 
         //Wait till the useCount is 0, because the untrack should only return if the service is not used anymore.
@@ -625,37 +564,37 @@
     }
 }
 
-static celix_status_t serviceTracker_invokeRemovingService(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
+static celix_status_t serviceTracker_invokeRemovingService(service_tracker_t *tracker, celix_tracked_entry_t *tracked) {
     celix_status_t status = CELIX_SUCCESS;
     bool ungetSuccess = true;
 
     void *customizerHandle = NULL;
     removed_callback_pt function = NULL;
 
-    serviceTrackerCustomizer_getHandle(&instance->customizer, &customizerHandle);
-    serviceTrackerCustomizer_getRemovedFunction(&instance->customizer, &function);
+    serviceTrackerCustomizer_getHandle(&tracker->customizer, &customizerHandle);
+    serviceTrackerCustomizer_getRemovedFunction(&tracker->customizer, &function);
 
     if (function != NULL) {
         status = function(customizerHandle, tracked->reference, tracked->service);
     }
 
-    void *handle = instance->callbackHandle;
-    if (instance->remove != NULL) {
-        instance->remove(handle, tracked->service);
+    void *handle = tracker->callbackHandle;
+    if (tracker->remove != NULL) {
+        tracker->remove(handle, tracked->service);
     }
-    if (instance->addWithProperties != NULL) {
-        instance->removeWithProperties(handle, tracked->service, tracked->properties);
+    if (tracker->addWithProperties != NULL) {
+        tracker->removeWithProperties(handle, tracked->service, tracked->properties);
     }
-    if (instance->removeWithOwner != NULL) {
-        instance->removeWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
+    if (tracker->removeWithOwner != NULL) {
+        tracker->removeWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
     }
 
     if (status == CELIX_SUCCESS) {
-        status = bundleContext_ungetService(instance->context, tracked->reference, &ungetSuccess);
+        status = bundleContext_ungetService(tracker->context, tracked->reference, &ungetSuccess);
     }
 
     if (!ungetSuccess) {
-        framework_log(instance->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error ungetting service");
+        framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error ungetting service");
         status = CELIX_BUNDLE_EXCEPTION;
     }
 
@@ -687,11 +626,12 @@
         const celix_service_tracking_options_t *opts
 ) {
     celix_service_tracker_t *tracker = NULL;
-    if (ctx != NULL && opts != NULL && opts->filter.serviceName != NULL) {
+    const char* serviceName = opts->filter.serviceName == NULL ? "*" : opts->filter.serviceName;
+    if (ctx != NULL && opts != NULL) {
         tracker = calloc(1, sizeof(*tracker));
         if (tracker != NULL) {
             tracker->context = ctx;
-            tracker->serviceName = celix_utils_strdup(opts->filter.serviceName);
+            tracker->serviceName = celix_utils_strdup(serviceName);
 
             //setting callbacks
             tracker->callbackHandle = opts->callbackHandle;
@@ -705,72 +645,33 @@
             tracker->addWithOwner = opts->addWithOwner;
             tracker->removeWithOwner = opts->removeWithOwner;
 
-            celixThreadRwlock_create(&tracker->instanceLock, NULL);
+            celixThreadMutex_create(&tracker->closeSync.mutex, NULL);
+            celixThreadCondition_init(&tracker->closeSync.cond, NULL);
 
-            //setting lang
-            const char *lang = opts->filter.serviceLanguage;
-            if (lang == NULL || strncmp("", lang, 1) == 0) {
-                lang = CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
-            }
+            celixThreadMutex_create(&tracker->mutex, NULL);
+            celixThreadCondition_init(&tracker->cond, NULL);
+            tracker->trackedServices = celix_arrayList_create();
+            tracker->untrackingServices = celix_arrayList_create();
 
-            char* versionRange = NULL;
-            if(opts->filter.versionRange != NULL) {
-                version_range_pt range;
-                celix_status_t status = versionRange_parse(opts->filter.versionRange, &range);
-                if(status != CELIX_SUCCESS) {
-                    framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
-                    "Error incorrect version range.");
-                    celixThreadRwlock_destroy(&tracker->instanceLock);
-                    free(tracker);
-                    return NULL;
-                }
-                versionRange = versionRange_createLDAPFilter(range, CELIX_FRAMEWORK_SERVICE_VERSION);
-                versionRange_destroy(range);
-                if(versionRange == NULL) {
-                    framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
-                                  "Error creating LDAP filter.");
-                    celixThreadRwlock_destroy(&tracker->instanceLock);
-                    free(tracker);
-                    return NULL;
-                }
-            }
+            celixThreadMutex_create(&tracker->mutex, NULL);
+            tracker->currentHighestServiceId = -1;
 
-            //setting filter
-            if (opts->filter.ignoreServiceLanguage) {
-                if (opts->filter.filter != NULL && versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName, versionRange, opts->filter.filter);
-                } else if (versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName, versionRange);
-                } else if (opts->filter.filter != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName, opts->filter.filter);
-                } else {
-                    asprintf(&tracker->filter, "(&(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName);
-                }
-            } else {
-                if (opts->filter.filter != NULL && versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange, opts->filter.filter);
-                } else if (versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange);
-                } else if (opts->filter.filter != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, opts->filter.filter);
-                } else {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, opts->filter.serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
-                }
-            }
+            tracker->listener.handle = tracker;
+            tracker->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
+            tracker->filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->filter.serviceName, opts->filter.versionRange, opts->filter.filter, opts->filter.serviceLanguage, opts->filter.ignoreServiceLanguage);
 
-            if(versionRange != NULL){
-                free(versionRange);
+            if (tracker->filter == NULL) {
+                framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                              "Error cannot create filter.");
+                free(tracker->serviceName);
+                free(tracker);
+                return NULL;
             }
 
             serviceTracker_open(tracker);
         }
     } else {
-        if (ctx != NULL && opts != NULL && opts->filter.serviceName == NULL) {
-            framework_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
-                          "Error incorrect arguments. Missing service name.");
-        } else if (ctx != NULL) {
-            framework_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error incorrect arguments. Required context (%p) or opts (%p) is NULL", ctx, opts);
-        }
+        framework_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error incorrect arguments. Required context (%p) or opts (%p) is NULL", ctx, opts);
     }
     return tracker;
 }
@@ -782,7 +683,7 @@
     }
 }
 
-static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracker_instance_t *instance,
+bool celix_serviceTracker_useHighestRankingService(service_tracker_t *tracker,
                                                             const char *serviceName /*sanity*/,
                                                             void *callbackHandle,
                                                             void (*use)(void *handle, void *svc),
@@ -795,11 +696,11 @@
     unsigned int i;
 
     //first lock tracker and get highest tracked entry
-    celixThreadRwlock_readLock(&instance->lock);
-    unsigned int size = arrayList_size(instance->trackedServices);
+    celixThreadMutex_lock(&tracker->mutex);
+    unsigned int size = arrayList_size(tracker->trackedServices);
 
     for (i = 0; i < size; i++) {
-        tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
+        tracked = (celix_tracked_entry_t *) arrayList_get(tracker->trackedServices, i);
         if (serviceName != NULL && tracked->serviceName != NULL && strncmp(tracked->serviceName, serviceName, 10*1024) == 0) {
             const char *val = properties_getWithDefault(tracked->properties, OSGI_FRAMEWORK_SERVICE_RANKING, "0");
             long rank = strtol(val, NULL, 10);
@@ -813,7 +714,7 @@
         tracked_retain(highest);
     }
     //unlock tracker so that the tracked entry can be removed from the trackedServices list if unregistered.
-    celixThreadRwlock_unlock(&instance->lock);
+    celixThreadMutex_unlock(&tracker->mutex);
 
     if (highest != NULL) {
         //got service, call, decrease use count an signal useCond after.
@@ -833,40 +734,6 @@
     return called;
 }
 
-
-bool celix_serviceTracker_useHighestRankingService(
-        celix_service_tracker_t *tracker,
-        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),
-        void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)) {
-
-    bool called = false;
-    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;
-}
-
 size_t celix_serviceTracker_useServices(
         service_tracker_t *tracker,
         const char* serviceName /*sanity*/,
@@ -875,141 +742,34 @@
         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)) {
     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);
-        int size = celix_arrayList_size(instance->trackedServices);
-        count = (size_t)size;
-        celix_tracked_entry_t *entries[size];
-        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;
-        }
-        //unlock tracker so that the tracked entry can be removed from the trackedServices list if unregistered.
-        celixThreadRwlock_unlock(&instance->lock);
-
-        //then use entries and decrease use count
-        for (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) {
-                use(callbackHandle, entry->service);
-            }
-            if (useWithProperties != NULL) {
-                useWithProperties(callbackHandle, entry->service, entry->properties);
-            }
-            if (useWithOwner != NULL) {
-                useWithOwner(callbackHandle, entry->service, entry->properties, entry->serviceOwner);
-            }
-
-            tracked_release(entry);
-        }
+    //first lock tracker, get tracked entries and increase use count
+    celixThreadMutex_lock(&tracker->mutex);
+    int size = celix_arrayList_size(tracker->trackedServices);
+    count = (size_t)size;
+    celix_tracked_entry_t *entries[size];
+    for (int i = 0; i < size; i++) {
+        celix_tracked_entry_t *tracked = (celix_tracked_entry_t *) arrayList_get(tracker->trackedServices, i);
+        tracked_retain(tracked);
+        entries[i] = tracked;
     }
-    celixThreadRwlock_unlock(&tracker->instanceLock);
+    //unlock tracker so that the tracked entry can be removed from the trackedServices list if unregistered.
+    celixThreadMutex_unlock(&tracker->mutex);
+
+    //then use entries and decrease use count
+    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) {
+            use(callbackHandle, entry->service);
+        }
+        if (useWithProperties != NULL) {
+            useWithProperties(callbackHandle, entry->service, entry->properties);
+        }
+        if (useWithOwner != NULL) {
+            useWithOwner(callbackHandle, entry->service, entry->properties, entry->serviceOwner);
+        }
+
+        tracked_release(entry);
+    }
     return count;
-}
-
-void celix_serviceTracker_syncForFramework(void *fw) {
-    celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_shutdownMutex);
-    size_t count = 0;
-    do {
-        count = 0;
-        if (g_shutdownInstances != NULL) {
-            for (int i = 0; i < celix_arrayList_size(g_shutdownInstances); ++i) {
-                celix_service_tracker_instance_t *instance = celix_arrayList_get(g_shutdownInstances, i);
-                if (instance->context->framework == fw) {
-                    count += 1;
-                }
-            }
-        }
-        if (count > 0) {
-            pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex);
-        }
-    } while (count > 0);
-
-    if (g_shutdownInstances != NULL && celix_arrayList_size(g_shutdownInstances) == 0) {
-        celix_arrayList_destroy(g_shutdownInstances);
-        g_shutdownInstances = NULL;
-    }
-    celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-void celix_serviceTracker_syncForContext(void *ctx) {
-    celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_shutdownMutex);
-    size_t count;
-    do {
-        count = 0;
-        if (g_shutdownInstances != NULL) {
-            for (int i = 0; i < celix_arrayList_size(g_shutdownInstances); ++i) {
-                celix_service_tracker_instance_t *instance = celix_arrayList_get(g_shutdownInstances, i);
-                if (instance->context == ctx) {
-                    count += 1;
-                }
-            }
-        }
-        if (count > 0) {
-            pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex);
-        }
-    } while (count > 0);
-
-    if (g_shutdownInstances != NULL && celix_arrayList_size(g_shutdownInstances) == 0) {
-        celix_arrayList_destroy(g_shutdownInstances);
-        g_shutdownInstances = NULL;
-    }
-    celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-#ifdef CELIX_SERVICE_TRACKER_USE_SHUTDOWN_THREAD
-static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance) {
-    celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_shutdownMutex);
-    if (g_shutdownInstances == NULL) {
-        g_shutdownInstances = celix_arrayList_create();
-    }
-    celix_arrayList_add(g_shutdownInstances, instance);
-    celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t *instance) {
-    celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_shutdownMutex);
-    if (g_shutdownInstances != NULL) {
-        size_t size = celix_arrayList_size(g_shutdownInstances);
-        for (size_t i = 0; i < size; ++i) {
-            celix_array_list_entry_t entry;
-            memset(&entry, 0, sizeof(entry));
-            entry.voidPtrVal = instance;
-            celix_arrayList_removeEntry(g_shutdownInstances, entry);
-        }
-        if (celix_arrayList_size(g_shutdownInstances) == 0) {
-            celix_arrayList_destroy(g_shutdownInstances);
-            g_shutdownInstances = NULL;
-        }
-        celixThreadCondition_broadcast(&g_shutdownCond);
-    }
-    celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-static void* shutdownServiceTrackerInstanceHandler(void *data) {
-    celix_service_tracker_instance_t *instance = data;
-
-    fw_removeServiceListener(instance->context->framework, instance->context->bundle, &instance->listener);
-
-    celixThreadMutex_destroy(&instance->closingLock);
-    celixThreadCondition_destroy(&instance->activeServiceChangeCallsCond);
-    celixThreadMutex_destroy(&instance->mutex);
-    celixThreadRwlock_destroy(&instance->lock);
-    celix_arrayList_destroy(instance->trackedServices);
-    free(instance->filter);
-
-    serviceTracker_remInstanceFromShutdownList(instance);
-    free(instance);
-
-    return NULL;
-}
-#endif
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/libs/framework/src/service_tracker_private.h b/libs/framework/src/service_tracker_private.h
index 47b8fa7..4bc1b27 100644
--- a/libs/framework/src/service_tracker_private.h
+++ b/libs/framework/src/service_tracker_private.h
@@ -23,51 +23,14 @@
 #include "service_tracker.h"
 #include "celix_types.h"
 
-//instance for an active per open statement and removed per close statement
-typedef struct celix_service_tracker_instance {
-	celix_thread_mutex_t closingLock; //projects closing and activeServiceChangeCalls
-	bool closing; //when true the service tracker instance is being closed and all calls from the service listener are ignored
-	size_t activeServiceChangeCalls;
-	celix_thread_cond_t activeServiceChangeCallsCond;
-
-	bundle_context_t *context;
-	char * filter;
-
-	service_tracker_customizer_t customizer;
-	celix_service_listener_t listener;
-
-	void *callbackHandle;
-
-	void (*set)(void *handle, void *svc); //highest ranking
-	void (*add)(void *handle, void *svc);
-	void (*remove)(void *handle, void *svc);
-	void (*modified)(void *handle, void *svc);
-
-	void (*setWithProperties)(void *handle, void *svc, const properties_t *props); //highest ranking
-	void (*addWithProperties)(void *handle, void *svc, const properties_t *props);
-	void (*removeWithProperties)(void *handle, void *svc, const properties_t *props);
-	void (*modifiedWithProperties)(void *handle, void *svc, const properties_t *props);
-
-	void (*setWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner); //highest ranking
-	void (*addWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
-	void (*removeWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
-	void (*modifiedWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
-
-	celix_thread_rwlock_t lock; //projects trackedServices
-	array_list_t *trackedServices;
-
-	celix_thread_mutex_t mutex; //protect current highest service id
-	long currentHighestServiceId;
-
-	celix_thread_t shutdownThread; //will be created when this instance is shutdown
-} celix_service_tracker_instance_t;
-
 struct celix_serviceTracker {
 	bundle_context_t *context;
 
 	char* serviceName;
 	char* filter;
-	service_tracker_customizer_t *customizer;
+
+    service_tracker_customizer_t customizer;
+    celix_service_listener_t listener;
 
 	void *callbackHandle;
 
@@ -86,9 +49,19 @@
 	void (*removeWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
 	void (*modifiedWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
 
-	celix_thread_rwlock_t instanceLock;
-	celix_service_tracker_instance_t *instance; /*NULL -> close, !NULL->open*/
+    struct {
+        celix_thread_mutex_t mutex; //projects below
+        celix_thread_cond_t cond;
+        bool closing; //if closing is true, no new service registrations are added to the serice tracker
+        size_t activeCalls; // >0 if there is still a serviceChange for a service registration call active
+    } closeSync;
 
+    celix_thread_mutex_t mutex; //projects below
+    celix_thread_cond_t  cond;
+    celix_array_list_t *trackedServices;
+    celix_array_list_t *untrackingServices;
+    bool open;
+    long currentHighestServiceId;
 };
 
 typedef struct celix_tracked_entry {
diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt
index 697a3b0..d00b14b 100644
--- a/libs/utils/gtest/CMakeLists.txt
+++ b/libs/utils/gtest/CMakeLists.txt
@@ -18,6 +18,7 @@
 
 add_executable(test_utils
         src/LogUtilsTestSuite.cc
+        src/TimeUtilsTestSuite.cc
 )
 
 target_link_libraries(test_utils PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
diff --git a/libs/utils/gtest/src/TimeUtilsTestSuite.cc b/libs/utils/gtest/src/TimeUtilsTestSuite.cc
new file mode 100644
index 0000000..ccbca69
--- /dev/null
+++ b/libs/utils/gtest/src/TimeUtilsTestSuite.cc
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <thread>
+#include <chrono>
+
+#include "celix_utils.h"
+
+class TimeUtilsTestSuite : public ::testing::Test {};
+
+TEST_F(TimeUtilsTestSuite, GetTimeTest) {
+    timespec t1;
+    timespec t3;
+    clock_gettime(CLOCK_MONOTONIC, &t1);
+    std::this_thread::sleep_for(std::chrono::seconds {1} );
+    auto t2 = celix_gettime(CLOCK_MONOTONIC);
+    std::this_thread::sleep_for(std::chrono::seconds {1} );
+    clock_gettime(CLOCK_MONOTONIC, &t3);
+
+    EXPECT_GT(t2.tv_sec, t1.tv_sec);
+    EXPECT_GT(t3.tv_sec, t2.tv_sec);
+}
+
+
+TEST_F(TimeUtilsTestSuite, DiffTimeTest) {
+    auto t1 = celix_gettime(CLOCK_MONOTONIC);
+    std::this_thread::sleep_for(std::chrono::microseconds {10} );
+    auto t2 = celix_gettime(CLOCK_MONOTONIC);
+    auto diff = celix_difftime(&t1, &t2);
+    EXPECT_GE(diff, 0.00001 /*10 us*/);
+    EXPECT_LT(diff, 0.01 /*1 ms*/);
+}
+
+TEST_F(TimeUtilsTestSuite, ElapsedTimeTest) {
+    auto t1 = celix_gettime(CLOCK_MONOTONIC);
+    std::this_thread::sleep_for(std::chrono::microseconds {10} );
+    auto diff = celix_elapsedtime(CLOCK_MONOTONIC, t1);
+    EXPECT_GE(diff, 0.00001 /*10 us*/);
+    EXPECT_LT(diff, 0.1 /*1/10 s, note do want to rely on accuracy of sleep_for*/);
+}
\ No newline at end of file
diff --git a/libs/utils/include/celix_log_utils.h b/libs/utils/include/celix_log_utils.h
index 43ea714..b90cb4d 100644
--- a/libs/utils/include/celix_log_utils.h
+++ b/libs/utils/include/celix_log_utils.h
@@ -53,7 +53,6 @@
  * Logs a message to stdout/stderr using the provided logName and log level.
  * If the provided log level is higher than info, stderr will be used.
  *
- * function is not thread safe (multiple printf's are used).
  */
 void celix_logUtils_logToStdout(const char *logName, celix_log_level_e level, const char *format, ...);
 
@@ -66,7 +65,6 @@
  *
  * If the argument file or function is NULL, the arguments file, function and line are not used.
  *
- * function is not thread safe (multiple printf's are used).
  */
 void celix_logUtils_logToStdoutDetails(const char *logName, celix_log_level_e level, const char* file, const char* function, int line, const char *format, ...);
 
@@ -75,7 +73,6 @@
  * Logs a message to stdout/stderr using the provided logName and log level.
  * If the provided log level is higher than info, stderr will be used.
  *
- * function is not thread safe (multiple printf's are used).
  */
 void celix_logUtils_vLogToStdout(const char *logName, celix_log_level_e level, const char *format, va_list formatArgs);
 
@@ -88,14 +85,12 @@
  *
  * If the argument file or function is NULL, the arguments file, function and line are not used.
  *
- * function is not thread safe (multiple printf's are used).
  */
 void celix_logUtils_vLogToStdoutDetails(const char *logName, celix_log_level_e level, const char* file, const char* function, int line, const char *format, va_list formatArgs);
 
 /**
  * Prints a backtrace to the provided output stream.
  *
- * function is not thread safe (multiple printf's are used).
  */
 void celix_logUtils_printBacktrace(FILE* stream);
 
diff --git a/libs/utils/include/celix_utils.h b/libs/utils/include/celix_utils.h
index 2a7ba35..d39e8e2 100644
--- a/libs/utils/include/celix_utils.h
+++ b/libs/utils/include/celix_utils.h
@@ -71,6 +71,17 @@
  */
 double celix_difftime(const struct timespec *tBegin, const struct timespec *tEnd);
 
+/**
+ * Returns the current time as struct timespec
+ * @param clockId The clock to use (see time.h)
+ */
+struct timespec celix_gettime(clockid_t clockId);
+
+/**
+ * Returns the elapsed time - in seconds - relative to the startTime
+ * using the clock for the provided clockid.
+ */
+double celix_elapsedtime(clockid_t clockId, struct timespec startTime);
 
 /**
  * Creates a hash from a string
diff --git a/libs/utils/private/test/utils_test.cpp b/libs/utils/private/test/utils_test.cpp
index dfd9066..0954b38 100644
--- a/libs/utils/private/test/utils_test.cpp
+++ b/libs/utils/private/test/utils_test.cpp
@@ -271,21 +271,21 @@
 
 TEST(utils, compareServiceIdsAndRanking){
     int ret;
-    //service 1 is higher ranked and has a irrelevant ID
+    //service 1 is higher ranked and has a irrelevant ID, so result is -1 (smaller -> sorted before service 2)
     ret = utils_compareServiceIdsAndRanking(2,2,1,1);
-    LONGS_EQUAL(1, ret);
+    LONGS_EQUAL(-1, ret);
 
-    //service 1 is equally ranked and has a lower ID
+    //service 1 is equally ranked and has a lower ID. so result is -1 (smaller -> sorted before service 2)
     ret = utils_compareServiceIdsAndRanking(1,1,2,1);
+    LONGS_EQUAL(-1, ret);
+
+    //service 1 is equally ranked and has a higher ID, so result is 1 (larger -> sorted after service 2)
+    ret = utils_compareServiceIdsAndRanking(2,1,1,1);
     LONGS_EQUAL(1, ret);
 
-    //service 1 is equally ranked and has a higher ID
-    ret = utils_compareServiceIdsAndRanking(2,1,1,1);
-    LONGS_EQUAL(-1, ret);
-
-    //service 1 is lower ranked and has a irrelevant ID
+    //service 1 is lower ranked and has a irrelevant ID, so result is -1 (larger -> sorted after service 2)
     ret = utils_compareServiceIdsAndRanking(1,1,2,2);
-    LONGS_EQUAL(-1, ret);
+    LONGS_EQUAL(1, ret);
 
     //service 1 is equal in ID and irrelevantly ranked
     ret = utils_compareServiceIdsAndRanking(1,1,1,1);
diff --git a/libs/utils/src/celix_log_utils.c b/libs/utils/src/celix_log_utils.c
index 236d0d9..7826725 100644
--- a/libs/utils/src/celix_log_utils.c
+++ b/libs/utils/src/celix_log_utils.c
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <time.h>
 #include <string.h>
+#include <pthread.h>
 
 static const char * const CELIX_STRING_VALUE_DISABLED  = "disabled";
 static const char * const CELIX_STRING_VALUE_FATAL     = "fatal";
@@ -127,6 +128,8 @@
     celix_logUtils_vLogToStdoutDetails(logName, level, NULL, NULL, 0, format, formatArgs);
 }
 
+static pthread_mutex_t globalMutex = PTHREAD_MUTEX_INITIALIZER;
+
 void celix_logUtils_vLogToStdoutDetails(const char *logName, celix_log_level_e level, const char* file, const char* function, int line, const char *format, va_list formatArgs) {
     if (level == CELIX_LOG_LEVEL_DISABLED) {
         //silently ignore
@@ -143,22 +146,21 @@
         out = stderr;
     }
 
+    pthread_mutex_lock(&globalMutex);
     fprintf(out, "[%i-%02i-%02iT%02i:%02i:%02i] ", local.tm_year + 1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
     if (file != NULL && function != NULL) {
         (void)file; //note not using file
-        fprintf(out, "[%s] [%s] [%s:%i] ", celix_logUtils_logLevelToString(level), logName, function, line);
+        fprintf(out, "[%7s] [%s] [%s:%i] ", celix_logUtils_logLevelToString(level), logName, function, line);
     } else {
-        fprintf(out, "[%s] [%s] ", celix_logUtils_logLevelToString(level), logName);
+        fprintf(out, "[%7s] [%s] ", celix_logUtils_logLevelToString(level), logName);
     }
-
     vfprintf(out, format, formatArgs);
-
     fprintf(out, "\n");
-    fflush(out);
 
     if (level >= CELIX_LOG_LEVEL_FATAL) {
         fprintf(out, "Backtrace:\n");
-        fflush(out);
         celix_logUtils_inlinePrintBacktrace(out);
     }
+    fflush(out);
+    pthread_mutex_unlock(&globalMutex);
 }
\ No newline at end of file
diff --git a/libs/utils/src/utils.c b/libs/utils/src/utils.c
index f82bd26..85be134 100644
--- a/libs/utils/src/utils.c
+++ b/libs/utils/src/utils.c
@@ -150,9 +150,9 @@
     if (servId == otherServId) {
         result = 0;
     } else if (servRank != otherServRank) {
-        result = servRank < otherServRank ? -1 : 1;
+        result = servRank < otherServRank ? 1 : -1;
     } else { //equal service rank, compare service ids
-        result = servId < otherServId ? 1 : -1;
+        result = servId < otherServId ? -1 : 1;
     }
 
     return result;
@@ -171,6 +171,21 @@
     return ((double)diff.tv_sec) + diff.tv_nsec /  1000000000.0;
 }
 
+struct timespec celix_gettime(clockid_t clockId) {
+    struct timespec t;
+    errno = 0;
+    int rc = clock_gettime(clockId, &t);
+    if (rc != 0) {
+        fprintf(stderr, "Cannot get time from clock_gettime. Error is %s\n", strerror(errno));
+    }
+    return t;
+}
+
+double celix_elapsedtime(clockid_t clockId, struct timespec startTime) {
+    struct timespec now = celix_gettime(clockId);
+    return celix_difftime(&startTime, &now);
+}
+
 char* celix_utils_strdup(const char *str) {
     if (str != NULL) {
         return strndup(str, CELIX_UTILS_MAX_STRLEN);