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 2019/05/28 18:06:35 UTC

[celix] branch develop updated: CELIX-459: Fixes a potentional memory leak in zmq.

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 6ed5c4a  CELIX-459: Fixes a potentional memory leak in zmq.
6ed5c4a is described below

commit 6ed5c4a0e9bea853e314bd09c789db353b092100
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Tue May 28 20:05:52 2019 +0200

    CELIX-459: Fixes a potentional memory leak in zmq.
    
    Also refactors the log_writer / help command
---
 bundles/CMakeLists.txt                             |   3 +-
 bundles/deployment_admin/CMakeLists.txt            |   1 +
 bundles/log_writer/log_writer/include/log_writer.h |  53 ---------
 bundles/log_writer/log_writer/src/log_writer.c     | 122 -------------------
 .../log_writer/src/log_writer_activator.c          |  57 ---------
 bundles/{ => logging}/CMakeLists.txt               |   8 +-
 bundles/{ => logging}/log_service/CMakeLists.txt   |   0
 bundles/{ => logging}/log_service/README.md        |   0
 .../{ => logging}/log_service/include/log_entry.h  |   8 +-
 .../log_service/include/log_listener.h             |  12 +-
 .../log_service/include/log_reader_service.h       |  12 +-
 .../log_service/include/log_service.h              |   8 +-
 .../log_service/loghelper_include/log_helper.h     |   0
 bundles/{ => logging}/log_service/src/log.c        |   0
 bundles/{ => logging}/log_service/src/log.h        |   0
 bundles/{ => logging}/log_service/src/log_entry.c  |   0
 .../{ => logging}/log_service/src/log_factory.c    |   0
 .../{ => logging}/log_service/src/log_factory.h    |   0
 bundles/{ => logging}/log_service/src/log_helper.c |   0
 .../log_service/src/log_reader_service_impl.c      |   0
 .../log_service/src/log_reader_service_impl.h      |   0
 .../log_service/src/log_service_activator.c        |   0
 .../log_service/src/log_service_impl.c             |   0
 .../log_service/src/log_service_impl.h             |   0
 bundles/{ => logging}/log_writer/CMakeLists.txt    |   0
 bundles/{ => logging}/log_writer/README.md         |   0
 .../log_writer/log_writer/CMakeLists.txt           |   2 +-
 .../log_writer/include/celix_log_writer.h}         |  28 ++---
 .../log_writer/src/log_writer_activator.c          |  66 +++++++++++
 .../log_writer/log_writer_stdout/CMakeLists.txt    |   0
 .../log_writer_stdout/src/log_writer_stdout.c      |  19 +--
 .../log_writer/log_writer_syslog/CMakeLists.txt    |   0
 .../private/src/log_writer_syslog.c                |  18 +--
 bundles/pubsub/examples/CMakeLists.txt             |  11 +-
 .../pubsub_admin_zmq/src/pubsub_zmq_topic_sender.c |  57 ++++++---
 .../pubsub_discovery/src/pubsub_discovery_impl.c   |  10 +-
 bundles/pubsub/test/CMakeLists.txt                 |  20 ++++
 bundles/shell/shell/src/help_command.c             | 131 ++++++++++-----------
 cmake/cmake_celix/ContainerPackaging.cmake         |  10 +-
 cmake/cmake_celix/Runtimes.cmake                   |   4 +-
 libs/framework/src/service_registry.c              |   2 +-
 41 files changed, 246 insertions(+), 416 deletions(-)

diff --git a/bundles/CMakeLists.txt b/bundles/CMakeLists.txt
index 5ed4054..42baf25 100644
--- a/bundles/CMakeLists.txt
+++ b/bundles/CMakeLists.txt
@@ -20,6 +20,5 @@ add_subdirectory(device_access)
 add_subdirectory(deployment_admin)
 add_subdirectory(remote_services)
 add_subdirectory(shell)
-add_subdirectory(log_writer)
-add_subdirectory(log_service)
+add_subdirectory(logging)
 add_subdirectory(pubsub)
\ No newline at end of file
diff --git a/bundles/deployment_admin/CMakeLists.txt b/bundles/deployment_admin/CMakeLists.txt
index 9364fea..25286b7 100644
--- a/bundles/deployment_admin/CMakeLists.txt
+++ b/bundles/deployment_admin/CMakeLists.txt
@@ -51,6 +51,7 @@ if (DEPLOYMENT_ADMIN)
 
     target_compile_definitions(deployment_admin PRIVATE -DUSE_FILE32API)
     target_link_libraries(deployment_admin PRIVATE ${CURL_LIBRARIES} ${UUID_LIBRARY} ${ZLIB_LIBRARIES} deployment_admin_api)
+    target_include_directories(deployment_admin PRIVATE ${CURL_INCLUDE_DIRS})
 
     install(TARGETS deployment_admin_api EXPORT celix COMPONENT deployment_admin)
     install(DIRECTORY api/ DESTINATION include/celix/deployment_admin COMPONENT deployment_admin)
diff --git a/bundles/log_writer/log_writer/include/log_writer.h b/bundles/log_writer/log_writer/include/log_writer.h
deleted file mode 100644
index b4b70d0..0000000
--- a/bundles/log_writer/log_writer/include/log_writer.h
+++ /dev/null
@@ -1,53 +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.
- */
-/*
- * log_writer.h
- *
- *  \date       Jul 4, 2011
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-
-#ifndef LOG_WRITER_H_
-#define LOG_WRITER_H_
-
-#include "log_reader_service.h"
-#include "service_tracker.h"
-
-struct log_writer {
-    log_reader_service_pt logReader;
-    log_listener_pt logListener;
-
-    bundle_context_pt context;
-    service_tracker_pt tracker;
-};
-
-typedef struct log_writer *log_writer_pt;
-
-celix_status_t logWriter_create(bundle_context_pt context, log_writer_pt *writer);
-celix_status_t logWriter_destroy(log_writer_pt *writer);
-celix_status_t logWriter_start(log_writer_pt writer);
-celix_status_t logWriter_stop(log_writer_pt writer);
-
-celix_status_t logWriter_addingServ(void * handle, service_reference_pt ref, void **service);
-celix_status_t logWriter_addedServ(void * handle, service_reference_pt ref, void * service);
-celix_status_t logWriter_modifiedServ(void * handle, service_reference_pt ref, void * service);
-celix_status_t logWriter_removedServ(void * handle, service_reference_pt ref, void * service);
-
-#endif /* LOG_WRITER_H_ */
diff --git a/bundles/log_writer/log_writer/src/log_writer.c b/bundles/log_writer/log_writer/src/log_writer.c
deleted file mode 100644
index 685c1a5..0000000
--- a/bundles/log_writer/log_writer/src/log_writer.c
+++ /dev/null
@@ -1,122 +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.
- */
-/*
- * log_writer.c
- *
- *  \date       Mar 7, 2011
- *  \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>
-
-#include "celix_errno.h"
-#include "celixbool.h"
-
-#include "log_writer.h"
-#include "log_listener.h"
-#include "module.h"
-#include "bundle.h"
-
-celix_status_t logWriter_create(bundle_context_pt context, log_writer_pt *writer) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	*writer = calloc(1, sizeof(**writer));
-	(*writer)->logListener = calloc(1, sizeof(*(*writer)->logListener));
-	(*writer)->logListener->handle = *writer;
-	(*writer)->logListener->logged = logListener_logged;
-	(*writer)->logReader = NULL;
-	(*writer)->context = context;
-	(*writer)->tracker = NULL;
-
-	return status;
-}
-
-
-celix_status_t logWriter_destroy(log_writer_pt *writer) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	free((*writer)->logListener);
-	free(*writer);
-
-	writer = NULL;
-
-	return status;
-}
-celix_status_t logWriter_start(log_writer_pt writer) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	service_tracker_customizer_pt cust = NULL;
-	service_tracker_pt tracker = NULL;
-
-	status = serviceTrackerCustomizer_create(writer, logWriter_addingServ, logWriter_addedServ, logWriter_modifiedServ, logWriter_removedServ, &cust);
-	if (status == CELIX_SUCCESS) {
-		status = serviceTracker_create(writer->context, (char *) OSGI_LOGSERVICE_READER_SERVICE_NAME, cust, &tracker);
-		if (status == CELIX_SUCCESS) {
-			writer->tracker = tracker;
-			status = serviceTracker_open(tracker);
-		}
-	}
-
-	return status;
-}
-
-celix_status_t logWriter_stop(log_writer_pt writer) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	if (serviceTracker_close(writer->tracker) != CELIX_SUCCESS) {
-		status = CELIX_BUNDLE_EXCEPTION;
-	}
-	if (serviceTracker_destroy(writer->tracker) != CELIX_SUCCESS) {
-		status = CELIX_BUNDLE_EXCEPTION;
-	}
-
-	return status;
-}
-
-celix_status_t logWriter_addingServ(void * handle, service_reference_pt ref, void **service) {
-	log_writer_pt writer = (log_writer_pt) handle;
-	bundleContext_getService(writer->context, ref, service);
-	return CELIX_SUCCESS;
-}
-
-celix_status_t logWriter_addedServ(void * handle, service_reference_pt ref, void * service) {
-	log_writer_pt writer = (log_writer_pt) handle;
-
-	// Add this writer to each log reader service found
-	if (service != NULL) {
-		((log_reader_service_pt) service)->addLogListener(((log_reader_service_pt) service)->reader, writer->logListener);
-	}
-
-	return CELIX_SUCCESS;
-}
-
-celix_status_t logWriter_modifiedServ(void * handle, service_reference_pt ref, void * service) {
-	return CELIX_SUCCESS;
-}
-
-celix_status_t logWriter_removedServ(void * handle, service_reference_pt ref, void * service) {
-	log_writer_pt writer = (log_writer_pt) handle;
-
-	if (service != NULL) {
-		((log_reader_service_pt) service)->removeLogListener(((log_reader_service_pt) service)->reader, writer->logListener);
-	}
-
-	return CELIX_SUCCESS;
-}
diff --git a/bundles/log_writer/log_writer/src/log_writer_activator.c b/bundles/log_writer/log_writer/src/log_writer_activator.c
deleted file mode 100644
index 248cad6..0000000
--- a/bundles/log_writer/log_writer/src/log_writer_activator.c
+++ /dev/null
@@ -1,57 +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.
- */
-/*
- * log_writer_activator.c
- *
- *  \date       Oct 1, 2013
- *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright  Apache License, Version 2.0
- */
-
-#include "log_writer.h"
-
-#include "bundle_activator.h"
-
-celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
-	log_writer_pt writer = NULL;
-
-	logWriter_create(context, &writer);
-
-	*userData = writer;
-
-	return CELIX_SUCCESS;
-}
-
-celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
-	log_writer_pt writer = (log_writer_pt) userData;
-
-	return logWriter_start(writer);
-}
-
-celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
-	log_writer_pt writer = (log_writer_pt) userData;
-
-	return logWriter_stop(writer);
-}
-
-celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
-	log_writer_pt writer = (log_writer_pt) userData;
-
-	return logWriter_destroy(&writer);
-}
diff --git a/bundles/CMakeLists.txt b/bundles/logging/CMakeLists.txt
similarity index 79%
copy from bundles/CMakeLists.txt
copy to bundles/logging/CMakeLists.txt
index 5ed4054..6175ead 100644
--- a/bundles/CMakeLists.txt
+++ b/bundles/logging/CMakeLists.txt
@@ -15,11 +15,5 @@
 # specific language governing permissions and limitations
 # under the License.
 
-add_subdirectory(config_admin)
-add_subdirectory(device_access)
-add_subdirectory(deployment_admin)
-add_subdirectory(remote_services)
-add_subdirectory(shell)
 add_subdirectory(log_writer)
-add_subdirectory(log_service)
-add_subdirectory(pubsub)
\ No newline at end of file
+add_subdirectory(log_service)
\ No newline at end of file
diff --git a/bundles/log_service/CMakeLists.txt b/bundles/logging/log_service/CMakeLists.txt
similarity index 100%
rename from bundles/log_service/CMakeLists.txt
rename to bundles/logging/log_service/CMakeLists.txt
diff --git a/bundles/log_service/README.md b/bundles/logging/log_service/README.md
similarity index 100%
rename from bundles/log_service/README.md
rename to bundles/logging/log_service/README.md
diff --git a/bundles/log_service/include/log_entry.h b/bundles/logging/log_service/include/log_entry.h
similarity index 90%
rename from bundles/log_service/include/log_entry.h
rename to bundles/logging/log_service/include/log_entry.h
index e588774..ea12500 100644
--- a/bundles/log_service/include/log_entry.h
+++ b/bundles/logging/log_service/include/log_entry.h
@@ -16,13 +16,6 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * log_entry.h
- *
- *  \date       Jun 26, 2011
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
 #ifndef LOG_ENTRY_H_
 #define LOG_ENTRY_H_
@@ -40,6 +33,7 @@ struct log_entry {
 };
 
 typedef struct log_entry * log_entry_pt;
+typedef struct log_entry log_entry_t;
 
 celix_status_t logEntry_create(long bundleId, const char* bundleSymbolicName , service_reference_pt reference,
         log_level_t level, char *message, int errorCode,
diff --git a/bundles/log_service/include/log_listener.h b/bundles/logging/log_service/include/log_listener.h
similarity index 72%
copy from bundles/log_service/include/log_listener.h
copy to bundles/logging/log_service/include/log_listener.h
index b726994..2f02300 100644
--- a/bundles/log_service/include/log_listener.h
+++ b/bundles/logging/log_service/include/log_listener.h
@@ -16,13 +16,6 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * log_listener.h
- *
- *  \date       Jul 4, 2011
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
 #ifndef LOG_LISTENER_H_
 #define LOG_LISTENER_H_
@@ -32,12 +25,11 @@
 
 struct log_listener {
     void *handle;
-    celix_status_t (*logged)(struct log_listener *listener, log_entry_pt entry);
+    celix_status_t (*logged)(void *handle, log_entry_t *entry);
 };
 
 typedef struct log_listener log_listener_t;
-typedef log_listener_t* log_listener_pt;
+typedef struct log_listener *log_listener_pt;
 
-celix_status_t logListener_logged(log_listener_pt listener, log_entry_pt entry);
 
 #endif /* LOG_LISTENER_H_ */
diff --git a/bundles/log_service/include/log_reader_service.h b/bundles/logging/log_service/include/log_reader_service.h
similarity index 86%
rename from bundles/log_service/include/log_reader_service.h
rename to bundles/logging/log_service/include/log_reader_service.h
index 6815123..37624ae 100644
--- a/bundles/log_service/include/log_reader_service.h
+++ b/bundles/logging/log_service/include/log_reader_service.h
@@ -16,13 +16,6 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * log_reader_service.h
- *
- *  \date       Jun 26, 2011
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
 #ifndef LOG_READER_SERVICE_H_
 #define LOG_READER_SERVICE_H_
@@ -40,11 +33,12 @@ typedef log_reader_data_t* log_reader_data_pt;
 struct log_reader_service {
     log_reader_data_pt reader;
     celix_status_t (*getLog)(log_reader_data_pt reader, linked_list_pt *list);
-    celix_status_t (*addLogListener)(log_reader_data_pt reader, log_listener_pt listener);
-    celix_status_t (*removeLogListener)(log_reader_data_pt reader, log_listener_pt listener);
+    celix_status_t (*addLogListener)(log_reader_data_pt reader, log_listener_t *listener);
+    celix_status_t (*removeLogListener)(log_reader_data_pt reader, log_listener_t *listener);
     celix_status_t (*removeAllLogListener)(log_reader_data_pt reader);
 };
 
 typedef struct log_reader_service * log_reader_service_pt;
+typedef struct log_reader_service log_reader_service_t;
 
 #endif /* LOG_READER_SERVICE_H_ */
diff --git a/bundles/log_service/include/log_service.h b/bundles/logging/log_service/include/log_service.h
similarity index 89%
rename from bundles/log_service/include/log_service.h
rename to bundles/logging/log_service/include/log_service.h
index 2691e35..51073e9 100644
--- a/bundles/log_service/include/log_service.h
+++ b/bundles/logging/log_service/include/log_service.h
@@ -16,13 +16,7 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * log_service.h
- *
- *  \date       Jun 22, 2011
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
+
 
 #ifndef LOG_SERVICE_H_
 #define LOG_SERVICE_H_
diff --git a/bundles/log_service/loghelper_include/log_helper.h b/bundles/logging/log_service/loghelper_include/log_helper.h
similarity index 100%
rename from bundles/log_service/loghelper_include/log_helper.h
rename to bundles/logging/log_service/loghelper_include/log_helper.h
diff --git a/bundles/log_service/src/log.c b/bundles/logging/log_service/src/log.c
similarity index 100%
rename from bundles/log_service/src/log.c
rename to bundles/logging/log_service/src/log.c
diff --git a/bundles/log_service/src/log.h b/bundles/logging/log_service/src/log.h
similarity index 100%
rename from bundles/log_service/src/log.h
rename to bundles/logging/log_service/src/log.h
diff --git a/bundles/log_service/src/log_entry.c b/bundles/logging/log_service/src/log_entry.c
similarity index 100%
rename from bundles/log_service/src/log_entry.c
rename to bundles/logging/log_service/src/log_entry.c
diff --git a/bundles/log_service/src/log_factory.c b/bundles/logging/log_service/src/log_factory.c
similarity index 100%
rename from bundles/log_service/src/log_factory.c
rename to bundles/logging/log_service/src/log_factory.c
diff --git a/bundles/log_service/src/log_factory.h b/bundles/logging/log_service/src/log_factory.h
similarity index 100%
rename from bundles/log_service/src/log_factory.h
rename to bundles/logging/log_service/src/log_factory.h
diff --git a/bundles/log_service/src/log_helper.c b/bundles/logging/log_service/src/log_helper.c
similarity index 100%
rename from bundles/log_service/src/log_helper.c
rename to bundles/logging/log_service/src/log_helper.c
diff --git a/bundles/log_service/src/log_reader_service_impl.c b/bundles/logging/log_service/src/log_reader_service_impl.c
similarity index 100%
rename from bundles/log_service/src/log_reader_service_impl.c
rename to bundles/logging/log_service/src/log_reader_service_impl.c
diff --git a/bundles/log_service/src/log_reader_service_impl.h b/bundles/logging/log_service/src/log_reader_service_impl.h
similarity index 100%
rename from bundles/log_service/src/log_reader_service_impl.h
rename to bundles/logging/log_service/src/log_reader_service_impl.h
diff --git a/bundles/log_service/src/log_service_activator.c b/bundles/logging/log_service/src/log_service_activator.c
similarity index 100%
rename from bundles/log_service/src/log_service_activator.c
rename to bundles/logging/log_service/src/log_service_activator.c
diff --git a/bundles/log_service/src/log_service_impl.c b/bundles/logging/log_service/src/log_service_impl.c
similarity index 100%
rename from bundles/log_service/src/log_service_impl.c
rename to bundles/logging/log_service/src/log_service_impl.c
diff --git a/bundles/log_service/src/log_service_impl.h b/bundles/logging/log_service/src/log_service_impl.h
similarity index 100%
rename from bundles/log_service/src/log_service_impl.h
rename to bundles/logging/log_service/src/log_service_impl.h
diff --git a/bundles/log_writer/CMakeLists.txt b/bundles/logging/log_writer/CMakeLists.txt
similarity index 100%
rename from bundles/log_writer/CMakeLists.txt
rename to bundles/logging/log_writer/CMakeLists.txt
diff --git a/bundles/log_writer/README.md b/bundles/logging/log_writer/README.md
similarity index 100%
rename from bundles/log_writer/README.md
rename to bundles/logging/log_writer/README.md
diff --git a/bundles/log_writer/log_writer/CMakeLists.txt b/bundles/logging/log_writer/log_writer/CMakeLists.txt
similarity index 98%
rename from bundles/log_writer/log_writer/CMakeLists.txt
rename to bundles/logging/log_writer/log_writer/CMakeLists.txt
index cc6b8eb..40442f7 100644
--- a/bundles/log_writer/log_writer/CMakeLists.txt
+++ b/bundles/logging/log_writer/log_writer/CMakeLists.txt
@@ -16,9 +16,9 @@
 # under the License.
 
 add_library(log_writer_common STATIC
-		src/log_writer.c
 		src/log_writer_activator.c
 )
 target_include_directories(log_writer_common PRIVATE src)
 target_include_directories(log_writer_common PUBLIC include)
 target_link_libraries(log_writer_common PUBLIC Celix::log_service_api Celix::framework)
+
diff --git a/bundles/log_service/include/log_listener.h b/bundles/logging/log_writer/log_writer/include/celix_log_writer.h
similarity index 57%
rename from bundles/log_service/include/log_listener.h
rename to bundles/logging/log_writer/log_writer/include/celix_log_writer.h
index b726994..3667caa 100644
--- a/bundles/log_service/include/log_listener.h
+++ b/bundles/logging/log_writer/log_writer/include/celix_log_writer.h
@@ -16,28 +16,18 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * log_listener.h
- *
- *  \date       Jul 4, 2011
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
-#ifndef LOG_LISTENER_H_
-#define LOG_LISTENER_H_
+#ifndef CELIX_LOG_WRITER_H_
+#define CELIX_LOG_WRITER_H_
 
-#include "log_entry.h"
-#include "celix_errno.h"
 
-struct log_listener {
-    void *handle;
-    celix_status_t (*logged)(struct log_listener *listener, log_entry_pt entry);
-};
+#include "celix_api.h"
+#include "log_listener.h"
 
-typedef struct log_listener log_listener_t;
-typedef log_listener_t* log_listener_pt;
+typedef struct celix_log_writer celix_log_writer_t; //opaque pointer
 
-celix_status_t logListener_logged(log_listener_pt listener, log_entry_pt entry);
+celix_log_writer_t* celix_logWriter_create(celix_bundle_context_t *ctx);
+void celix_logWriter_destroy(celix_log_writer_t *writer);
+celix_status_t celix_logWriter_logged(celix_log_writer_t *writer, log_entry_t *entry);
 
-#endif /* LOG_LISTENER_H_ */
+#endif /* CELIX_LOG_WRITER_H_ */
diff --git a/bundles/logging/log_writer/log_writer/src/log_writer_activator.c b/bundles/logging/log_writer/log_writer/src/log_writer_activator.c
new file mode 100644
index 0000000..8652e47
--- /dev/null
+++ b/bundles/logging/log_writer/log_writer/src/log_writer_activator.c
@@ -0,0 +1,66 @@
+/**
+ *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 "log_reader_service.h"
+#include "log_listener.h"
+#include "celix_api.h"
+#include "celix_log_writer.h"
+
+typedef struct celix_logwriter_activator {
+    celix_log_writer_t *writer;
+	long svcTracker;
+	log_listener_t *listener;
+} celix_logwriter_activator_t;
+
+static void addSvc(void *handle, void *svc) {
+    celix_logwriter_activator_t *act = handle;
+	log_reader_service_t *reader = svc;
+	reader->addLogListener(reader->reader, act->listener);
+}
+
+static void remSvc(void *handle, void *svc) {
+    celix_logwriter_activator_t *act = handle;
+	log_reader_service_t *reader = svc;
+    reader->removeLogListener(reader->reader, act->listener);
+}
+
+static celix_status_t logWriterActivator_start(celix_logwriter_activator_t *act, celix_bundle_context_t *ctx) {
+    act->writer = celix_logWriter_create(ctx);
+	act->listener->handle = act->writer;
+	act->listener->logged = (void*)celix_logWriter_logged;
+	act->svcTracker = -1L;
+	if (act->writer != NULL) {
+		celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+		opts.filter.serviceName = OSGI_LOGSERVICE_READER_SERVICE_NAME;
+		opts.callbackHandle = act;
+		opts.add = addSvc;
+		opts.remove = remSvc;
+		act->svcTracker = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+	}
+	return CELIX_SUCCESS;
+}
+
+static celix_status_t logWriterActivator_stop(celix_logwriter_activator_t *act, celix_bundle_context_t *ctx) {
+	celix_bundleContext_stopTracker(ctx, act->svcTracker);
+	celix_logWriter_destroy(act->writer);
+	return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(celix_logwriter_activator_t, logWriterActivator_start, logWriterActivator_stop);
diff --git a/bundles/log_writer/log_writer_stdout/CMakeLists.txt b/bundles/logging/log_writer/log_writer_stdout/CMakeLists.txt
similarity index 100%
rename from bundles/log_writer/log_writer_stdout/CMakeLists.txt
rename to bundles/logging/log_writer/log_writer_stdout/CMakeLists.txt
diff --git a/bundles/log_writer/log_writer_stdout/src/log_writer_stdout.c b/bundles/logging/log_writer/log_writer_stdout/src/log_writer_stdout.c
similarity index 75%
rename from bundles/log_writer/log_writer_stdout/src/log_writer_stdout.c
rename to bundles/logging/log_writer/log_writer_stdout/src/log_writer_stdout.c
index d57e5d5..7c63b6b 100644
--- a/bundles/log_writer/log_writer_stdout/src/log_writer_stdout.c
+++ b/bundles/logging/log_writer/log_writer_stdout/src/log_writer_stdout.c
@@ -16,26 +16,27 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * log_writer_stdout.c
- *
- *  \date       Mar 7, 2011
- *  \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>
 
 #include "celix_errno.h"
 #include "celixbool.h"
 
-#include "log_writer.h"
+#include "celix_log_writer.h"
 #include "log_listener.h"
 
 #include "module.h"
 #include "bundle.h"
 
-celix_status_t logListener_logged(log_listener_pt listener, log_entry_pt entry) {
+struct celix_log_writer {
+    //empty
+};
+
+celix_log_writer_t* celix_logWriter_create(celix_bundle_context_t *ctx __attribute__((unused))) { return NULL; }
+void celix_logWriter_destroy(celix_log_writer_t *writer __attribute__((unused))) {/*nop*/}
+celix_status_t celix_logWriter_logged(celix_log_writer_t *writer __attribute__((unused)), log_entry_t *entry) {
+
 	celix_status_t status = CELIX_SUCCESS;
 
     if (!entry) {
diff --git a/bundles/log_writer/log_writer_syslog/CMakeLists.txt b/bundles/logging/log_writer/log_writer_syslog/CMakeLists.txt
similarity index 100%
rename from bundles/log_writer/log_writer_syslog/CMakeLists.txt
rename to bundles/logging/log_writer/log_writer_syslog/CMakeLists.txt
diff --git a/bundles/log_writer/log_writer_syslog/private/src/log_writer_syslog.c b/bundles/logging/log_writer/log_writer_syslog/private/src/log_writer_syslog.c
similarity index 83%
rename from bundles/log_writer/log_writer_syslog/private/src/log_writer_syslog.c
rename to bundles/logging/log_writer/log_writer_syslog/private/src/log_writer_syslog.c
index c5a35ea..a52a6c4 100644
--- a/bundles/log_writer/log_writer_syslog/private/src/log_writer_syslog.c
+++ b/bundles/logging/log_writer/log_writer_syslog/private/src/log_writer_syslog.c
@@ -16,13 +16,7 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * log_writer_syslog.c
- *
- *  \date       Mar 7, 2011
- *  \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>
 
@@ -37,8 +31,14 @@
 
 #include <syslog.h>
 
-celix_status_t logListener_logged(log_listener_pt listener, log_entry_pt entry)
-{
+struct celix_log_writer {
+	//empty
+};
+
+celix_log_writer_t* celix_logWriter_create(celix_bundle_context_t *ctx __attribute__((unused))) { return NULL; }
+void celix_logWriter_destroy(celix_log_writer_t *writer __attribute__((unused))) {/*nop*/}
+
+celix_status_t celix_logWriter_logged(celix_log_writer_t *writer __attribute__((unused)), log_entry_t *entry) {
 	celix_status_t status = CELIX_SUCCESS;
 
 	int sysLogLvl = -1;
diff --git a/bundles/pubsub/examples/CMakeLists.txt b/bundles/pubsub/examples/CMakeLists.txt
index dd9ca54..bdbd9c2 100644
--- a/bundles/pubsub/examples/CMakeLists.txt
+++ b/bundles/pubsub/examples/CMakeLists.txt
@@ -132,8 +132,8 @@ if (BUILD_PUBSUB_PSA_ZMQ)
 
     # ZMQ
     add_celix_container("pubsub_zmq"
-            GROUP "pubsub"
-            BUNDLES
+        GROUP "pubsub"
+        BUNDLES
             Celix::shell
             Celix::shell_tui
             Celix::pubsub_serializer_json
@@ -142,11 +142,13 @@ if (BUILD_PUBSUB_PSA_ZMQ)
             Celix::pubsub_admin_zmq
             celix_pubsub_poi_publisher
             celix_pubsub_poi_subscriber
-            )
+        PROPERTIES
+            PSA_ZMQ_ZEROCOPY_ENABLED=true
+    )
     target_link_libraries(pubsub_zmq PRIVATE ${PUBSUB_CONTAINER_LIBS})
 
     add_celix_container("pubsub_publisher_zmq"
-         GROUP "pubsub"
+        GROUP "pubsub"
         BUNDLES
             Celix::shell
             Celix::shell_tui
@@ -160,6 +162,7 @@ if (BUILD_PUBSUB_PSA_ZMQ)
             PSA_ZMQ_VERBOSE=true
             PUBSUB_ETCD_DISCOVERY_VERBOSE=true
             PUBSUB_TOPOLOGY_MANAGER_VERBOSE=true
+            PSA_ZMQ_ZEROCOPY_ENABLED=false
     )
     target_link_libraries(pubsub_publisher_zmq PRIVATE ${PUBSUB_CONTAINER_LIBS})
 
diff --git a/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_topic_sender.c b/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_topic_sender.c
index ef9a8a8..36fe852 100644
--- a/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_topic_sender.c
+++ b/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_topic_sender.c
@@ -52,7 +52,7 @@ struct pubsub_zmq_topic_sender {
     pubsub_serializer_service_t *serializer;
     uuid_t fwUUID;
     bool metricsEnabled;
-    bool zeroCopyEnabled; //TODO tmp, when zero copy is stable remove option
+    bool zeroCopyEnabled;
 
     char *scope;
     char *topic;
@@ -81,12 +81,12 @@ typedef struct psa_zmq_send_msg_entry {
     pubsub_zmq_msg_header_t header; //partially filled header (only seqnr and time needs to be updated per send)
     pubsub_msg_serializer_t *msgSer;
     celix_thread_mutex_t sendLock; //protects send & Seqnr
-    int seqNr;
+    unsigned int seqNr;
     struct {
         celix_thread_mutex_t mutex; //protects entries in struct
-        long nrOfMessagesSend;
-        long nrOfMessagesSendFailed;
-        long nrOfSerializationErrors;
+        unsigned long nrOfMessagesSend;
+        unsigned long nrOfMessagesSendFailed;
+        unsigned long nrOfSerializationErrors;
         struct timespec lastMessageSend;
         double averageTimeBetweenMessagesInSeconds;
         double averageSerializationTimeInSeconds;
@@ -336,12 +336,12 @@ bool pubsub_zmqTopicSender_isStatic(pubsub_zmq_topic_sender_t *sender) {
     return sender->isStatic;
 }
 
-void pubsub_zmqTopicSender_connectTo(pubsub_zmq_topic_sender_t *sender, const celix_properties_t *endpoint) {
-    //TODO subscriber count -> topic info
+void pubsub_zmqTopicSender_connectTo(pubsub_zmq_topic_sender_t *sender  __attribute__((unused)), const celix_properties_t *endpoint __attribute__((unused))) {
+    /*nop*/
 }
 
-void pubsub_zmqTopicSender_disconnectFrom(pubsub_zmq_topic_sender_t *sender, const celix_properties_t *endpoint) {
-    //TODO
+void pubsub_zmqTopicSender_disconnectFrom(pubsub_zmq_topic_sender_t *sender __attribute__((unused)), const celix_properties_t *endpoint __attribute__((unused))) {
+    /*nop*/
 }
 
 static void* psa_zmq_getPublisherService(void *handle, const celix_bundle_t *requestingBundle, const celix_properties_t *svcProperties __attribute__((unused))) {
@@ -372,8 +372,8 @@ static void* psa_zmq_getPublisherService(void *handle, const celix_bundle_t *req
                 int minor;
                 version_getMajor(sendEntry->msgSer->msgVersion, &major);
                 version_getMinor(sendEntry->msgSer->msgVersion, &minor);
-                sendEntry->header.major = (int8_t)major;
-                sendEntry->header.minor = (int8_t)minor;
+                sendEntry->header.major = (uint8_t)major;
+                sendEntry->header.minor = (uint8_t)minor;
                 uuid_copy(sendEntry->header.originUUID, sender->fwUUID);
                 celixThreadMutex_create(&sendEntry->metrics.mutex, NULL);
                 hashMap_put(entry->msgEntries, key, sendEntry);
@@ -510,17 +510,16 @@ static int psa_zmq_topicPublicationSend(void* handle, unsigned int msgTypeId, co
         if (status == CELIX_SUCCESS /*ser ok*/) {
             unsigned char *hdr = calloc(sizeof(pubsub_zmq_msg_header_t), sizeof(unsigned char));
 
-            //TODO refactor, is the mutex really needed?
             celixThreadMutex_lock(&entry->sendLock);
 
             pubsub_zmq_msg_header_t msg_hdr = entry->header;
-            msg_hdr.seqNr = -1;
+            msg_hdr.seqNr = 0;
             msg_hdr.sendtimeSeconds = 0;
             msg_hdr.sendTimeNanoseconds = 0;
             if (monitor) {
                 clock_gettime(CLOCK_REALTIME, &sendTime);
-                msg_hdr.sendtimeSeconds = (int64_t) sendTime.tv_sec;
-                msg_hdr.sendTimeNanoseconds = (int64_t) sendTime.tv_nsec;
+                msg_hdr.sendtimeSeconds = (uint64_t) sendTime.tv_sec;
+                msg_hdr.sendTimeNanoseconds = (uint64_t) sendTime.tv_nsec;
                 msg_hdr.seqNr = entry->seqNr++;
             }
             psa_zmq_encodeHeader(&msg_hdr, hdr, sizeof(pubsub_zmq_msg_header_t));
@@ -532,17 +531,36 @@ static int psa_zmq_topicPublicationSend(void* handle, unsigned int msgTypeId, co
                 zmq_msg_t msg1; //filter
                 zmq_msg_t msg2; //header
                 zmq_msg_t msg3; //payload
-                zmq_msg_init_data(&msg1, sender->scopeAndTopicFilter, 4, NULL, bound);
-                zmq_msg_init_data(&msg2, hdr, sizeof(pubsub_zmq_msg_header_t), psa_zmq_freeMsg, bound);
-                zmq_msg_init_data(&msg3, serializedOutput, serializedOutputLen, psa_zmq_freeMsg, bound);
                 void *socket = zsock_resolve(sender->zmq.socket);
+
+                zmq_msg_init_data(&msg1, sender->scopeAndTopicFilter, 4, NULL, bound);
+                //send filter
                 int rc = zmq_msg_send(&msg1, socket, ZMQ_SNDMORE);
+                if (rc == -1) {
+                    L_WARN("Error sending filter msg. %s", strerror(errno));
+                    zmq_msg_close(&msg1);
+                }
+
+                //send header
                 if (rc > 0) {
+                    zmq_msg_init_data(&msg2, hdr, sizeof(pubsub_zmq_msg_header_t), psa_zmq_freeMsg, bound);
                     rc = zmq_msg_send(&msg2, socket, ZMQ_SNDMORE);
+                    if (rc == -1) {
+                        L_WARN("Error sending header msg. %s", strerror(errno));
+                        zmq_msg_close(&msg2);
+                    }
                 }
+
+
                 if (rc > 0) {
+                    zmq_msg_init_data(&msg3, serializedOutput, serializedOutputLen, psa_zmq_freeMsg, bound);
                     rc = zmq_msg_send(&msg3, socket, 0);
+                    if (rc == -1) {
+                        L_WARN("Error sending payload msg. %s", strerror(errno));
+                        zmq_msg_close(&msg3);
+                    }
                 }
+
                 sendOk = rc > 0;
             } else {
                 zmsg_t *msg = zmsg_new();
@@ -553,6 +571,9 @@ static int psa_zmq_topicPublicationSend(void* handle, unsigned int msgTypeId, co
                 sendOk = rc == 0;
                 free(serializedOutput);
                 free(hdr);
+                if (!sendOk) {
+                    zmsg_destroy(&msg); //if send was not ok, no owner change -> destroy msg
+                }
             }
 
             celixThreadMutex_unlock(&entry->sendLock);
diff --git a/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c b/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c
index 4b7c2dc..2ffa07d 100644
--- a/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c
+++ b/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c
@@ -97,6 +97,11 @@ celix_status_t pubsub_discovery_destroy(pubsub_discovery_t *ps_discovery) {
 
     //note cleanup done in stop
     celixThreadMutex_lock(&ps_discovery->discoveredEndpointsMutex);
+    hash_map_iterator_t iter = hashMapIterator_construct(ps_discovery->discoveredEndpoints);
+    while (hashMapIterator_hasNext(&iter)) {
+        celix_properties_t *props = hashMapIterator_nextValue(&iter);
+        celix_properties_destroy(props);
+    }
     hashMap_destroy(ps_discovery->discoveredEndpoints, false, false);
     celixThreadMutex_unlock(&ps_discovery->discoveredEndpointsMutex);
     celixThreadMutex_destroy(&ps_discovery->discoveredEndpointsMutex);
@@ -489,7 +494,6 @@ static void pubsub_discovery_addDiscoveredEndpoint(pubsub_discovery_t *disc, cel
 
 static void pubsub_discovery_removeDiscoveredEndpoint(pubsub_discovery_t *disc, const char *uuid) {
     celixThreadMutex_lock(&disc->discoveredEndpointsMutex);
-    bool exists = hashMap_containsKey(disc->discoveredEndpoints, (void*)uuid);
     celix_properties_t *endpoint = hashMap_remove(disc->discoveredEndpoints, (void*)uuid);
     celixThreadMutex_unlock(&disc->discoveredEndpointsMutex);
 
@@ -506,7 +510,7 @@ static void pubsub_discovery_removeDiscoveredEndpoint(pubsub_discovery_t *disc,
                uuid, type, admin, ser);
     }
 
-    if (exists) {
+    if (endpoint != NULL) {
         celixThreadMutex_lock(&disc->discoveredEndpointsListenersMutex);
         hash_map_iterator_t iter = hashMapIterator_construct(disc->discoveredEndpointsListeners);
         while (hashMapIterator_hasNext(&iter)) {
@@ -514,6 +518,8 @@ static void pubsub_discovery_removeDiscoveredEndpoint(pubsub_discovery_t *disc,
             listener->removeDiscoveredEndpoint(listener->handle, endpoint);
         }
         celixThreadMutex_unlock(&disc->discoveredEndpointsListenersMutex);
+
+        celix_properties_destroy(endpoint);
     } else {
         L_WARN("[PSD] Warning unexpected remove from non existing endpoint (uuid is %s)\n", uuid);
     }
diff --git a/bundles/pubsub/test/CMakeLists.txt b/bundles/pubsub/test/CMakeLists.txt
index 69b3e43..bfb7317 100644
--- a/bundles/pubsub/test/CMakeLists.txt
+++ b/bundles/pubsub/test/CMakeLists.txt
@@ -89,4 +89,24 @@ if (BUILD_PUBSUB_PSA_ZMQ)
     target_include_directories(pubsub_zmq_tests PRIVATE ${CPPUTEST_INCLUDE_DIR})
     add_test(NAME pubsub_zmq_tests COMMAND pubsub_zmq_tests WORKING_DIRECTORY $<TARGET_PROPERTY:pubsub_zmq_tests,CONTAINER_LOC>)
     SETUP_TARGET_FOR_COVERAGE(pubsub_zmq_tests_cov pubsub_zmq_tests ${CMAKE_BINARY_DIR}/coverage/pubsub_zmq_tests/pubsub_zmq_tests ..)
+
+
+    add_celix_container(pubsub_zmq_zerocopy_tests
+            USE_CONFIG #ensures that a config.properties will be created with the launch bundles.
+            LAUNCHER_SRC ${CMAKE_CURRENT_LIST_DIR}/test/test_runner.cc
+            DIR ${CMAKE_CURRENT_BINARY_DIR}
+            PROPERTIES
+                LOGHELPER_STDOUT_FALLBACK_INCLUDE_DEBUG=true
+                PSA_ZMQ_ZEROCOPY_ENABLED=true
+            BUNDLES
+                Celix::pubsub_serializer_json
+                Celix::pubsub_topology_manager
+                Celix::pubsub_admin_zmq
+                pubsub_sut
+                pubsub_tst
+    )
+    target_link_libraries(pubsub_zmq_zerocopy_tests PRIVATE Celix::pubsub_api ${CPPUTEST_LIBRARIES} ${JANSSON_LIBRARIES} Celix::dfi)
+    target_include_directories(pubsub_zmq_zerocopy_tests PRIVATE ${CPPUTEST_INCLUDE_DIR})
+    add_test(NAME pubsub_zmq_zerocopy_tests COMMAND pubsub_zmq_zerocopy_tests WORKING_DIRECTORY $<TARGET_PROPERTY:pubsub_zmq_zerocopy_tests,CONTAINER_LOC>)
+    SETUP_TARGET_FOR_COVERAGE(pubsub_zmq_zerocopy_tests_cov pubsub_zmq_zerocopy_tests ${CMAKE_BINARY_DIR}/coverage/pubsub_zmq_tests/pubsub_zmq_zerocopy_tests ..)
 endif ()
\ No newline at end of file
diff --git a/bundles/shell/shell/src/help_command.c b/bundles/shell/shell/src/help_command.c
index aa9334e..be9b63c 100644
--- a/bundles/shell/shell/src/help_command.c
+++ b/bundles/shell/shell/src/help_command.c
@@ -16,97 +16,84 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * help_command.c
- *
- *  \date       Aug 20, 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 <stdint.h>
 
-#include "array_list.h"
-#include "bundle_context.h"
+#include "celix_api.h"
 #include "shell.h"
 #include "std_commands.h"
 
-celix_status_t helpCommand_execute(void *_ptr, char *line_str, FILE *out_ptr, FILE *err_ptr) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	bundle_context_pt context_ptr = _ptr;
-	service_reference_pt shell_service_reference_ptr = NULL;
-	shell_service_pt shell_ptr = NULL;
-
-	if (!context_ptr || !line_str || !out_ptr || !err_ptr) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	}
+struct print_handle {
+    char *cmdLine;
+    FILE *out;
+    FILE *err;
+};
 
-	if (status == CELIX_SUCCESS) {
-		status = bundleContext_getServiceReference(context_ptr, (char *) OSGI_SHELL_SERVICE_NAME, &shell_service_reference_ptr);
-	}
+static void printHelp(void *handle, void *svc) {
+    shell_service_t *shell = svc;
+    struct print_handle *p = handle;
+    char *cmdLine = p->cmdLine;
+    FILE *out = p->out;
+    FILE *err = p->err;
 
-	if (status == CELIX_SUCCESS) {
-		status = bundleContext_getService(context_ptr, shell_service_reference_ptr, (void **) &shell_ptr);
-	}
+    uint32_t out_len = 256;
+    char *sub = NULL;
+    char *save_ptr = NULL;
+    char out_str[out_len];
 
-	if (status == CELIX_SUCCESS) {
-        uint32_t out_len = 256;
-        char *sub = NULL;
-        char *save_ptr = NULL;
-        char out_str[out_len];
+    memset(out_str, 0, sizeof(out_str));
 
-        memset(out_str, 0, sizeof(out_str));
+    strtok_r(cmdLine, OSGI_SHELL_COMMAND_SEPARATOR, &save_ptr);
+    sub = strtok_r(NULL, OSGI_SHELL_COMMAND_SEPARATOR, &save_ptr);
 
-        strtok_r(line_str, OSGI_SHELL_COMMAND_SEPARATOR, &save_ptr);
-        sub = strtok_r(NULL, OSGI_SHELL_COMMAND_SEPARATOR, &save_ptr);
+    if (sub == NULL) {
+        unsigned int i;
+        array_list_pt commands = NULL;
 
-        if (sub == NULL) {
-            unsigned int i;
-            array_list_pt commands = NULL;
-
-            status = shell_ptr->getCommands(shell_ptr->shell, &commands);
-            for (i = 0; i < arrayList_size(commands); i++) {
-                char *name = arrayList_get(commands, i);
-                fprintf(out_ptr, "%s\n", name);
-            }
-            fprintf(out_ptr, "\nUse 'help <command-name>' for more information.\n");
-            arrayList_destroy(commands);
-        } else {
-            celix_status_t sub_status_desc;
-            celix_status_t sub_status_usage;
-            int i;
-            array_list_pt commands = NULL;
-            shell_ptr->getCommands(shell_ptr->shell, &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_ptr->getCommandDescription(shell_ptr->shell, name, &desc_str);
-                    sub_status_usage = shell_ptr->getCommandUsage(shell_ptr->shell, name, &usage_str);
+        shell->getCommands(shell->shell, &commands);
+        for (i = 0; i < arrayList_size(commands); i++) {
+            char *name = arrayList_get(commands, i);
+            fprintf(out, "%s\n", name);
+        }
+        fprintf(out, "\nUse 'help <command-name>' for more information.\n");
+        arrayList_destroy(commands);
+    } else {
+        celix_status_t sub_status_desc;
+        celix_status_t sub_status_usage;
+        int i;
+        celix_array_list_t *commands = NULL;
+        shell->getCommands(shell->shell, &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;
 
-                    if (sub_status_usage == CELIX_SUCCESS && sub_status_desc == CELIX_SUCCESS) {
-                        fprintf(out_ptr, "Command     : %s\n", name);
-                        fprintf(out_ptr, "Usage       : %s\n", usage_str == NULL ? "" : usage_str);
-                        fprintf(out_ptr, "Description : %s\n", desc_str == NULL ? "" : desc_str);
-                    } else {
-                        fprintf(err_ptr, "Error retrieving help info for command '%s'\n", sub);
-                    }
+                sub_status_desc = shell->getCommandDescription(shell->shell, name, &desc_str);
+                sub_status_usage = shell->getCommandUsage(shell->shell, name, &usage_str);
 
-                    if (sub_status_desc != CELIX_SUCCESS && status == CELIX_SUCCESS) {
-                        status = sub_status_desc;
-                    }
-                    if (sub_status_usage != CELIX_SUCCESS && status == CELIX_SUCCESS) {
-                        status = sub_status_usage;
-                    }
+                if (sub_status_usage == CELIX_SUCCESS && sub_status_desc == CELIX_SUCCESS) {
+                    fprintf(out, "Command     : %s\n", name);
+                    fprintf(out, "Usage       : %s\n", usage_str == NULL ? "" : usage_str);
+                    fprintf(out, "Description : %s\n", desc_str == NULL ? "" : desc_str);
+                } else {
+                    fprintf(err, "Error retrieving help info for command '%s'\n", sub);
                 }
             }
-            arrayList_destroy(commands);
         }
+        celix_arrayList_destroy(commands);
     }
+}
 
+celix_status_t helpCommand_execute(void *handle, char *cmdLine, FILE *out, FILE *err) {
+	celix_status_t status = CELIX_SUCCESS;
+	celix_bundle_context_t *ctx = handle;
+	struct print_handle printHandle;
+    printHandle.cmdLine = cmdLine;
+    printHandle.out = out;
+    printHandle.err = err;
+	celix_bundleContext_useService(ctx, OSGI_SHELL_SERVICE_NAME, &printHandle, printHelp);
     return status;
 }
diff --git a/cmake/cmake_celix/ContainerPackaging.cmake b/cmake/cmake_celix/ContainerPackaging.cmake
index 03eea77..f0a464c 100644
--- a/cmake/cmake_celix/ContainerPackaging.cmake
+++ b/cmake/cmake_celix/ContainerPackaging.cmake
@@ -77,16 +77,16 @@ function(add_celix_container)
         endif()
     elseif (CONTAINER_LAUNCHER_SRC)
         get_filename_component(SRC_FILENAME ${CONTAINER_LAUNCHER_SRC} NAME)
-        set(LAUNCHER_SRC "${PROJECT_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/${SRC_FILENAME}")
+        set(LAUNCHER_SRC "${CMAKE_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/${SRC_FILENAME}")
         set(LAUNCHER_ORG "${CONTAINER_LAUNCHER_SRC}")
         file(GENERATE OUTPUT "${LAUNCHER_SRC}" INPUT "${LAUNCHER_ORG}")
     else () #generate custom launcher
         if (CONTAINER_CXX)
-            set(LAUNCHER_SRC "${PROJECT_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/main.cc")
+            set(LAUNCHER_SRC "${CMAKE_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/main.cc")
         else()
-            set(LAUNCHER_SRC "${PROJECT_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/main.c")
+            set(LAUNCHER_SRC "${CMAKE_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/main.c")
         endif()
-        set(STAGE1_LAUNCHER_SRC "${PROJECT_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/main.stage1.c")
+        set(STAGE1_LAUNCHER_SRC "${CMAKE_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/main.stage1.c")
 
         file(GENERATE
                 OUTPUT "${STAGE1_LAUNCHER_SRC}"
@@ -129,7 +129,7 @@ $<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_EMBEDDED_PROPERTIES>,\\n\
 
     #generate config.properties. C
     set(CONTAINER_PROPS "${CONTAINER_LOC}/config.properties")
-    set(STAGE1_PROPERTIES "${PROJECT_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/container-config-stage1.properties")
+    set(STAGE1_PROPERTIES "${CMAKE_BINARY_DIR}/celix/gen/containers/${CONTAINER_TARGET}/container-config-stage1.properties")
     if (CONTAINER_USE_CONFIG)
         file(GENERATE
                 OUTPUT "${STAGE1_PROPERTIES}"
diff --git a/cmake/cmake_celix/Runtimes.cmake b/cmake/cmake_celix/Runtimes.cmake
index 543dca4..8853359 100644
--- a/cmake/cmake_celix/Runtimes.cmake
+++ b/cmake/cmake_celix/Runtimes.cmake
@@ -40,9 +40,9 @@ function(add_celix_runtime)
         set(RUNTIME_NAME ${RUNTIME_TARGET_NAME})
     endif ()
     if (NOT DEFINED RUNTIME_GROUP)
-        set(RUNTIME_LOC "${PROJECT_BINARY_DIR}/runtimes/${RUNTIME_NAME}")
+        set(RUNTIME_LOC "${CMAKE_BINARY_DIR}/runtimes/${RUNTIME_NAME}")
     else ()
-        set(RUNTIME_LOC "${PROJECT_BINARY_DIR}/runtimes/${RUNTIME_GROUP}/${RUNTIME_NAME}")
+        set(RUNTIME_LOC "${CMAKE_BINARY_DIR}/runtimes/${RUNTIME_GROUP}/${RUNTIME_NAME}")
     endif ()
     set(TIMESTAMP_FILE "${CMAKE_CURRENT_BINARY_DIR}/${RUNTIME_TARGET_NAME}-runtime-timestamp")
 
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index ed29676..8ab6dbe 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -678,8 +678,8 @@ celix_status_t serviceRegistry_getService(service_registry_pt registry, bundle_p
         if (count == 1) {
             serviceRegistration_getService(registration, bundle, &service);
             serviceReference_setService(reference, service);
-            serviceRegistration_release(registration);
         }
+        serviceRegistration_release(registration);
 
         /* NOTE the out argument of sr_getService should be 'const void**'
            To ensure backwards compatibility a cast is made instead.