From 6850a6f47a31ebece6f1100c4fd0a3004eade58b Mon Sep 17 00:00:00 2001 From: Paul Quiring Date: Mon, 14 Sep 2026 14:22:56 +0200 Subject: [PATCH] Use score::cpp::jthread where applicable --- .../src/control_client/src/details/BUILD | 1 + .../src/details/control_client_impl.cpp | 18 +++++----- .../src/details/control_client_impl.hpp | 18 +++++----- .../src/process_group_manager/details/BUILD | 2 +- .../details/os_handler.cpp | 6 ++-- .../details/os_handler.hpp | 34 +++++++++---------- .../lifecycle_client/src/lifecyclemanager.h | 3 ++ 7 files changed, 44 insertions(+), 38 deletions(-) diff --git a/score/launch_manager/src/control_client/src/details/BUILD b/score/launch_manager/src/control_client/src/details/BUILD index 9f1fdf825c..0a4ec860be 100644 --- a/score/launch_manager/src/control_client/src/details/BUILD +++ b/score/launch_manager/src/control_client/src/details/BUILD @@ -31,5 +31,6 @@ cc_library( "//score/launch_manager/src/daemon/src/control:control_client_channel", "//score/launch_manager/src/daemon/src/osal:semaphore", "@score_baselibs//score/concurrency/future", + "@score_baselibs//score/language/futurecpp", ], ) diff --git a/score/launch_manager/src/control_client/src/details/control_client_impl.cpp b/score/launch_manager/src/control_client/src/details/control_client_impl.cpp index 6de12ca1aa..22604b297a 100644 --- a/score/launch_manager/src/control_client/src/details/control_client_impl.cpp +++ b/score/launch_manager/src/control_client/src/details/control_client_impl.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "score/concurrency/future/interruptible_future.h" #include "score/concurrency/future/interruptible_promise.h" @@ -64,8 +65,7 @@ ControlClientImpl::ControlClientImpl( : undefined_state_callback_{undefinedStateCallback}, control_client_requests_{}, ipc_request_semaphore_{}, - ipc_response_thread_(nullptr), - ipc_response_thread_running_{true}, + ipc_response_thread_{}, ipc_channel_{nullptr} { @@ -108,24 +108,26 @@ ControlClientImpl::ControlClientImpl( SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE( score::mw::lifecycle::internal::osal::OsalReturnType::kSuccess == init_result, "ControlClient semaphore initialization failed"); - ipc_response_thread_ = std::make_unique(&ControlClientImpl::run, this); + ipc_response_thread_ = score::cpp::jthread([this](score::cpp::stop_token stop_token) { + run(std::move(stop_token)); + }); } ControlClientImpl::~ControlClientImpl() noexcept { std::unique_lock lock(instance_creation_mutex_); instance_created_ = false; - ipc_response_thread_running_ = false; - if (ipc_response_thread_->joinable()) + score::cpp::ignore = ipc_response_thread_.request_stop(); + if (ipc_response_thread_.joinable()) { - ipc_response_thread_->join(); + ipc_response_thread_.join(); } static_cast(ipc_request_semaphore_.deinit()); } -void ControlClientImpl::run() +void ControlClientImpl::run(score::cpp::stop_token stop_token) { // creating a instance called msg for ControlClientMessage that will handle all the communication between LCM and // ControlClientImpl @@ -198,7 +200,7 @@ void ControlClientImpl::run() // in that case, we just return from the function if (nullptr != ipc_channel_) { - while (ipc_response_thread_running_) + while (!stop_token.stop_requested()) { if (ipc_channel_->getResponse(msg)) { diff --git a/score/launch_manager/src/control_client/src/details/control_client_impl.hpp b/score/launch_manager/src/control_client/src/details/control_client_impl.hpp index d8e21fffd8..56ef396885 100644 --- a/score/launch_manager/src/control_client/src/details/control_client_impl.hpp +++ b/score/launch_manager/src/control_client/src/details/control_client_impl.hpp @@ -18,6 +18,9 @@ #include #include +#include +#include + #include "score/mw/launch_manager/common/constants.hpp" #include "score/mw/launch_manager/common/identifier_hash.hpp" #include "score/mw/launch_manager/control/control_client_channel.hpp" @@ -187,19 +190,14 @@ class ControlClientImpl final /// Asynchronous nature of ControlClient API means responses to ControlClient requests, will arrive at /// a random point in future. For this reason a background thread is needed to monitor response_ link, /// this way we can deliver answers when they arrive from LCM. - std::unique_ptr ipc_response_thread_; - - /// @brief Synchronization variable used to manage lifetime of ipc_response_thread_ - /// As long as ipc_response_thread_running_ is set to true, - /// the ipc_response_thread_ should stay alive and perform its job. - /// When ipc_response_thread_running_ is set to false, - /// the ipc_response_thread_ should finish its execution and exit ASAP. - std::atomic_bool ipc_response_thread_running_; + /// Default-constructed (not joinable) until the constructor has finished validating the IPC channel, then + /// started via move-assignment. Requesting stop and joining on destruction is handled automatically. + score::cpp::jthread ipc_response_thread_; /// @brief Entry point for ipc_response_thread_ /// This code will run in background and perform the work that is needed. - /// Exit from this function depends on ipc_response_thread_running_ variable. - void run(); + /// Exit from this function depends on stop being requested on the given stop_token. + void run(score::cpp::stop_token stop_token); /// @brief Handle to the real IPC communication channel with LCM /// This handle is used to perform low level communication with LCM. diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD b/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD index c04f9072a6..a8b5f3e4e3 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/BUILD @@ -303,8 +303,8 @@ cc_library( ":safe_process_map", "//score/launch_manager/src/daemon/src/common:log", "//score/launch_manager/src/daemon/src/process_group_manager:iprocess", + "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/os:sys_wait", - "@score_baselibs//score/os/utils:thread", ], ) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.cpp index 8aace47e6f..be9f11d05f 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.cpp @@ -13,12 +13,14 @@ #include "score/mw/launch_manager/process_group_manager/details/os_handler.hpp" +#include + namespace score::mw::lifecycle::internal { -void OsHandler::run(void) +void OsHandler::run(score::cpp::stop_token stop_token) { - while (is_running_) + while (!stop_token.stop_requested()) { int32_t wait_status = 0; auto result = sys_wait_.wait(&wait_status); diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.hpp b/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.hpp index be9c1aae5a..ddcfd38ac6 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.hpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/os_handler.hpp @@ -15,11 +15,12 @@ #define OS_HANDLER_HPP_INCLUDED #include -#include #include "score/mw/launch_manager/process_group_manager/details/safe_process_map.hpp" #include "score/os/sys_wait.h" -#include "score/os/utils/thread.h" + +#include +#include namespace score::mw::lifecycle::internal { @@ -46,16 +47,12 @@ class OsHandler final OsHandler(SafeProcessMap& map, score::os::SysWait& sys_wait = score::os::SysWait::instance()) : safe_process_map_(map), sys_wait_(sys_wait) { - score::os::set_thread_name(os_handler_, "os_handler"); } - /// @brief Stops and and destroy the execution of the OsHandler's thread by setting the is_running_ flag to false, - /// allowing the thread to exit its main loop and then joining the thread to ensure proper termination. - ~OsHandler() - { - is_running_ = false; - os_handler_.join(); - } + /// @brief Stops and destroys the execution of the OsHandler's thread by requesting a stop, allowing the thread to + /// exit its main loop, and then joining the thread to ensure proper termination. + /// This happens automatically as part of score::cpp::jthread's destructor. + ~OsHandler() = default; // Rule of five /// @brief No copy constructor needed. @@ -75,20 +72,23 @@ class OsHandler final /// This method continuously checks for terminated processes using the OSAL waitForProcessTermination method /// If a terminated process is found, it locates the corresponding ProcessInfoNode by calling the findTerminated /// method of SafeProcessMap, and then notifies the ProcessInfoNode by calling its terminated method. If no - /// processes are terminating, it sleeps for a short duration to prevent CPU hogging. - void run(); + /// processes are terminating, it sleeps for a short duration to prevent CPU hogging. Exits once a stop is + /// requested on the given stop_token. + void run(score::cpp::stop_token stop_token); /// @brief A reference to a SafeProcessMap that stores the mapping of processes to be managed. SafeProcessMap& safe_process_map_; - /// @brief Indicates whether the os handler's thread is currently running. - std::atomic_bool is_running_{true}; - /// @brief Interface to wait for child process termination. score::os::SysWait& sys_wait_; - /// @brief Thread object to manage execution of the run method. - std::thread os_handler_{&score::mw::lifecycle::internal::OsHandler::run, this}; + /// @brief Thread object to manage execution of the run method. Automatically requests a stop and joins on + /// destruction. + score::cpp::jthread os_handler_{ + score::cpp::jthread::name_hint{"os_handler"}, + [this](score::cpp::stop_token stop_token) { + run(std::move(stop_token)); + }}; }; } // namespace score::mw::lifecycle::internal diff --git a/score/launch_manager/src/lifecycle_client/src/lifecyclemanager.h b/score/launch_manager/src/lifecycle_client/src/lifecyclemanager.h index e7e9c72af0..d5961063f9 100644 --- a/score/launch_manager/src/lifecycle_client/src/lifecyclemanager.h +++ b/score/launch_manager/src/lifecycle_client/src/lifecyclemanager.h @@ -58,6 +58,9 @@ class LifeCycleManager /** * \brief The thread dedicated to signal handling. + * + * \note std::thread, not score::cpp::jthread used: this thread just blocks in sigwait() (see handle_signal()), + * it never polls a stop_token. */ std::thread m_signal_handler_thread; /* NOLINT(score-banned-type) using std::thread by desing */