This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/additional_component_states in repository https://gitbox.apache.org/repos/asf/celix.git
commit 2eca5a7944a68e427fcbcd7b5a64d11ec6c52679 Author: Pepijn Noltes <[email protected]> AuthorDate: Sun May 8 22:45:47 2022 +0200 Refactors celix cmp to include intermediate states --- documents/diagrams/component_lifecycle.puml | 47 +++++ .../gtest/src/DependencyManagerTestSuite.cc | 37 +++- libs/framework/include/celix/dm/Component.h | 39 +++- libs/framework/include/celix_dm_component.h | 15 +- libs/framework/src/dm_component_impl.c | 197 ++++++++++++++------- 5 files changed, 252 insertions(+), 83 deletions(-) diff --git a/documents/diagrams/component_lifecycle.puml b/documents/diagrams/component_lifecycle.puml new file mode 100644 index 00000000..c27fa33e --- /dev/null +++ b/documents/diagrams/component_lifecycle.puml @@ -0,0 +1,47 @@ +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. + +@startuml +state "Waiting for Required" as WaitingForRequired +state "Initialized And Waiting For Required" as Initialized + +[*] -down-> Inactive +Inactive -left-> [*] +Inactive -right-> WaitingForRequired +WaitingForRequired -down-> Initializing +Initializing -down-> Initialized + +state Active { + state "Tracking Optional Dependencies" as TrackingOptional + [*] -> Starting + Starting -down-> TrackingOptional + TrackingOptional -> Suspending + Suspending -> Suspended + Suspended -> Resuming + Resuming --> TrackingOptional + TrackingOptional --> Stopping + Stopping -left-> [*] +} + +Initialized -> Active +Active -> Initialized + +Initialized -down-> Deinitializing +Deinitializing -down-> Inactive + + + + +@enduml \ No newline at end of file diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc index e55efaee..a07cbde9 100644 --- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc +++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc @@ -123,7 +123,7 @@ TEST_F(DependencyManagerTestSuite, DmComponentRemoveAllAsync) { EXPECT_EQ(1, count.load()); } -TEST_F(DependencyManagerTestSuite, CDmGetInfo) { +TEST_F(DependencyManagerTestSuite, DmGetInfo) { auto* mng = celix_bundleContext_getDependencyManager(ctx); auto* cmp = celix_dmComponent_create(ctx, "test1"); @@ -207,7 +207,7 @@ TEST_F(DependencyManagerTestSuite, CxxDmGetInfo) { auto& cmpInfo = info.components[0]; EXPECT_TRUE(!cmpInfo.uuid.empty()); EXPECT_EQ(cmpInfo.name, "Cmp1"); - EXPECT_EQ(cmpInfo.state, "WAITING_FOR_REQUIRED"); + EXPECT_EQ(cmpInfo.state, "CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED"); EXPECT_FALSE(cmpInfo.isActive); EXPECT_EQ(cmpInfo.nrOfTimesStarted, 0); EXPECT_EQ(cmpInfo.nrOfTimesResumed, 0); @@ -641,13 +641,13 @@ TEST_F(DependencyManagerTestSuite, UnneededSuspendIsPrevented) { celix::dm::DependencyManager dm{ctx}; //cmp1 has lifecycle callbacks, but not set or add/rem callbacks for the service dependency -> should not trigger suspend - auto& cmp1 = dm.createComponent<CounterComponent>() + auto& cmp1 = dm.createComponent<CounterComponent>("CounterCmp1") .setCallbacks(nullptr, &CounterComponent::start, &CounterComponent::stop, nullptr); cmp1.createServiceDependency<TestService>(); cmp1.build(); //cmp2 has lifecycle callbacks and set, add/rem callbacks for the service dependency -> should trigger suspend 2x - auto& cmp2 = dm.createComponent<CounterComponent>() + auto& cmp2 = dm.createComponent<CounterComponent>("CounterCmp2") .setCallbacks(nullptr, &CounterComponent::start, &CounterComponent::stop, nullptr); cmp2.createServiceDependency<TestService>() .setCallbacks(&CounterComponent::setService) @@ -788,6 +788,35 @@ TEST_F(DependencyManagerTestSuite, installBundleWithDepManActivator) { celix_arrayList_destroy(list); } +TEST_F(DependencyManagerTestSuite, testStateToString) { + const char* state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_INACTIVE); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_INACTIVE"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_INITIALIZING); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_INITIALIZING"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_DEINITIALIZING); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_DEINITIALIZING"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_STARTING); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_STARTING"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_STOPPING); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_STOPPING"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_TRACKING_OPTIONAL); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_TRACKING_OPTIONAL"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_SUSPENDING); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_SUSPENDING"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_SUSPENDED); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_SUSPENDED"); + state = celix_dmComponent_stateToString(CELIX_DM_CMP_STATE_RESUMING); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_RESUMING"); + state = celix_dmComponent_stateToString((celix_dm_component_state_enum)0); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_INACTIVE"); + state = celix_dmComponent_stateToString((celix_dm_component_state_enum)16); + EXPECT_STREQ(state, "CELIX_DM_CMP_STATE_INACTIVE"); +} + #if __cplusplus >= 201703L //C++17 or higher class TestInterfaceWithStaticInfo { diff --git a/libs/framework/include/celix/dm/Component.h b/libs/framework/include/celix/dm/Component.h index 6c9004db..d101b35f 100644 --- a/libs/framework/include/celix/dm/Component.h +++ b/libs/framework/include/celix/dm/Component.h @@ -41,10 +41,17 @@ namespace celix { namespace dm { enum class ComponentState { - INACTIVE = 1, - WAITING_FOR_REQUIRED = 2, - INSTANTIATED_AND_WAITING_FOR_REQUIRED = 3, - TRACKING_OPTIONAL = 4, + INACTIVE = 1, + WAITING_FOR_REQUIRED = 2, + INITIALIZING = 3, + DEINITIALIZING = 4, + INSTANTIATED_AND_WAITING_FOR_REQUIRED = 5, + STARTING = 6, + STOPPING = 7, + TRACKING_OPTIONAL = 8, + SUSPENDING = 9, + SUSPENDED = 10, + RESUMING = 11, }; class BaseComponent { @@ -90,14 +97,28 @@ namespace celix { namespace dm { ComponentState getState() const { auto cState = celix_dmComponent_currentState(cCmp); switch (cState) { - case DM_CMP_STATE_INACTIVE: - return ComponentState::INACTIVE; - case DM_CMP_STATE_WAITING_FOR_REQUIRED: + case CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED: return ComponentState::WAITING_FOR_REQUIRED; - case DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED: + case CELIX_DM_CMP_STATE_INITIALIZING: + return ComponentState::INITIALIZING; + case CELIX_DM_CMP_STATE_DEINITIALIZING: + return ComponentState::DEINITIALIZING; + case CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED: return ComponentState::INSTANTIATED_AND_WAITING_FOR_REQUIRED; - default: + case CELIX_DM_CMP_STATE_STARTING: + return ComponentState::STARTING; + case CELIX_DM_CMP_STATE_STOPPING: + return ComponentState::STOPPING; + case CELIX_DM_CMP_STATE_TRACKING_OPTIONAL: return ComponentState::TRACKING_OPTIONAL; + case CELIX_DM_CMP_STATE_SUSPENDING: + return ComponentState::SUSPENDING; + case CELIX_DM_CMP_STATE_SUSPENDED: + return ComponentState::SUSPENDED; + case CELIX_DM_CMP_STATE_RESUMING: + return ComponentState::RESUMING; + default: + return ComponentState::INACTIVE; } } diff --git a/libs/framework/include/celix_dm_component.h b/libs/framework/include/celix_dm_component.h index 29d3cb3d..885a46b2 100644 --- a/libs/framework/include/celix_dm_component.h +++ b/libs/framework/include/celix_dm_component.h @@ -35,10 +35,17 @@ extern "C" { #define CELIX_DM_COMPONENT_UUID "component.uuid" typedef enum celix_dm_component_state_enum { - DM_CMP_STATE_INACTIVE = 1, - DM_CMP_STATE_WAITING_FOR_REQUIRED = 2, - DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED = 3, - DM_CMP_STATE_TRACKING_OPTIONAL = 4, + CELIX_DM_CMP_STATE_INACTIVE = 1, + CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED = 2, + CELIX_DM_CMP_STATE_INITIALIZING = 3, + CELIX_DM_CMP_STATE_DEINITIALIZING = 4, + CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED = 5, + CELIX_DM_CMP_STATE_STARTING = 6, + CELIX_DM_CMP_STATE_STOPPING = 7, + CELIX_DM_CMP_STATE_TRACKING_OPTIONAL = 8, + CELIX_DM_CMP_STATE_SUSPENDING = 9, + CELIX_DM_CMP_STATE_SUSPENDED = 10, + CELIX_DM_CMP_STATE_RESUMING = 11, } celix_dm_component_state_t; #define CELIX_DM_COMPONENT_MAX_ID_LENGTH 64 diff --git a/libs/framework/src/dm_component_impl.c b/libs/framework/src/dm_component_impl.c index c456487d..c4544f75 100644 --- a/libs/framework/src/dm_component_impl.c +++ b/libs/framework/src/dm_component_impl.c @@ -57,6 +57,12 @@ struct celix_dm_component_struct { size_t nrOfTimesResumed; bool isEnabled; + + /** + * Whether the component is an a transition (active performTransition call). + * Should only be used inside the Celix event Thread -> no locking needed. + */ + bool inTransition; }; typedef struct dm_interface_struct { @@ -83,6 +89,7 @@ static void celix_dmComponent_disableDirectly(celix_dm_component_t *component); static celix_status_t celix_dmComponent_disableDependencies(celix_dm_component_t *component); static bool celix_dmComponent_isDisabled(celix_dm_component_t *component); static void celix_dmComponent_cleanupRemovedDependencies(celix_dm_component_t* component); +static bool celix_dmComponent_isActiveInternal(celix_dm_component_t *component); celix_dm_component_t* celix_dmComponent_create(bundle_context_t *context, const char* name) { @@ -123,7 +130,7 @@ celix_dm_component_t* celix_dmComponent_createWithUUID(bundle_context_t *context component->callbackStart = NULL; component->callbackStop = NULL; component->callbackDeinit = NULL; - component->state = DM_CMP_STATE_INACTIVE; + component->state = CELIX_DM_CMP_STATE_INACTIVE; component->setCLanguageProperty = false; component->providedInterfaces = celix_arrayList_create(); @@ -251,7 +258,7 @@ celix_status_t celix_dmComponent_addServiceDependency(celix_dm_component_t *comp celixThreadMutex_lock(&component->mutex); arrayList_add(component->dependencies, dep); - bool startDep = component->state != DM_CMP_STATE_INACTIVE; + bool startDep = component->state != CELIX_DM_CMP_STATE_INACTIVE; if (startDep) { celix_dmServiceDependency_enable(dep); } @@ -266,7 +273,7 @@ celix_status_t celix_dmComponent_removeServiceDependency(celix_dm_component_t *c celixThreadMutex_lock(&component->mutex); celix_arrayList_remove(component->dependencies, dep); - bool disableDependency = component->state != DM_CMP_STATE_INACTIVE; + bool disableDependency = component->state != CELIX_DM_CMP_STATE_INACTIVE; if (disableDependency) { celix_dmServiceDependency_disable(dep); } @@ -344,7 +351,7 @@ static celix_status_t celix_dmComponent_disable(celix_dm_component_t *component) */ static void celix_dmComponent_disableDirectly(celix_dm_component_t *component) { component->isEnabled = false; - component->state = DM_CMP_STATE_INACTIVE; + component->state = CELIX_DM_CMP_STATE_INACTIVE; celix_dmComponent_unregisterServices(component, false); celix_dmComponent_disableDependencies(component); } @@ -389,7 +396,7 @@ static bool celix_dmComponent_isDisabled(celix_dm_component_t *component) { celixThreadMutex_lock(&component->mutex); isStopped = !component->isEnabled && - component->state == DM_CMP_STATE_INACTIVE && + component->state == CELIX_DM_CMP_STATE_INACTIVE && celix_dmComponent_areAllDependenciesDisabled(component); celixThreadMutex_unlock(&component->mutex); return isStopped; @@ -432,7 +439,7 @@ celix_status_t celix_dmComponent_addInterface(celix_dm_component_t *component, c interface->properties = properties; interface->svcId= -1L; celix_arrayList_add(component->providedInterfaces, interface); - if (component->state == DM_CMP_STATE_TRACKING_OPTIONAL) { + if (component->state == CELIX_DM_CMP_STATE_TRACKING_OPTIONAL) { celix_dmComponent_registerServices(component, false); } celixThreadMutex_unlock(&component->mutex); @@ -517,49 +524,69 @@ celix_status_t celix_private_dmComponent_handleEvent(celix_dm_component_t *compo static celix_status_t celix_dmComponent_suspend(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency) { celix_status_t status = CELIX_SUCCESS; if (component->callbackStop != NULL) { + celixThreadMutex_lock(&component->mutex); + component->state = CELIX_DM_CMP_STATE_SUSPENDING; celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_TRACE, "Suspending component %s (uuid=%s)", component->name, component->uuid); - celix_dmComponent_unregisterServices(component, true); + celix_dmComponent_unregisterServices(component, false); status = component->callbackStop(component->implementation); - if (status != CELIX_SUCCESS) { + if (status == CELIX_SUCCESS) { + component->state = CELIX_DM_CMP_STATE_SUSPENDED; + celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_TRACE, + "Suspended component %s (uuid=%s)", + component->name, + component->uuid); + } else { celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_ERROR, - "Error stopping component %s (uuid=%s) using the stop callback", + "Error stopping component %s (uuid=%s) using the stop callback. Disabling component.", component->name, component->uuid); + celix_dmComponent_disableDirectly(component); } + celixThreadMutex_unlock(&component->mutex); } return status; } static celix_status_t celix_dmComponent_resume(celix_dm_component_t *component, celix_dm_service_dependency_t *dependency) { celix_status_t status = CELIX_SUCCESS; - if (component->callbackStart != NULL) { - //ensure that the current state is still TRACKING_OPTION. Else during a add/rem/set call a required svc dep has been added. + celixThreadMutex_lock(&component->mutex); + if (component->state == CELIX_DM_CMP_STATE_SUSPENDED) { + component->state = CELIX_DM_CMP_STATE_RESUMING; celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_TRACE, "Resuming component %s (uuid=%s)", component->name, component->uuid); status = component->callbackStart(component->implementation); if (status == CELIX_SUCCESS) { - celix_dmComponent_registerServices(component, true); + celix_dmComponent_registerServices(component, false); component->nrOfTimesResumed += 1; + component->state = CELIX_DM_CMP_STATE_TRACKING_OPTIONAL; + celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_TRACE, + "Resumed component %s (uuid=%s)", + component->name, + component->uuid); } else { celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_ERROR, - "Error starting component %s (uuid=%s) using the start callback", + "Error starting component %s (uuid=%s) using the start callback. Disabling component.", component->name, component->uuid); + celixThreadMutex_lock(&component->mutex); + celix_dmComponent_disableDirectly(component); + celixThreadMutex_unlock(&component->mutex); } - } - return status; + } + celixThreadMutex_unlock(&component->mutex); + return status; } static bool celix_dmComponent_needsSuspend(celix_dm_component_t *component, const celix_dm_event_t* event) { bool cmpActive = false; celixThreadMutex_lock(&component->mutex); switch (component->state) { - case DM_CMP_STATE_TRACKING_OPTIONAL: + case CELIX_DM_CMP_STATE_TRACKING_OPTIONAL: cmpActive = true; break; default: //DM_CMP_STATE_INACTIVE @@ -586,6 +613,17 @@ static celix_status_t celix_dmComponent_handleEvent(celix_dm_component_t *compon component->uuid, event->dep->serviceName); + + if (component->inTransition) { + /* Note if the component is already in transition (stopping, starting, etc) then only remove the svc + * function pointers. This can happen when with dependency loops or if a component also depends on a + * services it provides. (e.g. during stopping the component a handle event will be created to remove the + * service dependency). + */ + setAddOrRemFp(event->dep, event->svc, event->props); + return CELIX_SUCCESS; + } + bool eventHandled = false; if (event->eventType == CELIX_DM_EVENT_SVC_ADD || (event->eventType == CELIX_DM_EVENT_SVC_SET && event->svc != NULL)) { //note adding service or setting new service, so cmp will not be stopped in handleChange -> use suspend / resume now @@ -705,41 +743,49 @@ static celix_status_t celix_dmComponent_calculateNewState(celix_dm_component_t * celix_status_t status = CELIX_SUCCESS; bool allResolved = celix_dmComponent_areAllRequiredServiceDependenciesResolved(component); - if (currentState == DM_CMP_STATE_INACTIVE) { + if (currentState == CELIX_DM_CMP_STATE_INACTIVE) { if (component->isEnabled) { - *newState = DM_CMP_STATE_WAITING_FOR_REQUIRED; + *newState = CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED; } else { *newState = currentState; } - } else if (currentState == DM_CMP_STATE_WAITING_FOR_REQUIRED) { + } else if (currentState == CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED) { if (!component->isEnabled) { - *newState = DM_CMP_STATE_INACTIVE; + *newState = CELIX_DM_CMP_STATE_INACTIVE; } else { if (allResolved) { - *newState = DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED; + *newState = CELIX_DM_CMP_STATE_INITIALIZING; } else { *newState = currentState; } } - } else if (currentState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) { + } else if (currentState == CELIX_DM_CMP_STATE_INITIALIZING) { + *newState = CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED; + } else if (currentState == CELIX_DM_CMP_STATE_DEINITIALIZING) { + *newState = CELIX_DM_CMP_STATE_INACTIVE; + } else if (currentState == CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED) { if (!component->isEnabled) { - *newState = DM_CMP_STATE_WAITING_FOR_REQUIRED; + *newState = CELIX_DM_CMP_STATE_DEINITIALIZING; } else { if (allResolved) { - *newState = DM_CMP_STATE_TRACKING_OPTIONAL; + *newState = CELIX_DM_CMP_STATE_STARTING; } else { *newState = currentState; } } - } else if (currentState == DM_CMP_STATE_TRACKING_OPTIONAL) { + } else if (currentState == CELIX_DM_CMP_STATE_STARTING) { + *newState = CELIX_DM_CMP_STATE_TRACKING_OPTIONAL; + } else if (currentState == CELIX_DM_CMP_STATE_STOPPING) { + *newState = CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED; + } else if (currentState == CELIX_DM_CMP_STATE_TRACKING_OPTIONAL) { if (component->isEnabled && allResolved) { *newState = currentState; } else { - *newState = DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED; + *newState = CELIX_DM_CMP_STATE_STOPPING; } } else { //should not reach - *newState = DM_CMP_STATE_INACTIVE; + *newState = CELIX_DM_CMP_STATE_INACTIVE; status = CELIX_BUNDLE_EXCEPTION; } @@ -756,6 +802,7 @@ static bool celix_dmComponent_performTransition(celix_dm_component_t *component, if (currentState == desiredState) { return false; } + component->inTransition = true; celix_bundleContext_log(component->context, CELIX_LOG_LEVEL_TRACE, @@ -766,13 +813,24 @@ static bool celix_dmComponent_performTransition(celix_dm_component_t *component, celix_dmComponent_stateToString(desiredState)); celix_status_t status = CELIX_SUCCESS; - if (currentState == DM_CMP_STATE_INACTIVE && desiredState == DM_CMP_STATE_WAITING_FOR_REQUIRED) { + if (currentState == CELIX_DM_CMP_STATE_INACTIVE && desiredState == CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED) { celix_dmComponent_enableDependencies(component); - } else if (currentState == DM_CMP_STATE_WAITING_FOR_REQUIRED && desiredState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) { + } else if (currentState == CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED && desiredState == CELIX_DM_CMP_STATE_INITIALIZING) { + //nop + } else if (currentState == CELIX_DM_CMP_STATE_INITIALIZING && desiredState == CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED) { if (component->callbackInit) { - status = component->callbackInit(component->implementation); + status = component->callbackInit(component->implementation); } - } else if (currentState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED && desiredState == DM_CMP_STATE_TRACKING_OPTIONAL) { + } else if (currentState == CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED && desiredState == CELIX_DM_CMP_STATE_DEINITIALIZING) { + //nop + } else if (currentState == CELIX_DM_CMP_STATE_DEINITIALIZING && desiredState == CELIX_DM_CMP_STATE_INACTIVE) { + if (component->callbackDeinit) { + status = component->callbackDeinit(component->implementation); + } + celix_dmComponent_disableDependencies(component); + } else if (currentState == CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED && desiredState == CELIX_DM_CMP_STATE_STARTING) { + //nop + } else if (currentState == CELIX_DM_CMP_STATE_STARTING && desiredState == CELIX_DM_CMP_STATE_TRACKING_OPTIONAL) { if (component->callbackStart) { status = component->callbackStart(component->implementation); } @@ -780,16 +838,14 @@ static bool celix_dmComponent_performTransition(celix_dm_component_t *component, celix_dmComponent_registerServices(component, false); component->nrOfTimesStarted += 1; } - } else if (currentState == DM_CMP_STATE_TRACKING_OPTIONAL && desiredState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED) { + } else if (currentState == CELIX_DM_CMP_STATE_TRACKING_OPTIONAL && desiredState == CELIX_DM_CMP_STATE_STOPPING) { + //nop + } else if (currentState == CELIX_DM_CMP_STATE_STOPPING && desiredState == CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED) { celix_dmComponent_unregisterServices(component, false); if (component->callbackStop) { status = component->callbackStop(component->implementation); } - } else if (currentState == DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED && desiredState == DM_CMP_STATE_WAITING_FOR_REQUIRED) { - if (component->callbackDeinit) { - status = component->callbackDeinit(component->implementation); - } - } else if (currentState == DM_CMP_STATE_WAITING_FOR_REQUIRED && desiredState == DM_CMP_STATE_INACTIVE) { + } else if (currentState == CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED && desiredState == CELIX_DM_CMP_STATE_INACTIVE) { celix_dmComponent_disableDependencies(component); } else { assert(false); //should not be reached. @@ -809,6 +865,7 @@ static bool celix_dmComponent_performTransition(celix_dm_component_t *component, celix_dmComponent_disableDirectly(component); } + component->inTransition = false; return transition; } @@ -964,25 +1021,8 @@ celix_status_t celix_dmComponent_getComponentInfo(celix_dm_component_t *componen memcpy(info->name, component->name, DM_COMPONENT_MAX_NAME_LENGTH); info->nrOfTimesStarted = component->nrOfTimesStarted; info->nrOfTimesResumed = component->nrOfTimesResumed; - - switch (component->state) { - case DM_CMP_STATE_INACTIVE : - info->state = strdup("INACTIVE"); - break; - case DM_CMP_STATE_WAITING_FOR_REQUIRED : - info->state = strdup("WAITING_FOR_REQUIRED"); - break; - case DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED : - info->state = strdup("INSTANTIATED_AND_WAITING_FOR_REQUIRED"); - break; - case DM_CMP_STATE_TRACKING_OPTIONAL : - info->state = strdup("TRACKING_OPTIONAL"); - info->active = true; - break; - default : - info->state = strdup("UNKNOWN"); - break; - } + info->state = celix_utils_strdup(celix_dmComponent_stateToString(component->state)); + info->active = celix_dmComponent_isActiveInternal(component); for (int i = 0; i < celix_arrayList_size(component->dependencies); i += 1) { celix_dm_service_dependency_t *dep = celix_arrayList_get(component->dependencies, i); @@ -1027,22 +1067,47 @@ void celix_dmComponent_destroyComponentInfo(dm_component_info_pt info) { free(info); } +static bool celix_dmComponent_isActiveInternal(celix_dm_component_t *component) { + //precondition: mutex component->mutex taken. + return + component->state == CELIX_DM_CMP_STATE_STARTING || + component->state == CELIX_DM_CMP_STATE_TRACKING_OPTIONAL || + component->state == CELIX_DM_CMP_STATE_SUSPENDING || + component->state == CELIX_DM_CMP_STATE_SUSPENDED || + component->state == CELIX_DM_CMP_STATE_RESUMING || + component->state == CELIX_DM_CMP_STATE_STOPPING; +} + bool celix_dmComponent_isActive(celix_dm_component_t *component) { celixThreadMutex_lock(&component->mutex); - bool active = component->state == DM_CMP_STATE_TRACKING_OPTIONAL; + bool isActivate = celix_dmComponent_isActiveInternal(component); celixThreadMutex_unlock(&component->mutex); - return active; + return isActivate; } const char* celix_dmComponent_stateToString(celix_dm_component_state_t state) { switch(state) { - case DM_CMP_STATE_INACTIVE: - return "DM_CMP_STATE_INACTIVE"; - case DM_CMP_STATE_WAITING_FOR_REQUIRED: - return "DM_CMP_STATE_WAITING_FOR_REQUIRED"; - case DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED: - return "DM_CMP_STATE_INSTANTIATED_AND_WAITING_FOR_REQUIRED"; - default: //only DM_CMP_STATE_TRACKING_OPTIONAL left - return "DM_CMP_STATE_TRACKING_OPTIONAL"; + case CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED: + return "CELIX_DM_CMP_STATE_WAITING_FOR_REQUIRED"; + case CELIX_DM_CMP_STATE_INITIALIZING: + return "CELIX_DM_CMP_STATE_INITIALIZING"; + case CELIX_DM_CMP_STATE_DEINITIALIZING: + return "CELIX_DM_CMP_STATE_DEINITIALIZING"; + case CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED: + return "CELIX_DM_CMP_STATE_INITIALIZED_AND_WAITING_FOR_REQUIRED"; + case CELIX_DM_CMP_STATE_STARTING: + return "CELIX_DM_CMP_STATE_STARTING"; + case CELIX_DM_CMP_STATE_STOPPING: + return "CELIX_DM_CMP_STATE_STOPPING"; + case CELIX_DM_CMP_STATE_TRACKING_OPTIONAL: + return "CELIX_DM_CMP_STATE_TRACKING_OPTIONAL"; + case CELIX_DM_CMP_STATE_SUSPENDING: + return "CELIX_DM_CMP_STATE_SUSPENDING"; + case CELIX_DM_CMP_STATE_SUSPENDED: + return "CELIX_DM_CMP_STATE_SUSPENDED"; + case CELIX_DM_CMP_STATE_RESUMING: + return "CELIX_DM_CMP_STATE_RESUMING"; + default: //only CELIX_DM_CMP_STATE_INACTIVE left + return "CELIX_DM_CMP_STATE_INACTIVE"; } }
