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

[celix] branch feature/query_command created (now 59f5783)

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

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


      at 59f5783  gh-144: Adds initial impl for the query command.

This branch includes the following new commits:

     new 59f5783  gh-144: Adds initial impl for the query command.

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



[celix] 01/01: gh-144: Adds initial impl for the query command.

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

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

commit 59f578393047e4531afd7b53eafa624b24c6617a
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Feb 2 22:16:29 2020 +0100

    gh-144: Adds initial impl for the query command.
    
    Also refactors the shell impl. Adds a much needed mutex.
---
 bundles/shell/remote_shell/src/shell_mediator.c    |   2 +-
 bundles/shell/shell/CMakeLists.txt                 |   2 +
 bundles/shell/shell/include/command.h              |   2 +-
 bundles/shell/shell/include/shell.h                |  31 +-
 bundles/shell/shell/src/activator.c                | 183 +++++++-----
 bundles/shell/shell/src/help_command.c             |  12 +-
 bundles/shell/shell/src/lb_command.c               |   3 +-
 bundles/shell/shell/src/shell.c                    | 332 +++++++--------------
 bundles/shell/shell/src/shell_private.h            |  30 +-
 bundles/shell/shell/src/std_commands.h             |   3 +
 bundles/shell/shell_tui/private/src/shell_tui.c    |   8 +-
 .../shell_wui/src/shell_wui_bundle_activator.c     |   2 +-
 libs/framework/CMakeLists.txt                      |   1 +
 libs/framework/include/celix_bundle.h              |  55 ++++
 libs/framework/include/service_registration.h      |   4 +
 libs/framework/include/service_registry.h          |  31 +-
 libs/framework/private/mock/bundle_mock.c          |  20 ++
 .../private/mock/service_registration_mock.c       |   5 +
 .../framework/private/mock/service_registry_mock.c |  25 ++
 libs/framework/src/bundle.c                        |  59 ++++
 libs/framework/src/bundle_context.c                |  12 +-
 libs/framework/src/bundle_context_private.h        |   4 +-
 libs/framework/src/service_registration.c          |  17 +-
 libs/framework/src/service_registry.c              |  55 ++++
 libs/framework/src/service_tracker.c               |  35 ++-
 25 files changed, 554 insertions(+), 379 deletions(-)

diff --git a/bundles/shell/remote_shell/src/shell_mediator.c b/bundles/shell/remote_shell/src/shell_mediator.c
index 0839be2..e12abb2 100644
--- a/bundles/shell/remote_shell/src/shell_mediator.c
+++ b/bundles/shell/remote_shell/src/shell_mediator.c
@@ -110,7 +110,7 @@ celix_status_t shellMediator_executeCommand(shell_mediator_pt instance, char *co
 
 
 	if (instance->shellService != NULL) {
-		instance->shellService->executeCommand(instance->shellService->shell, command, out, err);
+		instance->shellService->executeCommand(instance->shellService->handle, command, out, err);
 	}
 
 	celixThreadMutex_unlock(&instance->mutex);
diff --git a/bundles/shell/shell/CMakeLists.txt b/bundles/shell/shell/CMakeLists.txt
index 4d59345..c1037b7 100644
--- a/bundles/shell/shell/CMakeLists.txt
+++ b/bundles/shell/shell/CMakeLists.txt
@@ -44,6 +44,8 @@ if (SHELL)
           src/inspect_command
           src/help_command
 		  src/dm_shell_list_command
+		  src/query_command.c
+		  src/q_command.c
 	)
 	target_include_directories(shell PRIVATE src)
 	target_link_libraries(shell PRIVATE Celix::shell_api CURL::libcurl Celix::log_service_api Celix::log_helper)
diff --git a/bundles/shell/shell/include/command.h b/bundles/shell/shell/include/command.h
index 3ab3f2a..df1310b 100644
--- a/bundles/shell/shell/include/command.h
+++ b/bundles/shell/shell/include/command.h
@@ -49,7 +49,7 @@ typedef command_service_t * command_service_pt;
  */
 struct commandService {
     void *handle;
-    celix_status_t (*executeCommand)(void *handle, char * commandLine, FILE *outStream, FILE *errorStream);
+    celix_status_t (*executeCommand)(void *handle, char* commandLine, FILE *outStream, FILE *errorStream);
 };
 
 
diff --git a/bundles/shell/shell/include/shell.h b/bundles/shell/shell/include/shell.h
index 54bc6e8..306c881 100644
--- a/bundles/shell/shell/include/shell.h
+++ b/bundles/shell/shell/include/shell.h
@@ -31,18 +31,31 @@
 #include "service_reference.h"
 
 static const char * const OSGI_SHELL_SERVICE_NAME = "shellService";
-
-typedef struct shell shell_t;
-typedef shell_t* shell_pt;
+static const char * const OSGI_SHELL_SERVICE_VERSION = "2.0.0";
 
 struct shellService {
-	shell_pt shell;
+	void *handle;
+
+	/**
+	 * List the registered command names. Caller is owner of the commands.
+	 * @return A celix array list with char*.
+	 */
+	celix_status_t (*getCommands)(void *handle, celix_array_list_t **commands);
+
+	/**
+	 * Gets the usage info for the provided command str. Caller is owner.
+	 */
+	celix_status_t (*getCommandUsage)(void *handle, const char *commandName, char **UsageStr);
+
+    /**
+     * Gets the usage info for the provided command str. Caller is owner.
+     */
+	celix_status_t (*getCommandDescription)(void *handle, const char *commandName, char **commandDescription);
 
-	celix_status_t (*getCommands)(shell_pt shell_ptr, celix_array_list_t **commands_ptr);
-	celix_status_t (*getCommandUsage)(shell_pt shell_ptr, char *command_name_str, char **usage_str);
-	celix_status_t (*getCommandDescription)(shell_pt shell_ptr, char *command_name_str, char **command_description_str);
-	celix_status_t (*getCommandReference)(shell_pt shell_ptr, char *command_name_str, service_reference_pt *command_reference_ptr);
-	celix_status_t (*executeCommand)(shell_pt shell_ptr, char * command_line_str, FILE *out, FILE *err);
+	/**
+	 * Try to execute a commmand using the provided command line.
+	 */
+	celix_status_t (*executeCommand)(void *handle, const char *commandLine, FILE *out, FILE *err);
 };
 
 typedef struct shellService shell_service_t;
diff --git a/bundles/shell/shell/src/activator.c b/bundles/shell/shell/src/activator.c
index 67c06e6..291e802 100644
--- a/bundles/shell/shell/src/activator.c
+++ b/bundles/shell/shell/src/activator.c
@@ -33,50 +33,51 @@
 #include "service_tracker.h"
 #include "celix_constants.h"
 
-#define NUMBER_OF_COMMANDS 11
+#define NUMBER_OF_COMMANDS 13
 
 struct command {
     celix_status_t (*exec)(void *handle, char *commandLine, FILE *out, FILE *err);
     char *name;
     char *description;
     char *usage;
-    command_service_pt service;
-    properties_pt props;
+    command_service_t service;
+    celix_properties_t *props;
     long svcId; //used for service (un)registration
 };
 
-struct bundle_instance {
-	shell_service_pt shellService;
-	service_registration_pt registration;
-    service_tracker_pt tracker;
+struct shell_bundle_activator {
+    shell_t *shell;
+    shell_service_t shellService;
+	long shellSvcId;
+	long trackerId;
 
     struct command std_commands[NUMBER_OF_COMMANDS];
 };
 
-typedef struct bundle_instance *bundle_instance_pt;
+typedef struct shell_bundle_activator shell_bundle_activator_t;
 
-celix_status_t bundleActivator_create(bundle_context_pt context_ptr, void **_pptr) {
+celix_status_t bundleActivator_create(celix_bundle_context_t* ctx, void **_pptr) {
 	celix_status_t status = CELIX_SUCCESS;
 
-    bundle_instance_pt instance_ptr = NULL;
+    shell_bundle_activator_t* activator = NULL;
 
-    if (!_pptr || !context_ptr) {
+    if (!_pptr || !ctx) {
         status = CELIX_ENOMEM;
     }
 
     if (status == CELIX_SUCCESS) {
-        instance_ptr = (bundle_instance_pt) calloc(1, sizeof(struct bundle_instance));
-        if (!instance_ptr) {
+        activator = calloc(1, sizeof(*activator));
+        if (!activator) {
             status = CELIX_ENOMEM;
         }
     }
 
     if (status == CELIX_SUCCESS) {
-        status = shell_create(context_ptr, &instance_ptr->shellService);
+        activator->shell = shell_create(ctx);
     }
 
     if (status == CELIX_SUCCESS) {
-        instance_ptr->std_commands[0] =
+        activator->std_commands[0] =
                 (struct command) {
                         .exec = lbCommand_execute,
                         .name = "lb",
@@ -85,162 +86,191 @@ celix_status_t bundleActivator_create(bundle_context_pt context_ptr, void **_ppt
                             "\nUse -l to print the bundle locations.\nUse -s to print the bundle symbolic names\nUse -u to print the bundle update location.",
                         .usage = "lb [-l | -s | -u | -a] [group]"
                 };
-        instance_ptr->std_commands[1] =
+        activator->std_commands[1] =
                 (struct command) {
                         .exec = startCommand_execute,
                         .name = "start",
                         .description = "start bundle(s).",
                         .usage = "start <id> [<id> ...]"
                 };
-        instance_ptr->std_commands[2] =
+        activator->std_commands[2] =
                 (struct command) {
                         .exec = stopCommand_execute,
                         .name = "stop",
                         .description = "stop bundle(s).",
                         .usage = "stop <id> [<id> ...]"
                 };
-        instance_ptr->std_commands[3] =
+        activator->std_commands[3] =
                 (struct command) {
                         .exec = installCommand_execute,
                         .name = "install",
                         .description = "install bundle(s).",
                         .usage = "install <file> [<file> ...]"
                 };
-        instance_ptr->std_commands[4] =
+        activator->std_commands[4] =
                 (struct command) {
                         .exec = uninstallCommand_execute,
                         .name = "uninstall",
                         .description = "uninstall bundle(s).",
                         .usage = "uninstall <file> [<file> ...]"
                 };
-        instance_ptr->std_commands[5] =
+        activator->std_commands[5] =
                 (struct command) {
                         .exec = updateCommand_execute,
                         .name = "update",
                         .description = "update bundle(s).",
                         .usage = "update <id> [<URL>]"
                 };
-        instance_ptr->std_commands[6] =
+        activator->std_commands[6] =
                 (struct command) {
                         .exec = helpCommand_execute,
                         .name = "help",
                         .description = "display available commands and description.",
                         .usage = "help <command>]"
                 };
-        instance_ptr->std_commands[7] =
+        activator->std_commands[7] =
                 (struct command) {
                         .exec = logCommand_execute,
                         .name = "log",
                         .description = "print log.",
                         .usage = "log"
                 };
-        instance_ptr->std_commands[8] =
+        activator->std_commands[8] =
                 (struct command) {
                         .exec = inspectCommand_execute,
                         .name = "inspect",
                         .description = "inspect services and components.",
                         .usage = "inspect (service) (capability|requirement) [<id> ...]"
                 };
-        instance_ptr->std_commands[9] =
+        activator->std_commands[9] =
                 (struct command) {
                         .exec = dmListCommand_execute,
                         .name = "dm",
                         .description = "Gives an overview of the component managed by a dependency manager.",
                         .usage = "dm [wtf] [f|full] [<Bundle ID> [<Bundle ID> [...]]]"
                 };
-        instance_ptr->std_commands[10] =
-                (struct command) { NULL, NULL, NULL, NULL, NULL, NULL, -1L }; /*marker for last element*/
+        activator->std_commands[10] =
+                (struct command) {
+                    .exec = queryCommand_execute,
+                    .name = "query",
+                    .description = "Query services. Query for registered and requested services" \
+                    "\nIf a query is provided, only service with a service name containing the query will be displayed." \
+                    "\nOr if the query is a filter. the filter will be used. If a filter is used, the optional bundle id will be ignored."
+                    "\n\tIf the -v option is provided, also list the service properties." \
+                    "\n\tIf the -r option is provided, only query for requested services." \
+                    "\n\tIf the -p option is provided, only query for provided services.",
+                    .usage = "ls [bundleId] [-v] [-p] [-r] [query_name ...]"
+                };
+        activator->std_commands[11] =
+                (struct command) {
+                        .exec = qCommand_execute,
+                        .name = "q",
+                        .description = "Quit (exit) framework.",
+                        .usage = "q"
+                };
+        activator->std_commands[12] =
+                (struct command) { NULL, NULL, NULL, NULL, {NULL,NULL}, NULL, -1L }; /*marker for last element*/
 
         unsigned int i = 0;
-        while (instance_ptr->std_commands[i].exec != NULL) {
-            instance_ptr->std_commands[i].props = properties_create();
-            if (!instance_ptr->std_commands[i].props) {
+        while (activator->std_commands[i].exec != NULL) {
+            activator->std_commands[i].props = properties_create();
+            if (!activator->std_commands[i].props) {
                 status = CELIX_BUNDLE_EXCEPTION;
                 break;
             }
 
-            properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_NAME, instance_ptr->std_commands[i].name);
-            properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_USAGE, instance_ptr->std_commands[i].usage);
-            properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_DESCRIPTION, instance_ptr->std_commands[i].description);
-            properties_set(instance_ptr->std_commands[i].props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
+            celix_properties_set(activator->std_commands[i].props, OSGI_SHELL_COMMAND_NAME, activator->std_commands[i].name);
+            celix_properties_set(activator->std_commands[i].props, OSGI_SHELL_COMMAND_USAGE, activator->std_commands[i].usage);
+            celix_properties_set(activator->std_commands[i].props, OSGI_SHELL_COMMAND_DESCRIPTION, activator->std_commands[i].description);
+            celix_properties_set(activator->std_commands[i].props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
 
-            instance_ptr->std_commands[i].service = calloc(1, sizeof(*instance_ptr->std_commands[i].service));
-            if (!instance_ptr->std_commands[i].service) {
-                status = CELIX_ENOMEM;
-                break;
-            }
-
-            instance_ptr->std_commands[i].service->handle = context_ptr;
-            instance_ptr->std_commands[i].service->executeCommand = instance_ptr->std_commands[i].exec;
+            activator->std_commands[i].service.handle = ctx;
+            activator->std_commands[i].service.executeCommand = activator->std_commands[i].exec;
 
             i += 1;
         }
     }
 
     if (status == CELIX_SUCCESS) {
-        *_pptr = instance_ptr;
+        *_pptr = activator;
     }
 
 
     if (status != CELIX_SUCCESS) {
-        bundleActivator_destroy(instance_ptr, context_ptr);
+        bundleActivator_destroy(activator, ctx);
     }
 
 	return status;
 }
 
-celix_status_t bundleActivator_start(void *_ptr, bundle_context_pt context_ptr) {
+celix_status_t bundleActivator_start(void *activatorData, celix_bundle_context_t* ctx) {
 	celix_status_t status = CELIX_SUCCESS;
 
-	bundle_instance_pt instance_ptr  = (bundle_instance_pt) _ptr;
+    shell_bundle_activator_t* activator  = (shell_bundle_activator_t*) activatorData;
 
-    if (!instance_ptr || !context_ptr) {
+    if (!activator || !ctx) {
         status = CELIX_ILLEGAL_ARGUMENT;
     }
 
     if (status == CELIX_SUCCESS) {
-        properties_pt props = properties_create();
-        properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
-        status = bundleContext_registerService(context_ptr, (char *) OSGI_SHELL_SERVICE_NAME, instance_ptr->shellService, props, &instance_ptr->registration);
+        activator->shellService.handle = activator->shell;
+        activator->shellService.executeCommand = (void*)shell_executeCommand;
+        activator->shellService.getCommandDescription = (void*)shell_getCommandDescription;
+        activator->shellService.getCommandUsage = (void*)shell_getCommandUsage;
+        activator->shellService.getCommands = (void*)shell_getCommands;
+
+        celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+        opts.serviceName = OSGI_SHELL_SERVICE_NAME;
+        opts.serviceVersion = OSGI_SHELL_SERVICE_VERSION;
+        opts.svc = &activator->shellService;
+
+        activator->shellSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts);
     }
 
 	if (status == CELIX_SUCCESS) {
-        service_tracker_customizer_pt cust = NULL;
-        serviceTrackerCustomizer_create(instance_ptr->shellService->shell, NULL, (void *)shell_addCommand, NULL, (void *)shell_removeCommand, &cust);
-        serviceTracker_create(context_ptr, (char *)OSGI_SHELL_COMMAND_SERVICE_NAME, cust, &instance_ptr->tracker);
-        serviceTracker_open(instance_ptr->tracker);
+	    celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+	    opts.callbackHandle = activator->shell;
+	    opts.addWithProperties = (void*) shell_addCommand;
+	    opts.removeWithProperties = (void*) shell_removeCommand;
+	    opts.filter.ignoreServiceLanguage = true;
+	    opts.filter.serviceName = OSGI_SHELL_COMMAND_SERVICE_NAME;
+	    activator->trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
     }
 
 
     if (status == CELIX_SUCCESS) {
-        for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) {
+        for (unsigned int i = 0; activator->std_commands[i].exec != NULL; i++) {
             celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
-            opts.svc = instance_ptr->std_commands[i].service;
+            opts.svc = &activator->std_commands[i].service;
             opts.serviceName = OSGI_SHELL_COMMAND_SERVICE_NAME;
             opts.serviceVersion = OSGI_SHELL_COMMAND_SERVICE_VERSION;
-            opts.properties = instance_ptr->std_commands[i].props;
-            instance_ptr->std_commands[i].svcId = celix_bundleContext_registerServiceWithOptions(context_ptr, &opts);
+            opts.properties = activator->std_commands[i].props;
+            activator->std_commands[i].svcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts);
         }
 	}
 
 	return status;
 }
 
-celix_status_t bundleActivator_stop(void *_ptr, bundle_context_pt context_ptr) {
+celix_status_t bundleActivator_stop(void *activatorData, celix_bundle_context_t* ctx) {
     celix_status_t status = CELIX_SUCCESS;
 
-    bundle_instance_pt instance_ptr = (bundle_instance_pt) _ptr;
+    shell_bundle_activator_t* activator = activatorData;
 
-    if (instance_ptr) {
-        for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) {
-            if (instance_ptr->std_commands[i].svcId >= 0) {
-                celix_bundleContext_unregisterService(context_ptr, instance_ptr->std_commands[i].svcId);
-                instance_ptr->std_commands[i].props = NULL;
+    if (activator) {
+        for (unsigned int i = 0; activator->std_commands[i].exec != NULL; i++) {
+            if (activator->std_commands[i].svcId >= 0) {
+                celix_bundleContext_unregisterService(ctx, activator->std_commands[i].svcId);
+                activator->std_commands[i].props = NULL;
             }
         }
 
-        if (instance_ptr->tracker != NULL) {
-            serviceTracker_close(instance_ptr->tracker);
+        if (activator->shellSvcId >= 0L) {
+            celix_bundleContext_unregisterService(ctx, activator->shellSvcId);
+        }
+
+        if (activator->trackerId >= 0L) {
+            celix_bundleContext_stopTracker(ctx, activator->trackerId);
         }
     } else {
         status = CELIX_ILLEGAL_ARGUMENT;
@@ -249,25 +279,14 @@ celix_status_t bundleActivator_stop(void *_ptr, bundle_context_pt context_ptr) {
     return status;
 }
 
-celix_status_t bundleActivator_destroy(void *_ptr, bundle_context_pt __attribute__((__unused__)) context_ptr) {
+celix_status_t bundleActivator_destroy(void *activatorData, celix_bundle_context_t* __attribute__((__unused__)) ctx) {
     celix_status_t status = CELIX_SUCCESS;
+    shell_bundle_activator_t* activator = activatorData;
 
-    bundle_instance_pt instance_ptr = (bundle_instance_pt) _ptr;
-
-    if (instance_ptr) {
-        serviceRegistration_unregister(instance_ptr->registration);
-
-        for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) {
-            free(instance_ptr->std_commands[i].service);
-        }
-
-        shell_destroy(&instance_ptr->shellService);
-
-        if (instance_ptr->tracker != NULL) {
-            serviceTracker_destroy(instance_ptr->tracker);
-        }
 
-        free(instance_ptr);
+    if (activator) {
+        shell_destroy(activator->shell);
+        free(activator);
     } else {
         status = CELIX_ILLEGAL_ARGUMENT;
     }
diff --git a/bundles/shell/shell/src/help_command.c b/bundles/shell/shell/src/help_command.c
index 1c29ab2..91550cc 100644
--- a/bundles/shell/shell/src/help_command.c
+++ b/bundles/shell/shell/src/help_command.c
@@ -52,7 +52,7 @@ static void printHelp(void *handle, void *svc) {
         unsigned int i;
         array_list_pt commands = NULL;
 
-        shell->getCommands(shell->shell, &commands);
+        shell->getCommands(shell->handle, &commands);
         for (i = 0; i < arrayList_size(commands); i++) {
             char *name = arrayList_get(commands, i);
             fprintf(out, "%s\n", name);
@@ -64,15 +64,15 @@ static void printHelp(void *handle, void *svc) {
         celix_status_t sub_status_usage;
         int i;
         celix_array_list_t *commands = NULL;
-        shell->getCommands(shell->shell, &commands);
+        shell->getCommands(shell->handle, &commands);
         for (i = 0; i < arrayList_size(commands); i++) {
             char *name = arrayList_get(commands, i);
             if (strcmp(sub, name) == 0) {
                 char *usage_str = NULL;
                 char *desc_str = NULL;
 
-                sub_status_desc = shell->getCommandDescription(shell->shell, name, &desc_str);
-                sub_status_usage = shell->getCommandUsage(shell->shell, name, &usage_str);
+                sub_status_desc = shell->getCommandDescription(shell->handle, name, &desc_str);
+                sub_status_usage = shell->getCommandUsage(shell->handle, name, &usage_str);
 
                 if (sub_status_usage == CELIX_SUCCESS && sub_status_desc == CELIX_SUCCESS) {
                     fprintf(out, "Command     : %s\n", name);
@@ -81,7 +81,11 @@ static void printHelp(void *handle, void *svc) {
                 } else {
                     fprintf(err, "Error retrieving help info for command '%s'\n", sub);
                 }
+
+                free(usage_str);
+                free(desc_str);
             }
+            free(name);
         }
         celix_arrayList_destroy(commands);
     }
diff --git a/bundles/shell/shell/src/lb_command.c b/bundles/shell/shell/src/lb_command.c
index ffeb9ce..8734a6c 100644
--- a/bundles/shell/shell/src/lb_command.c
+++ b/bundles/shell/shell/src/lb_command.c
@@ -264,8 +264,7 @@ celix_status_t lbCommand_execute(void *_ptr, char *command_line_str, FILE *out_p
     lb_options_t opts;
     memset(&opts, 0, sizeof(opts));
 
-    const char* config = NULL;
-    bundleContext_getPropertyWithDefault(ctx, SHELL_USE_ANSI_COLORS, SHELL_USE_ANSI_COLORS_DEFAULT_VALUE, &config);
+    const char* config = celix_bundleContext_getProperty(ctx, SHELL_USE_ANSI_COLORS, SHELL_USE_ANSI_COLORS_DEFAULT_VALUE);
     opts.useColors = config != NULL && strncmp("true", config, 5) == 0;
 
 
diff --git a/bundles/shell/shell/src/shell.c b/bundles/shell/shell/src/shell.c
index ce90108..bc67700 100644
--- a/bundles/shell/shell/src/shell.c
+++ b/bundles/shell/shell/src/shell.c
@@ -16,17 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * shell.c
- *
- *  \date       Aug 13, 2010
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
+
 
 #include <stdlib.h>
 #include <string.h>
 #include <log_helper.h>
+#include <celix_constants.h>
 
 #include "celix_errno.h"
 
@@ -35,271 +30,154 @@
 
 #include "utils.h"
 
-celix_status_t shell_getCommands(shell_pt shell_ptr, array_list_pt *commands_ptr);
-celix_status_t shell_getCommandUsage(shell_pt shell_ptr, char *command_name_str, char **usage_pstr);
-celix_status_t shell_getCommandDescription(shell_pt shell_ptr, char *command_name_str, char **command_description_pstr);
 
-celix_status_t shell_create(bundle_context_pt context_ptr, shell_service_pt *shell_service_ptr) {
-	celix_status_t status = CELIX_SUCCESS;
+shell_t* shell_create(celix_bundle_context_t *ctx) {
+    shell_t *shell = calloc(1, sizeof(*shell));
 
-	if (!context_ptr || !shell_service_ptr) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
-
-	if (status == CELIX_SUCCESS) {
-		*shell_service_ptr =  calloc(1, sizeof(**shell_service_ptr));
-		if (!*shell_service_ptr) {
-			status = CELIX_ENOMEM;
-		}
-	}
-
-	if (status == CELIX_SUCCESS) {
-		(*shell_service_ptr)->shell = calloc(1, sizeof(*(*shell_service_ptr)->shell));
-		if (!(*shell_service_ptr)->shell) {
-			status = CELIX_ENOMEM;
-		}
-	}
-
-	if (status == CELIX_SUCCESS) {
-		(*shell_service_ptr)->shell->bundle_context_ptr = context_ptr;
-		(*shell_service_ptr)->shell->command_name_map_ptr = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
-		(*shell_service_ptr)->shell->command_reference_map_ptr = hashMap_create(NULL, NULL, NULL, NULL);
+    shell->ctx = ctx;
+    logHelper_create(ctx, &shell->logHelper);
 
-		(*shell_service_ptr)->getCommands = shell_getCommands;
-		(*shell_service_ptr)->getCommandDescription = shell_getCommandDescription;
-		(*shell_service_ptr)->getCommandUsage = shell_getCommandUsage;
-		(*shell_service_ptr)->getCommandReference = shell_getCommandReference;
-		(*shell_service_ptr)->executeCommand = shell_executeCommand;
+    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);
+    shell->commandServices = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
 
-        status = logHelper_create(context_ptr, &(*shell_service_ptr)->shell->logHelper);
-	}
-
-	if (status != CELIX_SUCCESS) {
-		shell_destroy(shell_service_ptr);
-	}
-
-	return status;
+    return shell;
 }
 
-celix_status_t shell_destroy(shell_service_pt *shell_service_ptr) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	if (!shell_service_ptr || !*shell_service_ptr) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
-
-	if (status == CELIX_SUCCESS) {
-		if ((*shell_service_ptr)->shell) {
-			if ((*shell_service_ptr)->shell->command_name_map_ptr) {
-				hashMap_destroy((*shell_service_ptr)->shell->command_name_map_ptr, false, false);
-			}
-			if ((*shell_service_ptr)->shell->command_reference_map_ptr) {
-				hashMap_destroy((*shell_service_ptr)->shell->command_reference_map_ptr, false, false);
-			}
-			if ((*shell_service_ptr)->shell->logHelper) {
-				logHelper_destroy(&((*shell_service_ptr)->shell->logHelper));
-			}
-			free((*shell_service_ptr)->shell);
-			(*shell_service_ptr)->shell = NULL;
-		}
-		free(*shell_service_ptr);
-		*shell_service_ptr = NULL;
-	}
-
-	return status;
+void shell_destroy(shell_t *shell) {
+    if (shell != NULL) {
+        celixThreadMutex_destroy(&shell->mutex);
+        hashMap_destroy(shell->commandServices, false, false);
+        logHelper_destroy(&shell->logHelper);
+        free(shell);
+    }
 }
 
-celix_status_t shell_addCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc) {
+celix_status_t shell_addCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props) {
     celix_status_t status = CELIX_SUCCESS;
-    command_service_pt command_ptr = NULL;
-    const char *name_str = NULL;
-
-    if (!shell_ptr || !reference_ptr) {
-        return CELIX_ILLEGAL_ARGUMENT;
-    }
-
-    if (status == CELIX_SUCCESS) {
-        command_ptr = svc;
-    }
-
-    if (status == CELIX_SUCCESS) {
-        status = serviceReference_getProperty(reference_ptr, "command.name", &name_str);
-        if (!name_str) {
-            logHelper_log(shell_ptr->logHelper, OSGI_LOGSERVICE_ERROR, "Command service must contain a 'command.name' property!");
-            status = CELIX_BUNDLE_EXCEPTION;
+    const char *name = celix_properties_get(props, "command.name", NULL);
+
+    if (name == NULL) {
+        logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Command service must contain a 'command.name' property!");
+        status = CELIX_BUNDLE_EXCEPTION;
+    } else {
+        long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
+        celixThreadMutex_lock(&shell->mutex);
+        if (hashMap_containsKey(shell->commandServices, name)) {
+            logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Command with name %s already registered!", name);
+        } else {
+            celix_shell_command_entry_t *entry = calloc(1, sizeof(*entry));
+            entry->svcId = svcId;
+            entry->svc = svc;
+            entry->props = props;
+            hashMap_put(shell->commandServices, (void*)name, entry);
         }
-    }
-
-    if (status == CELIX_SUCCESS) {
-        hashMap_put(shell_ptr->command_name_map_ptr, (char *)name_str, command_ptr);
-        hashMap_put(shell_ptr->command_reference_map_ptr, reference_ptr, command_ptr);
-    }
-
-    if (status != CELIX_SUCCESS) {
-        shell_removeCommand(shell_ptr, reference_ptr, svc);
-        char err[32];
-        celix_strerror(status, err, 32);
-        logHelper_log(shell_ptr->logHelper, OSGI_LOGSERVICE_ERROR, "Could not add command, got error %s\n", err);
+        celixThreadMutex_unlock(&shell->mutex);
     }
 
     return status;
 }
 
-celix_status_t shell_removeCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc) {
+celix_status_t shell_removeCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props) {
     celix_status_t status = CELIX_SUCCESS;
-
-    command_service_pt command_ptr = NULL;
-    const char *name_str = NULL;
-
-    if (!shell_ptr || !reference_ptr) {
-        status = CELIX_ILLEGAL_ARGUMENT;
-    }
-
-    if (status == CELIX_SUCCESS) {
-        command_ptr = hashMap_remove(shell_ptr->command_reference_map_ptr, reference_ptr);
-        if (!command_ptr) {
-            status = CELIX_ILLEGAL_ARGUMENT;
-        }
-    }
-
-    if (status == CELIX_SUCCESS) {
-        status = serviceReference_getProperty(reference_ptr, "command.name", &name_str);
-        if (!name_str) {
-            status = CELIX_BUNDLE_EXCEPTION;
+    const char *name = celix_properties_get(props, "command.name", NULL);
+
+    if (name == NULL) {
+        logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Command service must contain a 'command.name' property!");
+        status = CELIX_BUNDLE_EXCEPTION;
+    } else {
+        long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
+        celixThreadMutex_lock(&shell->mutex);
+        if (hashMap_containsKey(shell->commandServices, name)) {
+            celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, name);
+            if (entry->svcId == svcId) {
+                hashMap_remove(shell->commandServices, name);
+                free(entry);
+            } else {
+                logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "svc id for command with name %s does not match (%li == %li)!", name, svcId, entry->svcId);
+            }
+        } else {
+            logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Cannot find shell command with name %s!", name);
         }
-    }
-
-    if (status == CELIX_SUCCESS) {
-        hashMap_remove(shell_ptr->command_name_map_ptr, (char *)name_str);
+        celixThreadMutex_unlock(&shell->mutex);
     }
 
     return status;
 }
 
-celix_status_t shell_getCommands(shell_pt shell_ptr, array_list_pt *commands_ptr) {
+celix_status_t shell_getCommands(shell_t *shell, celix_array_list_t **outCommands) {
 	celix_status_t status = CELIX_SUCCESS;
+	celix_array_list_t *result = celix_arrayList_create();
 
-	hash_map_iterator_pt iter = NULL;
-
-	if (!shell_ptr || !commands_ptr) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
-
-	if (status == CELIX_SUCCESS) {
-		iter = hashMapIterator_create(shell_ptr->command_name_map_ptr);
-		if (!iter) {
-			status = CELIX_BUNDLE_EXCEPTION;
-		}
-	}
+    celixThreadMutex_lock(&shell->mutex);
+    hash_map_iterator_t iter = hashMapIterator_construct(shell->commandServices);
+    while (hashMapIterator_hasNext(&iter)) {
+        const char *name = hashMapIterator_nextKey(&iter);
+        celix_arrayList_add(result, strndup(name, 1024*1024*10));
+    }
+    celixThreadMutex_unlock(&shell->mutex);
 
-	if (status == CELIX_SUCCESS) {
-		arrayList_create(commands_ptr);
-		while (hashMapIterator_hasNext(iter)) {
-			char *name_str = hashMapIterator_nextKey(iter);
-			arrayList_add(*commands_ptr, name_str);
-		}
-		hashMapIterator_destroy(iter);
-	}
+    *outCommands = result;
 
-	return status;
+    return status;
 }
 
 
-celix_status_t shell_getCommandUsage(shell_pt shell_ptr, char *command_name_str, char **usage_pstr) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	service_reference_pt reference = NULL;
-
-	if (!shell_ptr || !command_name_str || !usage_pstr) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
+celix_status_t shell_getCommandUsage(shell_t *shell, const char *commandName, char **outUsage) {
+    celix_status_t status = CELIX_SUCCESS;
 
-	if (status == CELIX_SUCCESS) {
-		status = shell_getCommandReference(shell_ptr, command_name_str, &reference);
-		if (!reference) {
-			status = CELIX_BUNDLE_EXCEPTION;
-		}
-	}
+    celixThreadMutex_lock(&shell->mutex);
+    celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, commandName);
+    if (entry != NULL) {
+        const char *usage = celix_properties_get(entry->props, OSGI_SHELL_COMMAND_USAGE, "N/A");
+        *outUsage = strndup(usage, 1024*1024*10);
+    } else {
+        *outUsage = NULL;
+    }
+    celixThreadMutex_unlock(&shell->mutex);
 
-	if (status == CELIX_SUCCESS) {
-		status = serviceReference_getProperty(reference, "command.usage", (const char**)usage_pstr);
-	}
 
-	return status;
+    return status;
 }
 
-celix_status_t shell_getCommandDescription(shell_pt shell_ptr, char *command_name_str, char **command_description_pstr) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	service_reference_pt reference = NULL;
-
-	if (!shell_ptr || !command_name_str || !command_description_pstr) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
-
-	if (status == CELIX_SUCCESS) {
-		status = shell_getCommandReference(shell_ptr, command_name_str, &reference);
-		if (!reference) {
-			status = CELIX_BUNDLE_EXCEPTION;
-		}
-	}
+celix_status_t shell_getCommandDescription(shell_t *shell, const char *commandName, char **outDescription) {
+    celix_status_t status = CELIX_SUCCESS;
 
-	if (status == CELIX_SUCCESS) {
-		serviceReference_getProperty(reference, "command.description", (const char**)command_description_pstr);
-	}
+    celixThreadMutex_lock(&shell->mutex);
+    celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, commandName);
+    if (entry != NULL) {
+        const char *desc = celix_properties_get(entry->props, OSGI_SHELL_COMMAND_DESCRIPTION, "N/A");
+        *outDescription = strndup(desc, 1024*1024*10);
+    } else {
+        *outDescription = NULL;
+    }
+    celixThreadMutex_unlock(&shell->mutex);
 
-	return status;
+    return status;
 }
 
-celix_status_t shell_getCommandReference(shell_pt shell_ptr, char *command_name_str, service_reference_pt *command_reference_ptr) {
+celix_status_t shell_executeCommand(shell_t *shell, const char *commandLine, FILE *out, FILE *err) {
 	celix_status_t status = CELIX_SUCCESS;
 
-	if (!shell_ptr || !command_name_str || !command_reference_ptr) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
-
 	if (status == CELIX_SUCCESS) {
-		*command_reference_ptr = NULL;
-		hash_map_iterator_pt iter = hashMapIterator_create(shell_ptr->command_reference_map_ptr);
-		while (hashMapIterator_hasNext(iter)) {
-			hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
-			service_reference_pt reference = hashMapEntry_getKey(entry);
-			const char *name_str = NULL;
-			serviceReference_getProperty(reference, "command.name", &name_str);
-			if (strcmp(name_str, command_name_str) == 0) {
-				*command_reference_ptr = (service_reference_pt) hashMapEntry_getKey(entry);
-				break;
-			}
-		}
-		hashMapIterator_destroy(iter);
-	}
-
-	return status;
-}
-
-celix_status_t shell_executeCommand(shell_pt shell_ptr, char *command_line_str, FILE *out, FILE *err) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	command_service_pt command_ptr = NULL;
-
-	if (!shell_ptr || !command_line_str || !out || !err) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
+		size_t pos = strcspn(commandLine, " ");
 
-	if (status == CELIX_SUCCESS) {
-		size_t pos = strcspn(command_line_str, " ");
+		char *command_name_str = (pos != strlen(commandLine)) ? strndup(commandLine, pos) : strdup(commandLine);
 
-		char *command_name_str = (pos != strlen(command_line_str)) ? strndup(command_line_str, pos) : strdup(command_line_str);
-		command_ptr = hashMap_get(shell_ptr->command_name_map_ptr, command_name_str);
+        celixThreadMutex_lock(&shell->mutex);
+        celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, command_name_str);
+        if (entry == NULL) {
+            fprintf(err, "No such command\n");
+            status = CELIX_BUNDLE_EXCEPTION;
+        } else {
+            char * cl = (void*)commandLine; //NOTE needed because the shell command was written with char* instead of const char*
+            entry->svc->executeCommand(entry->svc->handle, cl, out, err);
+        }
+        celixThreadMutex_unlock(&shell->mutex);
 		free(command_name_str);
-		if (!command_ptr) {
-			fprintf(err, "No such command\n");
-			status = CELIX_BUNDLE_EXCEPTION;
-		}
-	}
 
-	if (status == CELIX_SUCCESS) {
-		status = command_ptr->executeCommand(command_ptr->handle, command_line_str, out, err);
 	}
 
 	return status;
diff --git a/bundles/shell/shell/src/shell_private.h b/bundles/shell/shell/src/shell_private.h
index c056bbd..b845ef1 100644
--- a/bundles/shell/shell/src/shell_private.h
+++ b/bundles/shell/shell/src/shell_private.h
@@ -33,19 +33,29 @@
 #include "command.h"
 #include "log_helper.h"
 
+typedef struct celix_shell_command_entry {
+    long svcId;
+    command_service_t *svc;
+    const celix_properties_t *props;
+} celix_shell_command_entry_t;
+
 struct shell {
-	bundle_context_pt bundle_context_ptr;
-	hash_map_pt command_reference_map_ptr;
-	hash_map_pt command_name_map_ptr;
-	log_helper_t *logHelper;
+	celix_bundle_context_t *ctx;
+    log_helper_t *logHelper;
+    celix_thread_mutex_t mutex; //protects below
+    hash_map_t *commandServices; //key = char* (command name), value = celix_shell_command_entry_t*
 };
+typedef struct shell shell_t;
+
+shell_t* shell_create(celix_bundle_context_t *ctx);
+void shell_destroy(shell_t *shell);
+celix_status_t shell_addCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props);
+celix_status_t shell_removeCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props);
 
-celix_status_t shell_create(bundle_context_pt context_ptr, shell_service_pt *shell_service_ptr);
-celix_status_t shell_destroy(shell_service_pt *shell_service_ptr);
-celix_status_t shell_addCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc);
-celix_status_t shell_removeCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc);
+celix_status_t shell_executeCommand(shell_t *shell, const char *commandLine, FILE *out, FILE *err);
 
-celix_status_t shell_getCommandReference(shell_pt shell_ptr, char *command_name_str, service_reference_pt *command_reference_ptr);
-celix_status_t shell_executeCommand(shell_pt shell_ptr, char *command_line_str, FILE *out, FILE *err);
+celix_status_t shell_getCommands(shell_t *shell, celix_array_list_t **commands);
+celix_status_t shell_getCommandUsage(shell_t *shell, const char *commandName, char **outUsage);
+celix_status_t shell_getCommandDescription(shell_t *shell, const char *commandName, char **outDescription);
 
 #endif /* SHELL_PRIVATE_H_ */
diff --git a/bundles/shell/shell/src/std_commands.h b/bundles/shell/shell/src/std_commands.h
index a0c66b4..ef15f93 100644
--- a/bundles/shell/shell/src/std_commands.h
+++ b/bundles/shell/shell/src/std_commands.h
@@ -31,7 +31,9 @@
 
 #define OSGI_SHELL_COMMAND_SEPARATOR " "
 
+//TODO update all char *command_line_str to const char *command_line_str
 celix_status_t lbCommand_execute(void *_ptr, char *command_line_str, FILE *out_ptr, FILE *err_ptr);
+celix_status_t queryCommand_execute(void *_ptr, char *command_line_str, FILE *out_ptr, FILE *err_ptr);
 celix_status_t startCommand_execute(void *_ptr, char* command_line_str, FILE *out_ptr, FILE *err_ptr);
 celix_status_t stopCommand_execute(void *handle, char* commandline, FILE *outStream, FILE *errStream);
 celix_status_t installCommand_execute(void *handle, char * commandline, FILE *outStream, FILE *errStream);
@@ -41,6 +43,7 @@ celix_status_t logCommand_execute(void *handle, char * commandline, FILE *outStr
 celix_status_t inspectCommand_execute(void *handle, char * commandline, FILE *outStream, FILE *errStream);
 celix_status_t helpCommand_execute(void *handle, char * commandline, FILE *outStream, FILE *errStream);
 celix_status_t dmListCommand_execute(void* handle, char * line, FILE *out, FILE *err);
+celix_status_t qCommand_execute(void *_ptr, char *command_line_str, FILE *sout, FILE *serr);
 
 
 #endif
diff --git a/bundles/shell/shell_tui/private/src/shell_tui.c b/bundles/shell/shell_tui/private/src/shell_tui.c
index bbb443d..57bd6d8 100644
--- a/bundles/shell/shell_tui/private/src/shell_tui.c
+++ b/bundles/shell/shell_tui/private/src/shell_tui.c
@@ -256,7 +256,7 @@ static void shellTui_parseInput(shell_tui_t* shellTui, shell_context_t* ctx) {
             celixThreadMutex_lock(&shellTui->mutex);
             if (shellTui->shell != NULL) {
                 printf("Providing command '%s' from in '%s'\n", line, in);
-                shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr);
+                shellTui->shell->executeCommand(shellTui->shell->handle, line, stdout, stderr);
             } else {
                 fprintf(stderr, "Shell service not available\n");
             }
@@ -379,7 +379,7 @@ static void shellTui_parseInputForControl(shell_tui_t* shellTui, shell_context_t
         historyLineReset(hist);
         celixThreadMutex_lock(&shellTui->mutex);
         if (shellTui->shell != NULL) {
-            shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr);
+            shellTui->shell->executeCommand(shellTui->shell->handle, line, stdout, stderr);
             pos = 0;
             nr_chars = 0;
         } else {
@@ -426,7 +426,7 @@ static void writeLine(const char* line, int pos) {
 static int autoComplete(shell_service_t* shellSvc, char *in, int cursorPos, size_t maxLen) {
 	array_list_pt commandList = NULL;
 	array_list_pt possibleCmdList = NULL;
-	shellSvc->getCommands(shellSvc->shell, &commandList);
+	shellSvc->getCommands(shellSvc->handle, &commandList);
 	int nrCmds = arrayList_size(commandList);
 	arrayList_create(&possibleCmdList);
 
@@ -446,7 +446,7 @@ static int autoComplete(shell_service_t* shellSvc, char *in, int cursorPos, size
 				if (strncmp(in, cmd, strlen(cmd)) == 0) {
 					clearLine();
 					char* usage = NULL;
-					shellSvc->getCommandUsage(shellSvc->shell, cmd, &usage);
+					shellSvc->getCommandUsage(shellSvc->handle, cmd, &usage);
 					printf("Usage:\n %s\n", usage);
 				}
 			}
diff --git a/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c b/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c
index 932509b..72d0f90 100644
--- a/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c
+++ b/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c
@@ -44,7 +44,7 @@ static void useShell(void *handle, void *svc) {
     char *buf = NULL;
     size_t size;
     FILE *out = open_memstream(&buf, &size);
-    shell->executeCommand(shell->shell, arg->command, out, out);
+    shell->executeCommand(shell->handle, arg->command, out, out);
     fclose(out);
     mg_websocket_write(arg->conn, MG_WEBSOCKET_OPCODE_TEXT, buf, size);
 };
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 1946eb8..0ad8364 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -131,6 +131,7 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
         private/mock/bundle_revision_mock.c
         private/mock/resolver_mock.c
         private/mock/version_mock.c
+        private/mock/service_registry_mock.c
         src/bundle.c
         src/celix_errorcodes.c
         private/mock/celix_log_mock.c)
diff --git a/libs/framework/include/celix_bundle.h b/libs/framework/include/celix_bundle.h
index bd12693..0b0dac4 100644
--- a/libs/framework/include/celix_bundle.h
+++ b/libs/framework/include/celix_bundle.h
@@ -54,11 +54,66 @@ celix_bundle_state_e celix_bundle_getState(const celix_bundle_t *bnd);
  */
 char* celix_bundle_getEntry(const celix_bundle_t* bnd, const char *path);
 
+/**
+ * Returns the group of the bundle. Groups are used to order bundles.
+ * Note the return value is valid as long as the bundle is installed.
+ */
 const char* celix_bundle_getGroup(const celix_bundle_t *bnd);
 
+/**
+ * Returns the symbolic name of the bundle.
+ * Note the return value is valid as long as the bundle is installed.
+ */
 const char* celix_bundle_getSymbolicName(const celix_bundle_t *bnd);
 
 
+typedef struct celix_bundle_service_list_entry {
+    long serviceId;
+    long bundleOwner;
+    char *serviceName;
+    celix_properties_t *serviceProperties;
+    bool factory;
+} celix_bundle_service_list_entry_t;
+
+/**
+ * Returns a array list of registered service info entries for this bundle.
+ *
+ * @param ctx       The bundle context
+ * @param bndId     The bundle id for which the services should be listed
+ * @return          A celix array list with celix_bundle_service_list_entry_t*. Caller is owner of the celix array.
+ */
+celix_array_list_t* celix_bundle_listRegisteredServices(const celix_bundle_t *bnd);
+
+/**
+ * Utils function to free memory for the return of a celix_bundle_listRegisteredServices call.
+ */
+void celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list);
+
+
+/**
+ * Service Tracker Info provided to the service tracker tracker callbacks.
+ */
+typedef struct celix_bundle_service_tracker_list_entry {
+    char* filter;;
+    long bundleOwner;
+} celix_bundle_service_tracker_list_entry_t;
+
+
+/**
+ * Returns a array list of service tracker info entries for this bundle.
+ *
+ * @param ctx       The bundle context
+ * @param bndId     The bundle id for which the services should be listed
+ * @return          A celix array list with celix_bundle_service_tracker_list_entry_t*. Caller is owner of the celix array.
+ */
+celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd);
+
+/**
+ * Utils function to free memory for the return of a celix_bundle_listServiceTrackers call.
+ */
+void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/include/service_registration.h b/libs/framework/include/service_registration.h
index 097001f..4a93ae9 100644
--- a/libs/framework/include/service_registration.h
+++ b/libs/framework/include/service_registration.h
@@ -48,6 +48,10 @@ serviceRegistration_getServiceName(service_registration_t *registration, const c
 FRAMEWORK_EXPORT long
 serviceRegistration_getServiceId(service_registration_t *registration);
 
+FRAMEWORK_EXPORT bool
+serviceRegistration_isFactoryService(service_registration_t *registration);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/include/service_registry.h b/libs/framework/include/service_registry.h
index 3373328..9f06f8a 100644
--- a/libs/framework/include/service_registry.h
+++ b/libs/framework/include/service_registry.h
@@ -16,13 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * service_registry.h
- *
- *  \date       Aug 6, 2010
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
+
 
 #ifndef SERVICE_REGISTRY_H_
 #define SERVICE_REGISTRY_H_
@@ -110,6 +104,29 @@ celix_serviceRegistry_registerServiceFactory(
         celix_properties_t* props,
         service_registration_t **registration);
 
+/**
+ * List the registered service for the provided bundle.
+ * @return A list of service ids. Caller is owner of the array list.
+ */
+celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId);
+
+/**
+ * Get service information for the provided svc id and bnd id.
+ *
+ * If the output pointers for serviceName and/or serviceProperties are provided these will get a copy of the registry
+ * value. The caller is owner of the serviceName/serviceProperties.
+ *
+ * Returns true if the bundle is found.
+ */
+bool celix_serviceRegistry_getServiceInfo(
+        celix_service_registry_t* registry,
+        long svcId,
+        long bndId,
+        char **serviceName,
+        celix_properties_t **serviceProperties,
+        bool *factory);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/private/mock/bundle_mock.c b/libs/framework/private/mock/bundle_mock.c
index 22bd18b..86382a4 100644
--- a/libs/framework/private/mock/bundle_mock.c
+++ b/libs/framework/private/mock/bundle_mock.c
@@ -297,5 +297,25 @@ celix_bundle_state_e celix_bundle_getState(const bundle_t *bnd) {
 	return (celix_bundle_state_e)mock_c()->returnValue().value.intValue;
 }
 
+celix_array_list_t* celix_bundle_listRegisteredServices(const celix_bundle_t *bnd) {
+    mock_c()->actualCall("celix_bundle_listRegisteredServices")
+            ->withConstPointerParameters("bnd", bnd);
+    return mock_c()->returnValue().value.pointerValue;
+}
+
+void celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list) {
+    mock_c()->actualCall("celix_bundle_destroyRegisteredServicesList")
+            ->withPointerParameters("list)", list);
+}
 
+celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd) {
+    mock_c()->actualCall("celix_bundle_listServiceTrackers")
+            ->withConstPointerParameters("bnd", bnd);
+    return mock_c()->returnValue().value.pointerValue;
+}
+
+void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list) {
+    mock_c()->actualCall("celix_bundle_destroyServiceTrackerList")
+            ->withPointerParameters("list", list);
+}
 
diff --git a/libs/framework/private/mock/service_registration_mock.c b/libs/framework/private/mock/service_registration_mock.c
index 8f141eb..02715ab 100644
--- a/libs/framework/private/mock/service_registration_mock.c
+++ b/libs/framework/private/mock/service_registration_mock.c
@@ -157,3 +157,8 @@ service_registration_t* celix_serviceRegistration_createServiceFactory(
 	return mock_c()->returnValue().value.pointerValue;
 }
 
+bool serviceRegistration_isFactoryService(service_registration_t *registration) {
+    mock_c()->actualCall("serviceRegistration_isFactoryService")
+            ->withPointerParameters("registration", registration);
+    return mock_c()->returnValue().value.boolValue;
+}
diff --git a/libs/framework/private/mock/service_registry_mock.c b/libs/framework/private/mock/service_registry_mock.c
index feb7f4a..767e507 100644
--- a/libs/framework/private/mock/service_registry_mock.c
+++ b/libs/framework/private/mock/service_registry_mock.c
@@ -24,6 +24,7 @@
  *  \copyright  Apache License, Version 2.0
  */
 
+#include <CppUTestExt/MockSupport_c.h>
 #include "CppUTestExt/MockSupport_c.h"
 
 #include "service_registry.h"
@@ -195,3 +196,27 @@ void serviceRegistry_callHooksForListenerFilter(
             ->withStringParameters("filter", filter)
             ->withBoolParameters("removed", removed);
 }
+
+bool celix_serviceRegistry_getServiceInfo(
+        celix_service_registry_t* registry,
+        long svcId,
+        long bndId,
+        char **outServiceName,
+        celix_properties_t **outServiceProperties,
+        bool *outIsFactory) {
+    mock_c()->actualCall("celix_serviceRegistry_getServiceInfo")
+        ->withPointerParameters("registry", registry)
+        ->withLongIntParameters("svcId", svcId)
+        ->withLongIntParameters("bndId", bndId)
+        ->withOutputParameter("outServiceName", outServiceName)
+        ->withOutputParameter("outServiceProperties", outServiceProperties)
+        ->withOutputParameter("outIsFactory", outIsFactory);
+    return mock_c()->returnValue().value.boolValue;
+}
+
+celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId) {
+    mock_c()->actualCall("celix_serviceRegistry_listServiceIdsForOwner")
+        ->withPointerParameters("registry", registry)
+        ->withLongIntParameters("bndId", bndId);
+    return mock_c()->returnValue().value.pointerValue;
+}
\ No newline at end of file
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c
index 251941e..89ac70d 100644
--- a/libs/framework/src/bundle.c
+++ b/libs/framework/src/bundle.c
@@ -19,12 +19,16 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <service_tracker.h>
 
 #include "framework_private.h"
 #include "bundle_private.h"
 #include "resolver.h"
 #include "utils.h"
 
+#include "bundle_context_private.h"
+#include "service_tracker_private.h"
+
 celix_status_t bundle_createModule(bundle_pt bundle, module_pt *module);
 celix_status_t bundle_closeRevisions(const_bundle_pt bundle);
 
@@ -637,3 +641,58 @@ const char* celix_bundle_getSymbolicName(const celix_bundle_t *bnd) {
 	}
 	return result;
 }
+
+celix_array_list_t* celix_bundle_listRegisteredServices(const celix_bundle_t *bnd) {
+    long bndId = celix_bundle_getId(bnd);
+    celix_array_list_t* result = celix_arrayList_create();
+    celix_array_list_t *svcIds = celix_serviceRegistry_listServiceIdsForOwner(bnd->framework->registry, bndId);
+    for (int i = 0; i < celix_arrayList_size(svcIds); ++i) {
+        long svcId = celix_arrayList_getLong(svcIds, i);
+        celix_bundle_service_list_entry_t* entry = calloc(1, sizeof(*entry));
+        entry->serviceId = svcId;
+        entry->bundleOwner = bndId;
+        celix_serviceRegistry_getServiceInfo(bnd->framework->registry, svcId, bndId, &entry->serviceName, &entry->serviceProperties, &entry->factory);
+        celix_arrayList_add(result, entry);
+    }
+    celix_arrayList_destroy(svcIds);
+    return result;
+}
+
+void celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list) {
+    if (list != NULL) {
+        for (int i = 0; i < celix_arrayList_size(list); ++i) {
+            celix_bundle_service_list_entry_t *entry = celix_arrayList_get(list, i);
+            free(entry->serviceName);
+            celix_properties_destroy(entry->serviceProperties);
+            free(entry);
+        }
+    }
+}
+
+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_t *serviceTrackers; //key = trackerId, value = celix_service_tracker_t*
+    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 = strndup(tracker->filter, 1024*1024*10);
+        entry->bundleOwner = celix_bundle_getId(bnd);
+        celix_arrayList_add(result, entry);
+    }
+    celixThreadMutex_unlock(&bnd->context->mutex);
+    return result;
+}
+
+
+void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list) {
+    if (list != NULL) {
+        for (int i = 0; i < celix_arrayList_size(list); ++i) {
+            celix_bundle_service_tracker_list_entry_t *entry = celix_arrayList_get(list, i);
+            free(entry->filter);
+            free(entry);
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 430781c..00683c0 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -59,7 +59,7 @@ celix_status_t bundleContext_create(framework_pt framework, framework_logger_pt
             arrayList_create(&context->svcRegistrations);
             context->bundleTrackers = hashMap_create(NULL,NULL,NULL,NULL);
             context->serviceTrackers = hashMap_create(NULL,NULL,NULL,NULL);
-            context->serviceTrackerTrackers =  hashMap_create(NULL,NULL,NULL,NULL);
+            context->metaTrackers =  hashMap_create(NULL,NULL,NULL,NULL);
             context->nextTrackerId = 1L;
 
             *bundle_context = context;
@@ -632,13 +632,13 @@ static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx) {
 }
 
 static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx) {
-    hash_map_iterator_t iter = hashMapIterator_construct(ctx->serviceTrackerTrackers);
+    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);
     }
-    hashMap_destroy(ctx->serviceTrackerTrackers, false, false);
+    hashMap_destroy(ctx->metaTrackers, false, false);
 }
 
 
@@ -656,9 +656,9 @@ void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) {
         } else if (hashMap_containsKey(ctx->serviceTrackers, (void*)trackerId)) {
             found = true;
             serviceTracker = hashMap_remove(ctx->serviceTrackers, (void*)trackerId);
-        } else if (hashMap_containsKey(ctx->serviceTrackerTrackers, (void*)trackerId)) {
+        } else if (hashMap_containsKey(ctx->metaTrackers, (void*)trackerId)) {
             found = true;
-            svcTrackerTracker = hashMap_remove(ctx->serviceTrackerTrackers, (void*)trackerId);
+            svcTrackerTracker = hashMap_remove(ctx->metaTrackers, (void*)trackerId);
         }
         celixThreadMutex_unlock(&ctx->mutex);
 
@@ -1016,7 +1016,7 @@ long celix_bundleContext_trackServiceTrackers(
     if (entry->hookReg != NULL) {
         celixThreadMutex_lock(&ctx->mutex);
         entry->trackerId = ctx->nextTrackerId++;
-        hashMap_put(ctx->serviceTrackerTrackers, (void*)entry->trackerId, entry);
+        hashMap_put(ctx->metaTrackers, (void*)entry->trackerId, entry);
         trackerId = entry->trackerId;
         celixThreadMutex_unlock(&ctx->mutex);
     } else {
diff --git a/libs/framework/src/bundle_context_private.h b/libs/framework/src/bundle_context_private.h
index d9e8d9d..e3b7619 100644
--- a/libs/framework/src/bundle_context_private.h
+++ b/libs/framework/src/bundle_context_private.h
@@ -49,13 +49,13 @@ struct celix_bundle_context {
 	celix_framework_t *framework;
 	celix_bundle_t *bundle;
 
-	celix_thread_mutex_t mutex; //protects fields below
+	celix_thread_mutex_t mutex; //protects fields below (NOTE/FIXME also used by bundle.c for listing service tracker usage)
 	array_list_t *svcRegistrations;
 	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 *serviceTrackerTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_tracker_entry_t*
+	hash_map_t *metaTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_tracker_entry_t*
 };
 
 
diff --git a/libs/framework/src/service_registration.c b/libs/framework/src/service_registration.c
index 967f107..49f60c8 100644
--- a/libs/framework/src/service_registration.c
+++ b/libs/framework/src/service_registration.c
@@ -16,13 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * service_registration.c
- *
- *  \date       Aug 6, 2010
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -312,4 +305,14 @@ service_registration_t* celix_serviceRegistration_createServiceFactory(
     service_registration_pt registration = NULL;
     serviceRegistration_createInternal(callback, (celix_bundle_t*)bnd, serviceName, svcId, factory, props, CELIX_FACTORY_SERVICE, &registration);
     return registration;
+}
+
+bool serviceRegistration_isFactoryService(service_registration_t *registration) {
+    bool isFactory = false;
+    if (registration != NULL) {
+        celixThreadRwlock_readLock(&registration->lock);
+        isFactory = registration->svcType = CELIX_FACTORY_SERVICE || registration->svcType == CELIX_DEPRECATED_FACTORY_SERVICE;
+        celixThreadRwlock_unlock(&registration->lock);
+    }
+    return isFactory;
 }
\ No newline at end of file
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index accd7b6..bf2a68b 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -916,4 +916,59 @@ static void celix_decreaseCountHook(celix_service_registry_listener_hook_entry_t
         celixThreadCondition_broadcast(&entry->cond);
         celixThreadMutex_unlock(&entry->mutex);
     }
+}
+
+celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId) {
+    celix_array_list_t *result = celix_arrayList_create();
+    celixThreadRwlock_readLock(&registry->lock);
+    celix_bundle_t *bundle = framework_getBundleById(registry->framework, bndId);
+    celix_array_list_t *registrations = bundle != NULL ? hashMap_get(registry->serviceRegistrations, bundle) : NULL;
+    if (registrations != NULL) {
+        for (int i = 0; i < celix_arrayList_size(registrations); ++i) {
+            service_registration_t *reg = celix_arrayList_get(registrations, i);
+            long svcId = serviceRegistration_getServiceId(reg);
+            celix_arrayList_addLong(result, svcId);
+        }
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+    return result;
+}
+
+bool celix_serviceRegistry_getServiceInfo(
+        celix_service_registry_t* registry,
+        long svcId,
+        long bndId,
+        char **outServiceName,
+        celix_properties_t **outServiceProperties,
+        bool *outIsFactory) {
+    bool found = false;
+
+    celixThreadRwlock_readLock(&registry->lock);
+    celix_bundle_t *bundle = framework_getBundleById(registry->framework, bndId);
+    celix_array_list_t *registrations = bundle != NULL ? hashMap_get(registry->serviceRegistrations, bundle) : NULL;
+    if (registrations != NULL) {
+        for (int i = 0; i < celix_arrayList_size(registrations); ++i) {
+            service_registration_t *reg = celix_arrayList_get(registrations, i);
+            if (svcId == serviceRegistration_getServiceId(reg)) {
+                found = true;
+                if (outServiceName != NULL) {
+                    const char *s = NULL;
+                    serviceRegistration_getServiceName(reg, &s);
+                    *outServiceName = strndup(s, 1024 * 1024 * 10);
+                }
+                if (outServiceProperties != NULL) {
+                    celix_properties_t *p = NULL;
+                    serviceRegistration_getProperties(reg, &p);
+                    *outServiceProperties = celix_properties_copy(p);
+                }
+                if (outIsFactory != NULL) {
+                    *outIsFactory = serviceRegistration_isFactoryService(reg);
+                }
+                break;
+            }
+        }
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    return found;
 }
\ No newline at end of file
diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c
index 2dc0bba..9b24de8 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -52,14 +52,17 @@ static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracke
 static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance);
 static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t *instance);
 
-static celix_thread_once_t g_once = CELIX_THREAD_ONCE_INIT;
-static celix_thread_mutex_t g_mutex;
-static celix_thread_cond_t g_cond;
+static celix_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_mutex, NULL);
-    celixThreadCondition_init(&g_cond, NULL);
+    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) {
@@ -933,7 +936,7 @@ void celix_serviceTracker_useServices(
 
 void celix_serviceTracker_syncForFramework(void *fw) {
     celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_mutex);
+    celixThreadMutex_lock(&g_shutdownMutex);
     size_t count = 0;
     do {
         count = 0;
@@ -946,7 +949,7 @@ void celix_serviceTracker_syncForFramework(void *fw) {
             }
         }
         if (count > 0) {
-            pthread_cond_wait(&g_cond, &g_mutex);
+            pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex);
         }
     } while (count > 0);
 
@@ -954,12 +957,12 @@ void celix_serviceTracker_syncForFramework(void *fw) {
         celix_arrayList_destroy(g_shutdownInstances);
         g_shutdownInstances = NULL;
     }
-    celixThreadMutex_unlock(&g_mutex);
+    celixThreadMutex_unlock(&g_shutdownMutex);
 }
 
 void celix_serviceTracker_syncForContext(void *ctx) {
     celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_mutex);
+    celixThreadMutex_lock(&g_shutdownMutex);
     size_t count;
     do {
         count = 0;
@@ -972,7 +975,7 @@ void celix_serviceTracker_syncForContext(void *ctx) {
             }
         }
         if (count > 0) {
-            pthread_cond_wait(&g_cond, &g_mutex);
+            pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex);
         }
     } while (count > 0);
 
@@ -980,22 +983,22 @@ void celix_serviceTracker_syncForContext(void *ctx) {
         celix_arrayList_destroy(g_shutdownInstances);
         g_shutdownInstances = NULL;
     }
-    celixThreadMutex_unlock(&g_mutex);
+    celixThreadMutex_unlock(&g_shutdownMutex);
 }
 
 static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance) {
     celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_mutex);
+    celixThreadMutex_lock(&g_shutdownMutex);
     if (g_shutdownInstances == NULL) {
         g_shutdownInstances = celix_arrayList_create();
     }
     celix_arrayList_add(g_shutdownInstances, instance);
-    celixThreadMutex_unlock(&g_mutex);
+    celixThreadMutex_unlock(&g_shutdownMutex);
 }
 
 static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t *instance) {
     celixThread_once(&g_once, serviceTracker_once);
-    celixThreadMutex_lock(&g_mutex);
+    celixThreadMutex_lock(&g_shutdownMutex);
     if (g_shutdownInstances != NULL) {
         size_t size = celix_arrayList_size(g_shutdownInstances);
         for (size_t i = 0; i < size; ++i) {
@@ -1008,7 +1011,7 @@ static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_ins
             celix_arrayList_destroy(g_shutdownInstances);
             g_shutdownInstances = NULL;
         }
-        celixThreadCondition_broadcast(&g_cond);
+        celixThreadCondition_broadcast(&g_shutdownCond);
     }
-    celixThreadMutex_unlock(&g_mutex);
+    celixThreadMutex_unlock(&g_shutdownMutex);
 }