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 1af0812458d2f06fccafe85197e1420a82f8d6e6 Author: Pepijn Noltes <[email protected]> AuthorDate: Tue Jun 27 20:05:50 2023 +0200 Add initial setup for OSGi-like conditions --- documents/conditions.md | 23 +++++ libs/framework/CMakeLists.txt | 1 + libs/framework/include/celix_condition.h | 92 ++++++++++++++++++++ libs/framework/src/celix_framework_conditions.c | 107 +++++++++++++++++++++++ libs/framework/src/celix_framework_conditions.h | 73 ++++++++++++++++ libs/framework/src/framework.c | 108 +++++++++++++++--------- libs/framework/src/framework_private.h | 6 ++ 7 files changed, 371 insertions(+), 39 deletions(-) diff --git a/documents/conditions.md b/documents/conditions.md new file mode 100644 index 00000000..b2c170ee --- /dev/null +++ b/documents/conditions.md @@ -0,0 +1,23 @@ +--- +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/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt index 82968846..a0c71fc8 100644 --- a/libs/framework/CMakeLists.txt +++ b/libs/framework/CMakeLists.txt @@ -34,6 +34,7 @@ set(FRAMEWORK_SRC src/framework_bundle_lifecycle_handler.c src/celix_bundle_state.c src/celix_framework_utils.c + src/celix_framework_conditions.c src/celix_module_private.h) set(FRAMEWORK_DEPS libuuid::libuuid CURL::libcurl ZLIB::ZLIB ${CMAKE_DL_LIBS}) diff --git a/libs/framework/include/celix_condition.h b/libs/framework/include/celix_condition.h new file mode 100644 index 00000000..55fe37a1 --- /dev/null +++ b/libs/framework/include/celix_condition.h @@ -0,0 +1,92 @@ +/* + * 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_CONDITION_H_ +#define CELIX_CONDITION_H_ + +#include "celix_framework_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief The name of the condition service. + */ +#define CELIX_CONDITION_SERVICE_NAME "celix_condition" + +/*! + * @brief The version of the condition service. + */ +#define CELIX_CONDITION_SERVICE_VERSION "1.0.0" + +/*! + * @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" + +/*! + * @brief The unique identifier for the default True condition. + * The default True condition is registered by the framework during framework initialization and therefore + * can always be relied upon. + */ +#define CELIX_CONDITION_ID_TRUE "true" + +/*! + * @brief The unique identifier for the framework ready condition. + * The framework ready condition is registered by the framework after all install configured bundles are installed, + * all start configured bundles are started and after the Apache Celix Event Queue becomes empty. + * + * Note that after the framework ready condition is registered, the event queue can become non-empty again. + * For example if a component depends on the "framework.ready" condition. + */ +#define CELIX_CONDITION_ID_FRAMEWORK_READY "framework.ready" + +/** + * @brief Celix condition service struct. + * + * In dynamic systems, such as OSGi and Apache Celix, one of the more challenging problems can be to define when + * a system or part of it is ready to do work. The answer can change depending on the individual perspective. + * The developer of a web server might say, the system is ready when the server starts listening on port 80. + * An application developer however would define the system as ready when the database connection is up and all + * servlets are registered. Taking the application developers view, the web server should start listening on + * port 80 when the application is ready and not beforehand. + * + * The Condition service interface is a marker interface designed to address this issue. + * Its role is to provide a dependency that can be tracked. It acts as a defined signal to other services. + * + * A Condition service must be registered with the "celix.condition.id" service property. + */ +typedef struct celix_condition { + void* handle; /**< private dummy handle, note not used in marker service struct, but added to ensure + 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 + +#endif /* CELIX_CONDITION_H_ */ diff --git a/libs/framework/src/celix_framework_conditions.c b/libs/framework/src/celix_framework_conditions.c new file mode 100644 index 00000000..3105baf3 --- /dev/null +++ b/libs/framework/src/celix_framework_conditions.c @@ -0,0 +1,107 @@ +/* +* 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 "framework_private.h" +#include "celix_condition.h" +#include "celix_constants.h" + +void celix_frameworkConditions_registerInitialConditions(celix_framework_t* framework) { + long svcId = -1L; + celix_bundle_context_t* ctx = celix_framework_getFrameworkContext(framework); + celixThreadMutex_lock(&framework->conditions.mutex); + 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 = &CELIX_CONDITION_INSTANCE; + opts.properties = celix_properties_create(); + if (opts.properties) { + celix_properties_set(opts.properties, CELIX_CONDITION_ID, CELIX_CONDITION_ID_FRAMEWORK_READY); + svcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); + } + celix_status_t addStatus = celix_arrayList_add(framework->conditions.initialConditionSvcIds, (void*)svcId); + if (addStatus != CELIX_SUCCESS) { + celix_bundleContext_unregisterService(ctx, svcId); + fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Error adding initial condition service id to list"); + } + celixThreadMutex_unlock(&framework->conditions.mutex); +} + +void celix_frameworkConditions_unregisterInitialConditions(celix_framework_t* framework) { + celix_bundle_context_t* ctx = celix_framework_getFrameworkContext(framework); + celixThreadMutex_lock(&framework->conditions.mutex); + for (int i = 0; i < celix_arrayList_size(framework->conditions.initialConditionSvcIds); ++i) { + long svcId = (long)celix_arrayList_get(framework->conditions.initialConditionSvcIds, i); + celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL); + } + celix_arrayList_clear(framework->conditions.initialConditionSvcIds); + celixThreadMutex_unlock(&framework->conditions.mutex); +} + +static void celix_frameworkConditions_checkFrameworkReady(void* data) { + celix_framework_t* framework = data; + celix_bundle_context_t* ctx = celix_framework_getFrameworkContext(framework); + + celixThreadMutex_lock(&framework->dispatcher.mutex); + bool isEventQueueEmpty = framework->dispatcher.eventQueueSize == 0 && celix_arrayList_size(framework->dispatcher.dynamicEventQueue) == 0; + bool isActive = framework->dispatcher.active; + celixThreadMutex_unlock(&framework->dispatcher.mutex); + + if (!isActive) { + fw_log(framework->logger, CELIX_LOG_LEVEL_DEBUG, "Framework is not active anymore, so no need to register the framework ready condition"); + return; + } + + if (isEventQueueEmpty) { + celixThreadMutex_lock(&framework->conditions.mutex); + 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 = &CELIX_CONDITION_INSTANCE; + opts.properties = celix_properties_create(); + if (opts.properties) { + celix_properties_set(opts.properties, CELIX_CONDITION_ID, CELIX_CONDITION_ID_FRAMEWORK_READY); + long svcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); + celix_status_t addStatus = celix_arrayList_add(framework->conditions.frameworkReadyConditionSvcIds, (void*)svcId); + if (addStatus != CELIX_SUCCESS) { + celix_bundleContext_unregisterService(ctx, svcId); + fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Error adding framework ready condition service id to list"); + } + } + celixThreadMutex_unlock(&framework->conditions.mutex); + } else { + //try again later on the event queue + celix_framework_fireGenericEvent(framework, -1, CELIX_FRAMEWORK_BUNDLE_ID, "Check event queue for framework ready condition service", framework, celix_frameworkConditions_checkFrameworkReady, NULL, NULL); + } +} + +void celix_frameworkConditions_registerFrameworkReadyConditions(celix_framework_t* framework) { + //note called when all bundles are installed and started + celix_frameworkConditions_checkFrameworkReady(framework); +} + +void celix_frameworkConditions_unregisterFrameworkReadyConditions(celix_framework_t* framework) { + celix_bundle_context_t* ctx = celix_framework_getFrameworkContext(framework); + celixThreadMutex_lock(&framework->conditions.mutex); + for (int i = 0; i < celix_arrayList_size(framework->conditions.frameworkReadyConditionSvcIds); ++i) { + long svcId = (long)celix_arrayList_get(framework->conditions.frameworkReadyConditionSvcIds, i); + celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL); + } + celix_arrayList_clear(framework->conditions.frameworkReadyConditionSvcIds); + celixThreadMutex_unlock(&framework->conditions.mutex); +} \ No newline at end of file diff --git a/libs/framework/src/celix_framework_conditions.h b/libs/framework/src/celix_framework_conditions.h new file mode 100644 index 00000000..cf9c14ff --- /dev/null +++ b/libs/framework/src/celix_framework_conditions.h @@ -0,0 +1,73 @@ +/* +* 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_CELIX_FRAMEWORK_CONDITIONS_H_ +#define CELIX_CELIX_FRAMEWORK_CONDITIONS_H_ + +#include "celix_types.h" +#include "celix_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Register the initial celix_condition services for the framework. + * + * The initial celix_condition services are: + * - The true celix_condition service + * + * Will log an error if the initial celix_condition services administration objects or services registrations + * fail. + * + * @param[in] framework The framework. + */ +void celix_frameworkConditions_registerInitialConditions(celix_framework_t* framework); + +/** + * @brief Unregister the initial celix_condition services for the framework. + * @param[in] framework The framework. + */ +void celix_frameworkConditions_unregisterInitialConditions(celix_framework_t* framework); + +/** + * @brief Register the framework ready celix_condition services for the framework. + * + * The framework ready celix_condition services are: + * - The framework.ready celix_condition service + * + * Will log an error if the framework read celix_condition services administration objects or services registrations + * fail. + * + * @param framework The framework. + */ +void celix_frameworkConditions_registerFrameworkReadyConditions(celix_framework_t* framework); + +/** + * @brief Unregister the framework ready celix_condition services for the framework. + * @param framework The framework. + */ +void celix_frameworkConditions_unregisterFrameworkReadyConditions(celix_framework_t* framework); + + +#ifdef __cplusplus +} +#endif + +#endif // CELIX_CELIX_FRAMEWORK_CONDITIONS_H_ diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c index 0a2d1dc6..8962d0f8 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_conditions.h" #include "bundle_archive_private.h" #include "bundle_context_private.h" @@ -176,10 +177,10 @@ static celix_status_t frameworkActivator_start(void * userData, bundle_context_t 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 void framework_autoStartConfiguredBundles(celix_framework_t *fw); -static void framework_autoInstallConfiguredBundles(celix_framework_t *fw); -static void framework_autoInstallConfiguredBundlesForList(celix_framework_t *fw, const char *autoStart, celix_array_list_t *installedBundles); -static void framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const celix_array_list_t *installedBundles); +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); +static celix_status_t framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const celix_array_list_t *installedBundles); static void celix_framework_addToEventQueue(celix_framework_t *fw, const celix_framework_event_t* event); struct fw_bundleListener { @@ -255,6 +256,10 @@ celix_status_t framework_create(framework_pt *out, celix_properties_t* config) { framework->dispatcher.eventQueue = malloc(sizeof(celix_framework_event_t) * framework->dispatcher.eventQueueCap); framework->dispatcher.dynamicEventQueue = celix_arrayList_create(); + celixThreadMutex_create(&framework->conditions.mutex, NULL); + framework->conditions.initialConditionSvcIds = celix_arrayList_create(); + framework->conditions.frameworkReadyConditionSvcIds = celix_arrayList_create(); + //create and store framework uuid char uuid[37]; uuid_t uid; @@ -456,47 +461,59 @@ celix_status_t fw_init(framework_pt framework) { return status; } -celix_status_t framework_start(framework_pt framework) { - celix_status_t status = CELIX_SUCCESS; - bundle_state_e state = CELIX_BUNDLE_STATE_UNKNOWN; +celix_status_t framework_start(celix_framework_t* framework) { + celix_status_t status = CELIX_SUCCESS; + bundle_state_e state = CELIX_BUNDLE_STATE_UNKNOWN; - status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); - if (status == CELIX_SUCCESS) { - if ((state == CELIX_BUNDLE_STATE_INSTALLED) || (state == CELIX_BUNDLE_STATE_RESOLVED)) { - status = CELIX_DO_IF(status, fw_init(framework)); + status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); + if (status == CELIX_SUCCESS) { + if ((state == CELIX_BUNDLE_STATE_INSTALLED) || (state == CELIX_BUNDLE_STATE_RESOLVED)) { + status = CELIX_DO_IF(status, fw_init(framework)); } - } + } - status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); - if (status == CELIX_SUCCESS && state == CELIX_BUNDLE_STATE_STARTING) { + status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); + if (status == CELIX_SUCCESS && state == CELIX_BUNDLE_STATE_STARTING) { bundle_setState(framework->bundle, CELIX_BUNDLE_STATE_ACTIVE); - } + } - celix_framework_bundle_entry_t* entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, - framework->bundleId); - CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry)); + celix_framework_bundle_entry_t* entry = + celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, framework->bundleId); + CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry)); celix_framework_bundleEntry_decreaseUseCount(entry); - CELIX_DO_IF(status, fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId)); + celix_frameworkConditions_registerInitialConditions(framework); + CELIX_DO_IF(status, fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId)); - if (status != CELIX_SUCCESS) { - status = CELIX_BUNDLE_EXCEPTION; - fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not start framework"); - fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, status); + if (status != CELIX_SUCCESS) { + status = CELIX_BUNDLE_EXCEPTION; + fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not start framework"); + fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, status); } - framework_autoStartConfiguredBundles(framework); - framework_autoInstallConfiguredBundles(framework); + celix_status_t startStatus = framework_autoStartConfiguredBundles(framework); + celix_status_t installStatus = framework_autoInstallConfiguredBundles(framework); + if (startStatus == CELIX_SUCCESS && installStatus == CELIX_SUCCESS) { + celix_frameworkConditions_registerFrameworkReadyConditions(framework); + } else { + status = CELIX_BUNDLE_EXCEPTION; //error already logged + } - if (status == CELIX_SUCCESS) { + if (status == CELIX_SUCCESS) { fw_log(framework->logger, CELIX_LOG_LEVEL_INFO, "Celix framework started"); - fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Celix framework started with uuid %s", celix_framework_getUUID(framework)); - } + fw_log(framework->logger, + CELIX_LOG_LEVEL_TRACE, + "Celix framework started with uuid %s", + celix_framework_getUUID(framework)); + } else { + fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Celix framework failed to start"); + } - return status; + return status; } -static void framework_autoStartConfiguredBundles(celix_framework_t* fw) { +static celix_status_t framework_autoStartConfiguredBundles(celix_framework_t* fw) { + celix_status_t status = CELIX_SUCCESS; const char* const cosgiKeys[] = {"cosgi.auto.start.0","cosgi.auto.start.1","cosgi.auto.start.2","cosgi.auto.start.3","cosgi.auto.start.4","cosgi.auto.start.5","cosgi.auto.start.6", NULL}; const char* const celixKeys[] = {CELIX_AUTO_START_0, CELIX_AUTO_START_1, CELIX_AUTO_START_2, CELIX_AUTO_START_3, CELIX_AUTO_START_4, CELIX_AUTO_START_5, CELIX_AUTO_START_6, NULL}; CELIX_BUILD_ASSERT(sizeof(*cosgiKeys) == sizeof(*celixKeys)); @@ -507,22 +524,30 @@ static void framework_autoStartConfiguredBundles(celix_framework_t* fw) { autoStart = celix_framework_getConfigProperty(fw, cosgiKeys[i], NULL, NULL); } if (autoStart != NULL) { - framework_autoInstallConfiguredBundlesForList(fw, autoStart, installedBundles); + if (framework_autoInstallConfiguredBundlesForList(fw, autoStart, installedBundles) != CELIX_SUCCESS) { + status = CELIX_BUNDLE_EXCEPTION; + } } } - framework_autoStartConfiguredBundlesForList(fw, installedBundles); + celix_status_t startStatus = framework_autoStartConfiguredBundlesForList(fw, installedBundles); + if (status == CELIX_SUCCESS) { + status = startStatus; + } celix_arrayList_destroy(installedBundles); + return status; } -static void framework_autoInstallConfiguredBundles(celix_framework_t* fw) { +static celix_status_t framework_autoInstallConfiguredBundles(celix_framework_t* fw) { const char* autoInstall = celix_framework_getConfigProperty(fw, CELIX_AUTO_INSTALL, NULL, NULL); if (autoInstall != NULL) { - framework_autoInstallConfiguredBundlesForList(fw, autoInstall, NULL); + return framework_autoInstallConfiguredBundlesForList(fw, autoInstall, NULL); } + return CELIX_SUCCESS; } -static void framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw, const char *autoStartIn, celix_array_list_t *installedBundles) { +static celix_status_t framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw, const char *autoStartIn, celix_array_list_t *installedBundles) { + celix_status_t status = CELIX_SUCCESS; char delims[] = " "; char *save_ptr = NULL; char autoStartBuffer[CELIX_DEFAULT_STRING_CREATE_BUFFER_SIZE]; @@ -538,6 +563,7 @@ static void framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw, } } else { fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not install bundle from location '%s'.", location); + status = CELIX_BUNDLE_EXCEPTION; } location = strtok_r(NULL, delims, &save_ptr); } @@ -545,9 +571,11 @@ static void framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw, fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not auto install bundles, out of memory."); } celix_utils_freeStringIfNotEqual(autoStartBuffer, autoStart); + return status;; } -static void framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const celix_array_list_t *installedBundles) { +static celix_status_t framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const celix_array_list_t *installedBundles) { + celix_status_t status = CELIX_SUCCESS; assert(!celix_framework_isCurrentThreadTheEventLoop(fw)); for (int i = 0; i < celix_arrayList_size(installedBundles); ++i) { long bndId = celix_arrayList_getLong(installedBundles, i); @@ -559,8 +587,10 @@ static void framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, c } } else { fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "Cannot start bundle %s (bnd id = %li), because it is already started\n", bnd->symbolicName, bndId); + status = CELIX_BUNDLE_EXCEPTION; } } + return status; } celix_status_t framework_stop(framework_pt framework) { @@ -1177,7 +1207,6 @@ static void* framework_shutdown(void *framework) { } celixThreadMutex_unlock(&fw->installedBundles.mutex); - size = celix_arrayList_size(stopEntries); for (int i = size-1; i >= 0; --i) { //note loop in reverse order -> stop later installed bundle first celix_framework_bundle_entry_t *entry = celix_arrayList_get(stopEntries, i); @@ -1196,7 +1225,6 @@ static void* framework_shutdown(void *framework) { } celix_arrayList_destroy(stopEntries); - // 'stop' framework bundle if (fwEntry != NULL) { bundle_t *bnd = fwEntry->bnd; @@ -1494,8 +1522,10 @@ static celix_status_t frameworkActivator_stop(void * userData, bundle_context_t 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)); + celix_frameworkConditions_unregisterFrameworkReadyConditions(framework); + celix_frameworkConditions_unregisterInitialConditions(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; diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h index d2a36cfc..a06a8c3b 100644 --- a/libs/framework/src/framework_private.h +++ b/libs/framework/src/framework_private.h @@ -188,6 +188,12 @@ struct celix_framework { celix_thread_mutex_t mutex; //protects below celix_array_list_t* bundleLifecycleHandlers; //entry = celix_framework_bundle_lifecycle_handler_t* } bundleLifecycleHandling; + + struct { + celix_thread_mutex_t mutex; /**< protects below*/ + celix_array_list_t* initialConditionSvcIds; /**< entry = long (service id) */ + celix_array_list_t* frameworkReadyConditionSvcIds; /**< entry = long (service id) */ + } conditions; /**< Struct to store the framework celix_conditions admin */ }; /**
