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 2023/06/30 18:33:26 UTC
[celix] 05/06: Refactor conditions to framework bundle
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/585-celix-conditions
in repository https://gitbox.apache.org/repos/asf/celix.git
commit b5964b6427db0f0004162b86f9230dbc90fc1498
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Thu Jun 29 23:02:50 2023 +0200
Refactor conditions to framework bundle
---
documents/conditions.md | 23 ---
documents/framework.md | 4 +
libs/framework/CMakeLists.txt | 1 +
.../src/CelixBundleContextBundlesTestSuite.cc | 10 +-
.../src/CelixBundleContextServicesTestSuite.cc | 1 +
.../gtest/src/CxxBundleContextTestSuite.cc | 8 +-
libs/framework/include/celix_condition.h | 10 +-
libs/framework/include/celix_framework.h | 5 +
libs/framework/src/celix_framework_bundle.c | 167 +++++++++++++++++++++
libs/framework/src/celix_framework_bundle.h | 54 +++++++
libs/framework/src/framework.c | 94 +++++-------
libs/framework/src/framework_private.h | 6 +
12 files changed, 285 insertions(+), 98 deletions(-)
diff --git a/documents/conditions.md b/documents/conditions.md
deleted file mode 100644
index b2c170ee..00000000
--- a/documents/conditions.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: Apache Celix Conditions
----
-
-<!--
-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.
--->
-
-# Apache Celix Conditions
-TODO
\ No newline at end of file
diff --git a/documents/framework.md b/documents/framework.md
index 4eb0b99d..d697bd4a 100644
--- a/documents/framework.md
+++ b/documents/framework.md
@@ -206,6 +206,10 @@ add_executable(create_framework_with_celix_launcher src/launcher.c)
target_link_libraries(create_framework_with_celix_launcher PRIVATE Celix::framework)
```
+## Framework Conditions
+
+TODO
+
## Framework bundle cache
The Apache Celix framework uses a bundle cache directory to store the installed bundles, their state and for a
persistent bundle storage. The bundle cache directory is created in the directory configured in the framework
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 3cde3860..ad6c5921 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -35,6 +35,7 @@ set(FRAMEWORK_SRC
src/celix_bundle_state.c
src/celix_framework_utils.c
src/celix_scheduled_event.c
+ src/celix_framework_bundle.c
)
set(FRAMEWORK_DEPS libuuid::libuuid CURL::libcurl ZLIB::ZLIB ${CMAKE_DL_LIBS})
diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
index 37cf9b2a..fd5c5421 100644
--- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
@@ -46,10 +46,12 @@ public:
const char * const TEST_BND_UNRESOLVABLE_LOC = "" TEST_BUNDLE_UNRESOLVABLE_LOCATION "";
CelixBundleContextBundlesTestSuite() {
- properties = properties_create();
- properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
- properties_set(properties, "org.osgi.framework.storage.clean", "true");
- properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
+ properties = celix_properties_create();
+ celix_properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
+ celix_properties_set(properties, "org.osgi.framework.storage.clean", "true");
+ celix_properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
+ celix_properties_set(properties, "CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED", "false");
+
fw = celix_frameworkFactory_createFramework(properties);
ctx = framework_getContext(fw);
diff --git a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
index f9115f41..8780a4b7 100644
--- a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
@@ -47,6 +47,7 @@ public:
celix_properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
celix_properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
celix_properties_set(properties, "CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace");
+ celix_properties_set(properties, "CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED", "false");
celix_properties_setLong(properties, CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE, 256); //ensure that the floodEventLoopTest overflows the static event queue size
fw = celix_frameworkFactory_createFramework(properties);
diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index 7c0e7db9..004b87bd 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -33,10 +33,10 @@ public:
static constexpr const char * const TEST_BND2_LOC = "" SIMPLE_TEST_BUNDLE2_LOCATION "";
CxxBundleContextTestSuite() {
- auto* properties = properties_create();
- properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
- properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
- properties_set(properties, "org.osgi.framework.storage", ".cacheCxxBundleContextTestFramework");
+ auto* properties = celix_properties_create();
+ celix_properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
+ celix_properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
+ celix_properties_set(properties, "CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED", "false");
auto* cfw = celix_frameworkFactory_createFramework(properties);
fw = std::shared_ptr<celix_framework_t>{cfw, [](celix_framework_t* f){ celix_frameworkFactory_destroyFramework(f); }};
diff --git a/libs/framework/include/celix_condition.h b/libs/framework/include/celix_condition.h
index 55fe37a1..8c442e8b 100644
--- a/libs/framework/include/celix_condition.h
+++ b/libs/framework/include/celix_condition.h
@@ -20,8 +20,6 @@
#ifndef CELIX_CONDITION_H_
#define CELIX_CONDITION_H_
-#include "celix_framework_export.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -40,7 +38,7 @@ extern "C" {
* @brief The property key used to specify the condition id.
* A condition id can only identify a single condition.
*/
-#define CELIX_CONDITION_ID "celix.condition.id"
+#define CELIX_CONDITION_ID "condition.id"
/*!
* @brief The unique identifier for the default True condition.
@@ -79,12 +77,6 @@ typedef struct celix_condition {
sizeof(celix_condition_t) != 0 */
} celix_condition_t;
-/**
- * @brief A condition service struct instance that can be used to register celix_condition services.
- * This can be helpful to avoid a bundle having to implement this service to register a celix_condition service.
- */
-CELIX_FRAMEWORK_EXPORT celix_condition_t CELIX_CONDITION_INSTANCE;
-
#ifdef __cplusplus
}
#endif
diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h
index 749752f7..cd99d403 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -417,6 +417,11 @@ CELIX_FRAMEWORK_EXPORT void celix_framework_waitForGenericEvent(celix_framework_
*/
CELIX_FRAMEWORK_EXPORT void celix_framework_waitForStop(celix_framework_t *framework);
+/**
+ * @brief Check if the event queue is empty.
+ */
+CELIX_FRAMEWORK_EXPORT bool celix_framework_isEventQueueEmpty(celix_framework_t* fw);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/framework/src/celix_framework_bundle.c b/libs/framework/src/celix_framework_bundle.c
new file mode 100644
index 00000000..282f5511
--- /dev/null
+++ b/libs/framework/src/celix_framework_bundle.c
@@ -0,0 +1,167 @@
+/*
+ * 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 "celix_framework_bundle.h"
+
+#include "celix_condition.h"
+#include "celix_threads.h"
+#include "framework_private.h"
+
+#define CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED \
+ "CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED" // TODO move to constants.h
+#define CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED_DEFAULT true // TODO move to constants.h
+
+typedef struct celix_framework_bundle_activator {
+ celix_bundle_context_t* ctx;
+ celix_condition_t conditionInstance; /**< condition instance which can be used for multiple condition services.*/
+ long trueConditionSvcId; /**< service id of the condition service which is always true. */
+ framework_listener_t listener; /**< framework listener to check if the framework is ready. */
+
+ celix_thread_mutex_t mutex; /**< protects below. */
+ bool frameworkStartedEventReceived; /**< true if the framework started event is received. */
+ long frameworkReadyConditionSvcId; /**< service id of the condition service which is set when the framework is
+ ready. */
+ long checkFrameworkScheduledEventId; /**< event id of the scheduled event to check if the framework is ready. */
+
+} celix_framework_bundle_activator_t;
+
+static celix_status_t celix_frameworkBundle_frameworkEvent(void* handle, framework_event_t* event) {
+ framework_listener_t* listener = handle;
+ celix_framework_bundle_activator_t* act = listener->handle;
+ if (event->type == OSGI_FRAMEWORK_EVENT_STARTED) {
+ celixThreadMutex_lock(&act->mutex);
+ act->frameworkStartedEventReceived = true;
+ celixThreadMutex_unlock(&act->mutex);
+ }
+ return CELIX_SUCCESS;
+}
+
+celix_status_t celix_frameworkBundle_create(celix_bundle_context_t* ctx, void** userData) {
+ *userData = NULL;
+ celix_framework_bundle_activator_t* act = calloc(1, sizeof(*act));
+ if (act) {
+ act->ctx = ctx;
+ act->trueConditionSvcId = -1L;
+ act->listener.handle = act;
+ act->listener.frameworkEvent = celix_frameworkBundle_frameworkEvent;
+ act->frameworkStartedEventReceived = false;
+ act->frameworkReadyConditionSvcId = -1L;
+ act->checkFrameworkScheduledEventId = -1L;
+ act->conditionInstance.handle = act;
+ celixThreadMutex_create(&act->mutex, NULL);
+ *userData = act;
+ }
+ return act != NULL ? CELIX_SUCCESS : CELIX_ENOMEM;
+}
+
+static void celix_frameworkBundle_registerTrueCondition(celix_framework_bundle_activator_t* act) {
+ celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+ opts.serviceName = CELIX_CONDITION_SERVICE_NAME;
+ opts.serviceVersion = CELIX_CONDITION_SERVICE_VERSION;
+ opts.svc = &act->conditionInstance;
+ opts.properties = celix_properties_create();
+ if (opts.properties) {
+ celix_properties_set(opts.properties, CELIX_CONDITION_ID, CELIX_CONDITION_ID_TRUE);
+ act->trueConditionSvcId = celix_bundleContext_registerServiceWithOptionsAsync(act->ctx, &opts);
+ celix_bundleContext_log(
+ act->ctx, CELIX_LOG_LEVEL_INFO, "Registered true condition service with id %li", act->trueConditionSvcId);
+ } else {
+ celix_bundleContext_log(act->ctx, CELIX_LOG_LEVEL_ERROR, "Cannot create properties for true condition service");
+ }
+}
+
+static void celix_frameworkBundle_readyCheck(void* data) {
+ celix_framework_bundle_activator_t* act = data;
+ celix_bundleContext_log(act->ctx, CELIX_LOG_LEVEL_INFO, "celix_frameworkBundle_readyCheck");
+ celixThreadMutex_lock(&act->mutex);
+ bool ready = act->frameworkStartedEventReceived &&
+ celix_framework_isEventQueueEmpty(celix_bundleContext_getFramework(act->ctx));
+ if (ready) {
+ celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+ opts.serviceName = CELIX_CONDITION_SERVICE_NAME;
+ opts.serviceVersion = CELIX_CONDITION_SERVICE_VERSION;
+ opts.svc = &act->conditionInstance;
+ opts.properties = celix_properties_create();
+ if (opts.properties) {
+ celix_properties_set(opts.properties, CELIX_CONDITION_ID, CELIX_CONDITION_ID_FRAMEWORK_READY);
+ act->frameworkReadyConditionSvcId = celix_bundleContext_registerServiceWithOptionsAsync(act->ctx, &opts);
+ } else {
+ celix_bundleContext_log(
+ act->ctx, CELIX_LOG_LEVEL_ERROR, "Cannot create properties for framework.ready condition service");
+ }
+ } else {
+ // not ready yet, schedule a new check
+ celix_scheduled_event_options_t opts = CELIX_EMPTY_SCHEDULED_EVENT_OPTIONS;
+ opts.callback = celix_frameworkBundle_readyCheck;
+ opts.callbackData = act;
+ opts.initialDelayInSeconds = 0.01; // TBD use a small delay or accept a lot of scheduled events during startup.
+ act->checkFrameworkScheduledEventId = celix_bundleContext_scheduleEvent(act->ctx, &opts);
+ }
+ celixThreadMutex_unlock(&act->mutex);
+}
+
+celix_status_t celix_frameworkBundle_start(void* userData, celix_bundle_context_t* ctx) {
+ celix_framework_bundle_activator_t* act = userData;
+
+ bool conditionsEnabled = celix_bundleContext_getPropertyAsBool(
+ ctx, CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED, CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED_DEFAULT);
+ if (conditionsEnabled) {
+ celix_frameworkBundle_registerTrueCondition(act);
+ fw_addFrameworkListener(celix_bundleContext_getFramework(ctx), celix_bundleContext_getBundle(ctx), &act->listener);
+ celix_frameworkBundle_readyCheck(act);
+ return act->trueConditionSvcId >= 0 ? CELIX_SUCCESS : CELIX_BUNDLE_EXCEPTION;
+ }
+
+ return CELIX_SUCCESS;
+}
+
+celix_status_t celix_frameworkBundle_stop(void* userData, celix_bundle_context_t* ctx) {
+ celix_framework_bundle_activator_t* act = userData;
+ celix_status_t status = CELIX_SUCCESS;
+
+ // remove framework listener
+ fw_removeFrameworkListener(celix_bundleContext_getFramework(ctx), celix_bundleContext_getBundle(ctx), &act->listener);
+
+ // stop ready check and remove framework ready condition service if present
+ celixThreadMutex_lock(&act->mutex);
+ celix_bundleContext_tryRemoveScheduledEventAsync(ctx, act->checkFrameworkScheduledEventId);
+ act->checkFrameworkScheduledEventId = -1L;
+ celix_bundleContext_unregisterServiceAsync(ctx, act->frameworkReadyConditionSvcId, NULL, NULL);
+ act->frameworkReadyConditionSvcId = -1L;
+ celixThreadMutex_unlock(&act->mutex);
+
+ // remove true condition service
+ celix_bundleContext_unregisterServiceAsync(ctx, act->trueConditionSvcId, NULL, NULL);
+ act->trueConditionSvcId = -1L;
+
+ // framework shutdown
+ celix_framework_t* framework = celix_bundleContext_getFramework(ctx);
+ celix_framework_shutdownAsync(framework);
+ return status;
+}
+
+celix_status_t celix_frameworkBundle_destroy(void* userData,
+ celix_bundle_context_t* ctx __attribute__((unused))) {
+ celix_framework_bundle_activator_t* act = userData;
+ if (act) {
+ celixThreadMutex_destroy(&act->mutex);
+ free(userData);
+ }
+ return CELIX_SUCCESS;
+}
diff --git a/libs/framework/src/celix_framework_bundle.h b/libs/framework/src/celix_framework_bundle.h
new file mode 100644
index 00000000..29776bc5
--- /dev/null
+++ b/libs/framework/src/celix_framework_bundle.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef CELIX_FRAMEWORK_BUNDLE_H_
+#define CELIX_FRAMEWORK_BUNDLE_H_
+
+#include "celix_errno.h"
+#include "celix_bundle_context.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief The framework bundle bundle activator create.
+ */
+celix_status_t celix_frameworkBundle_create(celix_bundle_context_t* ctx, void** userData);
+
+/**
+ * @brief The framework bundle bundle activator start.
+ */
+celix_status_t celix_frameworkBundle_start(void* userData, celix_bundle_context_t* ctx);
+
+/**
+ * @brief The framework bundle bundle activator stop.
+ */
+celix_status_t celix_frameworkBundle_stop(void* userData, celix_bundle_context_t* ctx);
+
+/**
+ * @brief The framework bundle bundle activator destroy.
+ */
+celix_status_t celix_frameworkBundle_destroy(void* userData, celix_bundle_context_t* ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CELIX_FRAMEWORK_BUNDLE_H_ */
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index c993e80a..d9015c2d 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -36,6 +36,7 @@
#include "celix_libloader.h"
#include "celix_log_constants.h"
#include "celix_module_private.h"
+#include "celix_framework_bundle.h"
#include "bundle_archive_private.h"
#include "bundle_context_private.h"
@@ -177,10 +178,6 @@ static void *fw_eventDispatcher(void *fw);
celix_status_t fw_invokeBundleListener(framework_pt framework, bundle_listener_pt listener, bundle_event_pt event, bundle_pt bundle);
celix_status_t fw_invokeFrameworkListener(framework_pt framework, framework_listener_pt listener, framework_event_pt event, bundle_pt bundle);
-static celix_status_t frameworkActivator_start(void * userData, bundle_context_t *context);
-static celix_status_t frameworkActivator_stop(void * userData, bundle_context_t *context);
-static celix_status_t frameworkActivator_destroy(void * userData, bundle_context_t *context);
-
static celix_status_t framework_autoStartConfiguredBundles(celix_framework_t *fw);
static celix_status_t framework_autoInstallConfiguredBundles(celix_framework_t *fw);
static celix_status_t framework_autoInstallConfiguredBundlesForList(celix_framework_t *fw, const char *autoStart, celix_array_list_t *installedBundles);
@@ -435,27 +432,19 @@ celix_status_t fw_init(framework_pt framework) {
celix_status_t status = bundle_setState(framework->bundle, CELIX_BUNDLE_STATE_STARTING);
if (status == CELIX_SUCCESS) {
celix_bundle_activator_t *activator = calloc(1,(sizeof(*activator)));
- if (activator != NULL) {
+ if (activator) {
bundle_context_t *validateContext = NULL;
- void * userData = NULL;
-
- //create_function_pt create = NULL;
- celix_bundle_activator_start_fp start = frameworkActivator_start;
- celix_bundle_activator_stop_fp stop = frameworkActivator_stop;
- celix_bundle_activator_destroy_fp destroy = frameworkActivator_destroy;
- activator->start = start;
- activator->stop = stop;
- activator->destroy = destroy;
+ activator->create = celix_frameworkBundle_create;
+ activator->start = celix_frameworkBundle_start;
+ activator->stop = celix_frameworkBundle_stop;
+ activator->destroy = celix_frameworkBundle_destroy;
status = CELIX_DO_IF(status, bundle_setActivator(framework->bundle, activator));
status = CELIX_DO_IF(status, bundle_getContext(framework->bundle, &validateContext));
+ status = CELIX_DO_IF(status, activator->create(validateContext, &activator->userData));
+ status = CELIX_DO_IF(status, activator->start(activator->userData, validateContext));
- if (status == CELIX_SUCCESS) {
- activator->userData = userData;
- if (start != NULL) {
- start(userData, validateContext);
- }
- } else {
+ if (status != CELIX_SUCCESS) {
free(activator);
}
} else {
@@ -500,9 +489,11 @@ celix_status_t framework_start(celix_framework_t* framework) {
celix_status_t startStatus = framework_autoStartConfiguredBundles(framework);
celix_status_t installStatus = framework_autoInstallConfiguredBundles(framework);
if (startStatus == CELIX_SUCCESS && installStatus == CELIX_SUCCESS) {
- fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId); //TODO maybe register framwork.ready on this event and only keep the condition true service?
+ fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId);
} else {
- status = CELIX_BUNDLE_EXCEPTION; //error already logged
+ //note not returning a error, because the framework is started, but not all bundles are started/installed
+ fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not auto start or install all configured bundles");
+ fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, framework->bundleId);
}
if (status == CELIX_SUCCESS) {
@@ -1015,8 +1006,7 @@ celix_status_t fw_removeFrameworkListener(framework_pt framework, bundle_pt bund
if (frameworkListener->listener == listener && frameworkListener->bundle == bundle) {
arrayList_remove(framework->frameworkListeners, i);
- frameworkListener->bundle = NULL;
- frameworkListener->listener = NULL;
+
free(frameworkListener);
}
}
@@ -1264,6 +1254,21 @@ static void* framework_shutdown(void *framework) {
return NULL;
}
+void celix_framework_shutdownAsync(celix_framework_t* framework) {
+ fw_log(framework->logger,
+ CELIX_LOG_LEVEL_TRACE,
+ "Start shutdown thread for framework %s",
+ celix_framework_getUUID(framework));
+ celixThreadMutex_lock(&framework->shutdown.mutex);
+ bool alreadyInitialized = framework->shutdown.initialized;
+ framework->shutdown.initialized = true;
+ celixThreadMutex_unlock(&framework->shutdown.mutex);
+
+ if (!alreadyInitialized) {
+ celixThread_create(&framework->shutdown.thread, NULL, framework_shutdown, framework);
+ }
+}
+
celix_status_t framework_getFrameworkBundle(const_framework_pt framework, bundle_pt *bundle) {
celix_status_t status = CELIX_SUCCESS;
@@ -1563,6 +1568,13 @@ static int celix_framework_eventQueueSize(celix_framework_t* fw) {
return fw->dispatcher.eventQueueSize + celix_arrayList_size(fw->dispatcher.dynamicEventQueue);
}
+bool celix_framework_isEventQueueEmpty(celix_framework_t* fw) {
+ celixThreadMutex_lock(&fw->dispatcher.mutex);
+ bool empty = celix_framework_eventQueueSize(fw) == 0;
+ celixThreadMutex_unlock(&fw->dispatcher.mutex);
+ return empty;
+}
+
static bool requiresScheduledEventsProcessing(celix_framework_t* framework) {
// precondition framework->dispatcher.mutex locked
struct timespec currentTime = celixThreadCondition_getTime();
@@ -1647,40 +1659,6 @@ celix_status_t fw_invokeFrameworkListener(framework_pt framework, framework_list
return ret;
}
-static celix_status_t frameworkActivator_start(void * userData, bundle_context_t *context) {
- // nothing to do
- return CELIX_SUCCESS;
-}
-
-static celix_status_t frameworkActivator_stop(void * userData, bundle_context_t *context) {
- celix_status_t status = CELIX_SUCCESS;
- framework_pt framework;
-
-
- if (bundleContext_getFramework(context, &framework) == CELIX_SUCCESS) {
- fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Start shutdown thread for framework %s", celix_framework_getUUID(framework));
- celixThreadMutex_lock(&framework->shutdown.mutex);
- bool alreadyInitialized = framework->shutdown.initialized;
- framework->shutdown.initialized = true;
- celixThreadMutex_unlock(&framework->shutdown.mutex);
-
- if (!alreadyInitialized) {
- celixThread_create(&framework->shutdown.thread, NULL, framework_shutdown, framework);
- }
- } else {
- status = CELIX_FRAMEWORK_EXCEPTION;
- }
-
- framework_logIfError(framework->logger, status, NULL, "Failed to stop framework activator");
-
- return status;
-}
-
-static celix_status_t frameworkActivator_destroy(void * userData, bundle_context_t *context) {
- return CELIX_SUCCESS;
-}
-
-
/**********************************************************************************************************************
**********************************************************************************************************************
* Updated API
diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h
index 2482b352..0f8bcfbf 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -522,6 +522,12 @@ bool celix_framework_removeScheduledEvent(celix_framework_t* fw, bool async, boo
*/
void celix_framework_cleanupScheduledEvents(celix_framework_t* fw, long bndId);
+
+/**
+ * @brief Start the celix framework shutdown sequence on a separate thread and return immediately.
+ */
+void celix_framework_shutdownAsync(celix_framework_t* framework);
+
#ifdef __cplusplus
}
#endif