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 <[email protected]> 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
