Repository navigation
Introduce new Component class
#705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
danth
wants to merge
17
commits into
eclipse-score:main
Choose a base branch
from
etas-contrib:pin-split
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
b073b46
Implement new component class
danth 272ad89
Move start action, stop action, ready condition to subfolders
danth 35ccc51
Add force stop actions
danth c65b2fb
Add empty actions
danth 3a021ba
Allow actions to return an error code
danth 83b7780
Add process actions
danth 68f64f9
Add unit tests for new actions
danth d166710
Add report running ready condition
danth 34a9e93
Pass through `stop_token` from the component to the actions
danth 9d7e84b
Use references rather than pointers in `Component`
danth d0b50d1
Use `cpp::span` rather than `std::vector` for ready conditions
danth ab51ecc
Add docstrings for new classes
danth ee959e0
Add file ready condition
danth f7df5af
Rename `force_stop` to `forceStop`
danth 04bc7e9
Replace `kNotImplemented` returns with panics
danth 39eef1f
Add component state machine
danth 35b8294
Make component identifier `const`
danth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
score/launch_manager/src/daemon/src/process_group_manager/details/component.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| /******************************************************************************** | ||
| * Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| * | ||
| * See the NOTICE file(s) distributed with this work for additional | ||
| * information regarding copyright ownership. | ||
| * | ||
| * This program and the accompanying materials are made available under the | ||
| * terms of the Apache License Version 2.0 which is available at | ||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| ********************************************************************************/ | ||
|
|
||
| #include "score/mw/launch_manager/process_group_manager/details/component.hpp" | ||
|
|
||
| namespace score::mw::lifecycle::internal | ||
| { | ||
|
|
||
| Component::Component( | ||
| const IStartAction& start_action, | ||
| const IStopAction& stop_action, | ||
| const IForceStopAction& force_stop_action, | ||
| const cpp::span<std::reference_wrapper<const IReadyCondition>> ready_conditions, | ||
| IdentifierHash identifier) | ||
| : start_action_(start_action), | ||
| stop_action_(stop_action), | ||
| force_stop_action_(force_stop_action), | ||
| ready_conditions_(ready_conditions), | ||
| identifier_(identifier), | ||
| state_(TerminatedState{}) | ||
| { | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::activate(cpp::stop_token stop_token) | ||
| { | ||
| return std::visit( | ||
| [&](auto state) { | ||
| return state.activate(*this, stop_token); | ||
| }, | ||
| state_); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::TerminatedState::activate(Component& component, cpp::stop_token stop_token) | ||
| { | ||
| const Result<Handle> start_result = component.start_action_.start(stop_token); | ||
| if (!start_result.has_value()) | ||
| { | ||
| return cpp::make_unexpected(ComponentError::kErrorBeforeReady); | ||
| } | ||
| const Handle handle = start_result.value(); | ||
|
|
||
| component.state_ = StartingState{handle}; | ||
|
|
||
| for (const IReadyCondition& ready_condition : component.ready_conditions_) | ||
| { | ||
| if (!ready_condition.wait(stop_token, handle).has_value()) | ||
| { | ||
| return cpp::make_unexpected(ComponentError::kErrorBeforeReady); | ||
| } | ||
| } | ||
|
|
||
| component.state_ = ReadyState{handle}; | ||
|
|
||
| return RequestState::kSuccess; | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::StartingState::activate( | ||
| [[maybe_unused]] Component& component, | ||
| [[maybe_unused]] cpp::stop_token stop_token) | ||
| { | ||
| SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("Cannot activate component in StartingState"); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::ReadyState::activate( | ||
| [[maybe_unused]] Component& component, | ||
| [[maybe_unused]] cpp::stop_token stop_token) | ||
| { | ||
| SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("Cannot activate component in ReadyState"); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::TerminatingState::activate( | ||
| [[maybe_unused]] Component& component, | ||
| [[maybe_unused]] cpp::stop_token stop_token) | ||
| { | ||
| SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("Cannot activate component in TerminatingState"); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::FaultState::activate( | ||
| [[maybe_unused]] Component& component, | ||
| [[maybe_unused]] cpp::stop_token stop_token) | ||
| { | ||
| SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("Cannot activate component in FaultState"); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::deactivate(cpp::stop_token stop_token) | ||
| { | ||
| return std::visit( | ||
| [&](auto state) { | ||
| return state.deactivate(*this, stop_token); | ||
| }, | ||
| state_); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::TerminatedState::deactivate( | ||
| [[maybe_unused]] Component& component, | ||
| [[maybe_unused]] cpp::stop_token stop_token) | ||
| { | ||
| SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("Cannot deactivate component in TerminatedState"); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::StartingState::deactivate(Component& component, cpp::stop_token stop_token) | ||
| { | ||
| if (!component.stop_action_.stop(stop_token, handle_).has_value()) | ||
| { | ||
| return cpp::make_unexpected(ComponentError::kErrorAfterReady); | ||
| } | ||
|
|
||
| component.state_ = TerminatingState{handle_}; | ||
| return RequestState::kWaiting; | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::ReadyState::deactivate(Component& component, cpp::stop_token stop_token) | ||
| { | ||
| if (!component.stop_action_.stop(stop_token, handle_).has_value()) | ||
| { | ||
| return cpp::make_unexpected(ComponentError::kErrorAfterReady); | ||
| } | ||
|
|
||
| component.state_ = TerminatingState{handle_}; | ||
| return RequestState::kWaiting; | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::TerminatingState::deactivate( | ||
| [[maybe_unused]] Component& component, | ||
| [[maybe_unused]] cpp::stop_token stop_token) | ||
| { | ||
| SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("Cannot deactivate component in TerminatingState"); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::FaultState::deactivate( | ||
| [[maybe_unused]] Component& component, | ||
| [[maybe_unused]] cpp::stop_token stop_token) | ||
| { | ||
| SCORE_LANGUAGE_FUTURECPP_UNREACHABLE_MESSAGE("Cannot deactivate component in FaultState"); | ||
| } | ||
|
|
||
| IComponent::RequestResult Component::tryHandleTermination(int32_t status) | ||
| { | ||
| if (status == 0) | ||
| { | ||
| state_ = TerminatedState{}; | ||
| } | ||
| else | ||
| { | ||
| state_ = FaultState{}; | ||
| } | ||
|
|
||
| return RequestState::kSuccess; | ||
| } | ||
|
|
||
| IdentifierHash Component::getIdentifier() const | ||
| { | ||
| return identifier_; | ||
| } | ||
|
|
||
| bool Component::active() const | ||
| { | ||
| return std::holds_alternative<ReadyState>(state_); | ||
| } | ||
|
|
||
| } // namespace score::mw::lifecycle::internal | ||
134 changes: 134 additions & 0 deletions
134
score/launch_manager/src/daemon/src/process_group_manager/details/component.hpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| /******************************************************************************** | ||
| * Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| * | ||
| * See the NOTICE file(s) distributed with this work for additional | ||
| * information regarding copyright ownership. | ||
| * | ||
| * This program and the accompanying materials are made available under the | ||
| * terms of the Apache License Version 2.0 which is available at | ||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| ********************************************************************************/ | ||
|
|
||
| #ifndef SCORE_LCM_COMPONENT_HPP_INCLUDED | ||
| #define SCORE_LCM_COMPONENT_HPP_INCLUDED | ||
|
|
||
| #include "score/mw/launch_manager/process_group_manager/details/force_stop_action/iforce_stop_action.hpp" | ||
| #include "score/mw/launch_manager/process_group_manager/details/icomponent.hpp" | ||
| #include "score/mw/launch_manager/process_group_manager/details/ready_condition/iready_condition.hpp" | ||
| #include "score/mw/launch_manager/process_group_manager/details/start_action/istart_action.hpp" | ||
| #include "score/mw/launch_manager/process_group_manager/details/stop_action/istop_action.hpp" | ||
| #include <score/span.hpp> | ||
| #include <functional> | ||
| #include <vector> | ||
|
|
||
| namespace score::mw::lifecycle::internal | ||
| { | ||
|
|
||
| /// @brief Manages and tracks the state of a resource. | ||
| class Component final : public IComponent | ||
| { | ||
| public: | ||
| /// @brief Creates a new component from the given actions. | ||
| /// @param start_action How to start the resource. | ||
| /// @param stop_action How to gracefully stop the resource. | ||
| /// @param force_stop_action How to forcefully stop the resource. | ||
| /// @param ready_conditions How to decide when the resource has finished its startup. | ||
| /// @param identifier Name of the component. | ||
| Component( | ||
| const IStartAction& start_action, | ||
| const IStopAction& stop_action, | ||
| const IForceStopAction& force_stop_action, | ||
| cpp::span<std::reference_wrapper<const IReadyCondition>> ready_conditions = | ||
| cpp::span<std::reference_wrapper<const IReadyCondition>>{}, | ||
| IdentifierHash identifier = IdentifierHash{}); | ||
|
|
||
| /// @brief Start the resource and set the component to active. | ||
| /// @param stop_token Token which can be used to interrupt the activation. | ||
| /// @return Whether the component activation was successful, is waiting for another | ||
| /// thread, or an error was encountered. | ||
| RequestResult activate(cpp::stop_token stop_token) override; | ||
|
|
||
| /// @brief Stop the resource and set the component to inactive. | ||
| /// @param stop_token Token which can be used to interrupt the deactivation. | ||
| /// @return Whether the component deactivation was successful, is waiting for another | ||
| /// thread, or an error was encountered. | ||
| RequestResult deactivate(cpp::stop_token stop_token) override; | ||
|
|
||
| /// @brief Notify the component that a POSIX process has terminated. | ||
| /// @param status Exit code of the process. | ||
| /// @return Whether the component activation was successful, is waiting for another | ||
| /// thread, or an error was encountered. | ||
| RequestResult tryHandleTermination(int32_t status) override; | ||
|
|
||
| /// @brief Return the name of the component. | ||
| /// @return The name of the component. | ||
| [[nodiscard]] IdentifierHash getIdentifier() const override; | ||
|
|
||
| /// @brief Return whether the component is active. | ||
| /// @return Whether the component is active. | ||
| [[nodiscard]] bool active() const override; | ||
|
|
||
| private: | ||
| /// @brief How to start the resource. | ||
| const IStartAction& start_action_; | ||
|
|
||
| /// @brief How to gracefully stop the resource. | ||
| const IStopAction& stop_action_; | ||
|
|
||
| /// @brief How to forcefully stop the resource. | ||
| const IForceStopAction& force_stop_action_; | ||
|
|
||
| /// @brief How to decide when the resource has finished its startup. | ||
| const cpp::span<std::reference_wrapper<const IReadyCondition>> ready_conditions_; | ||
|
|
||
| /// @brief Name of the component. | ||
| const IdentifierHash identifier_; | ||
|
|
||
| class TerminatedState final | ||
| { | ||
| public: | ||
| RequestResult activate(Component& component, cpp::stop_token stop_token); | ||
| RequestResult deactivate(Component& component, cpp::stop_token stop_token); | ||
| }; | ||
|
|
||
| class StartingState final | ||
| { | ||
| public: | ||
| Handle handle_; | ||
| RequestResult activate(Component& component, cpp::stop_token stop_token); | ||
| RequestResult deactivate(Component& component, cpp::stop_token stop_token); | ||
| }; | ||
|
|
||
| class ReadyState final | ||
| { | ||
| public: | ||
| Handle handle_; | ||
| RequestResult activate(Component& component, cpp::stop_token stop_token); | ||
| RequestResult deactivate(Component& component, cpp::stop_token stop_token); | ||
| }; | ||
|
|
||
| class TerminatingState final | ||
| { | ||
| public: | ||
| Handle handle_; | ||
| RequestResult activate(Component& component, cpp::stop_token stop_token); | ||
| RequestResult deactivate(Component& component, cpp::stop_token stop_token); | ||
| }; | ||
|
|
||
| class FaultState final | ||
| { | ||
| public: | ||
| Handle handle_; | ||
| RequestResult activate(Component& component, cpp::stop_token stop_token); | ||
| RequestResult deactivate(Component& component, cpp::stop_token stop_token); | ||
| }; | ||
|
|
||
| /// @brief The current state of the component. | ||
| std::variant<TerminatedState, StartingState, ReadyState, TerminatingState, FaultState> state_; | ||
| }; | ||
|
|
||
| } // namespace score::mw::lifecycle::internal | ||
|
|
||
| #endif // SCORE_LCM_COMPONENT_HPP_INCLUDED |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll need to decide how the supervision is handled.
I think a natural point would be to start supervision here after all ready conditions are fulfilled.
Currently, this will always translate to start supervision when kRunning reported.
Though for this we also need the timestamp from the kRunning report, as the supervision has to be started exactly at this timestamp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be possible to have
IpcCommsSyncstore the timestamp (as it should happen only once per instance). That is already stored insideProcessHandle, so it would be accessible to the supervision.