Compare commits

...

11 Commits

Author SHA1 Message Date
Alejandro Hernandez Cordero
5beec9e32b 29.6.1 2025-06-23 16:00:13 +02:00
Alejandro Hernandez Cordero
6ee3a55fc3 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-06-23 16:00:09 +02:00
Adam Aposhian
1e95407bdf set thread names by node in component container isolated (#2871)
Signed-off-by: Adam Aposhian <adam.aposhian@fireflyautomatix.com>
2025-06-18 22:57:00 +02:00
keeponoiro
db8d917a12 Replace std::default_random_engine with std::mt19937 (rolling) (#2843)
Signed-off-by: keeponoiro <keeeeeeep@gmail.com>
2025-05-29 15:29:57 -07:00
Michael Orlov
8d44b95d8b Fix for memory leaks in rclcpp::SerializedMessage (#2861)
Signed-off-by: Michael Orlov <morlovmr@gmail.com>
Signed-off-by: Michael Orlov <michael.orlov@apex.ai>
Co-authored-by: kylemarcey <marcey.kyle@gmail.com>
2025-05-29 10:49:17 +02:00
Alejandro Hernández Cordero
df3a303a17 Removed warning test_qos (#2859)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-26 22:05:08 +02:00
Alejandro Hernández Cordero
373a63c5e6 Added missing chrono includes (#2854)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-23 00:22:27 +02:00
Alejandro Hernández Cordero
6c478834fb get_all_data_impl() does not handle null pointers properly, causing segmentation fault (#2840)
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>

* Update rclcpp/include/rclcpp/experimental/buffers/ring_buffer_implementation.hpp

Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

* make linters happy

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>

---------

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
2025-05-17 15:49:25 +02:00
Alejandro Hernández Cordero
73e9bfb62b QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (#2841)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-16 18:56:22 +02:00
Tomoya Fujita
1aaade8976 remove get_notify_guard_condition from NodeBaseInterface. (#2839)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-05-14 09:37:58 -07:00
Alejandro Hernández Cordero
88d8a9e75a Removed deprecated StaticSingleThreadedExecutor (#2835)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-12 10:04:32 +02:00
41 changed files with 125 additions and 660 deletions

View File

@@ -2,6 +2,23 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.1 (2025-06-23)
-------------------
* Fix for memory leaks in rclcpp::SerializedMessage (`#2861 <https://github.com/ros2/rclcpp/issues/2861>`_)
* Removed warning test_qos (`#2859 <https://github.com/ros2/rclcpp/issues/2859>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault (`#2840 <https://github.com/ros2/rclcpp/issues/2840>`_)
* QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (`#2841 <https://github.com/ros2/rclcpp/issues/2841>`_)
* remove get_notify_guard_condition from NodeBaseInterface. (`#2839 <https://github.com/ros2/rclcpp/issues/2839>`_)
* Removed deprecated StaticSingleThreadedExecutor (`#2835 <https://github.com/ros2/rclcpp/issues/2835>`_)
* Removed deprecated rcpputils Path (`#2834 <https://github.com/ros2/rclcpp/issues/2834>`_)
* Add range constraints for applicable array parameters (`#2828 <https://github.com/ros2/rclcpp/issues/2828>`_)
* Update RingBufferImplementation to clear internal data. (`#2837 <https://github.com/ros2/rclcpp/issues/2837>`_)
* Removed deprecated cancel_sleep_or_wait (`#2836 <https://github.com/ros2/rclcpp/issues/2836>`_)
* Add missing 's' to 'NodeParametersInterface' in doc/comment (`#2831 <https://github.com/ros2/rclcpp/issues/2831>`_)
* subordinate node consistent behavior and update docstring. (`#2822 <https://github.com/ros2/rclcpp/issues/2822>`_)
* Contributors: Alejandro Hernández Cordero, Alex Youngs, Christophe Bedard, Michael Carlstrom, Michael Orlov, Tomoya Fujita
29.6.0 (2025-04-25)
-------------------
* throws std::invalid_argument if ParameterEvent is NULL. (`#2814 <https://github.com/ros2/rclcpp/issues/2814>`_)

View File

@@ -70,7 +70,6 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/executors/executor_notify_waitable.cpp
src/rclcpp/executors/multi_threaded_executor.cpp
src/rclcpp/executors/single_threaded_executor.cpp
src/rclcpp/executors/static_single_threaded_executor.cpp
src/rclcpp/expand_topic_or_service_name.cpp
src/rclcpp/experimental/executors/events_executor/events_executor.cpp
src/rclcpp/experimental/timers_manager.cpp

View File

@@ -20,7 +20,6 @@
#include "rclcpp/executors/multi_threaded_executor.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/utilities.hpp"

View File

@@ -1,145 +0,0 @@
// Copyright 2019 Nobleo Technology
//
// Licensed 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 RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#define RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#include <atomic>
#include <chrono>
#include <memory>
#include "rclcpp/executor.hpp"
#include "rclcpp/executors/executor_entities_collection.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
namespace rclcpp
{
namespace executors
{
/// Static executor implementation
/**
* This executor is a static version of the original single threaded executor.
* It contains some performance optimization to avoid unnecessary reconstructions of
* the executable list for every iteration.
* All nodes, callbackgroups, timers, subscriptions etc. are created before
* spin() is called, and modified only when an entity is added/removed to/from a node.
* This executor is deprecated because these performance improvements have now been
* applied to all other executors.
* This executor is also considered unstable due to known bugs.
* See the unit-tests that are only applied to `StandardExecutors` for information
* on the known limitations.
*
* To run this executor instead of SingleThreadedExecutor replace:
* rclcpp::executors::SingleThreadedExecutor exec;
* by
* rclcpp::executors::StaticSingleThreadedExecutor exec;
* in your source code and spin node(s) in the following way:
* exec.add_node(node);
* exec.spin();
* exec.remove_node(node);
*/
class [[deprecated("Use rclcpp::executors::SingleThreadedExecutor")]] StaticSingleThreadedExecutor
: public rclcpp::Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(StaticSingleThreadedExecutor)
/// Default constructor. See the default constructor for Executor.
RCLCPP_PUBLIC
explicit StaticSingleThreadedExecutor(
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
/// Default destructor.
RCLCPP_PUBLIC
virtual ~StaticSingleThreadedExecutor();
/// Static executor implementation of spin.
/**
* This function will block until work comes in, execute it, and keep blocking.
* It will only be interrupted by a CTRL-C (managed by the global signal handler).
* \throws std::runtime_error when spin() called while already spinning
*/
RCLCPP_PUBLIC
void
spin() override;
/// Static executor implementation of spin some
/**
* This non-blocking function will execute entities that
* were ready when this API was called, until timeout or no
* more work available. Entities that got ready while
* executing work, won't be taken into account here.
*
* Example:
* while(condition) {
* spin_some();
* sleep(); // User should have some sync work or
* // sleep to avoid a 100% CPU usage
* }
*/
RCLCPP_PUBLIC
void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) override;
/// Static executor implementation of spin all
/**
* This non-blocking function will execute entities until timeout (must be >= 0)
* or no more work available.
* If timeout is `0`, potentially it blocks forever until no more work is available.
* If new entities get ready while executing work available, they will be executed
* as long as the timeout hasn't expired.
*
* Example:
* while(condition) {
* spin_all();
* sleep(); // User should have some sync work or
* // sleep to avoid a 100% CPU usage
* }
*/
RCLCPP_PUBLIC
void
spin_all(std::chrono::nanoseconds max_duration) override;
protected:
/**
* @brief Executes ready executables from wait set.
* @param collection entities to evaluate for ready executables.
* @param wait_result result to check for ready executables.
* @param spin_once if true executes only the first ready executable.
* @return true if any executable was ready.
*/
bool
execute_ready_executables(
const rclcpp::executors::ExecutorEntitiesCollection & collection,
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
bool spin_once);
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
void
spin_once_impl(std::chrono::nanoseconds timeout) override;
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
collect_and_wait(std::chrono::nanoseconds timeout);
private:
RCLCPP_DISABLE_COPY(StaticSingleThreadedExecutor)
};
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_

View File

@@ -265,9 +265,13 @@ private:
std::vector<BufferT> result_vtr;
result_vtr.reserve(size_);
for (size_t id = 0; id < size_; ++id) {
result_vtr.emplace_back(
new typename is_std_unique_ptr<T>::Ptr_type(
*(ring_buffer_[(read_index_ + id) % capacity_])));
const auto & elem(ring_buffer_[(read_index_ + id) % capacity_]);
if (elem != nullptr) {
result_vtr.emplace_back(new typename is_std_unique_ptr<T>::Ptr_type(
*elem));
} else {
result_vtr.emplace_back(nullptr);
}
}
return result_vtr;
}

View File

@@ -121,11 +121,6 @@ public:
std::atomic_bool &
get_associated_with_executor_atomic() override;
[[deprecated("Use get_shared_notify_guard_condition or trigger_notify_guard_condition instead")]]
RCLCPP_PUBLIC
rclcpp::GuardCondition &
get_notify_guard_condition() override;
RCLCPP_PUBLIC
rclcpp::GuardCondition::SharedPtr
get_shared_notify_guard_condition() override;

View File

@@ -144,17 +144,6 @@ public:
std::atomic_bool &
get_associated_with_executor_atomic() = 0;
/// Return a guard condition that should be notified when the internal node state changes.
/**
* For example, this should be notified when a publisher is added or removed.
*
* \return the GuardCondition if it is valid, else throw runtime error
*/
RCLCPP_PUBLIC
virtual
rclcpp::GuardCondition &
get_notify_guard_condition() = 0;
/// Return a guard condition that should be notified when the internal node state changes.
/**
* For example, this should be notified when a publisher is added or removed.

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>29.6.0</version>
<version>29.6.1</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -1,223 +0,0 @@
// Copyright 2019 Nobleo Technology
//
// Licensed 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 "rclcpp/executors/executor_entities_collection.hpp"
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/any_executable.hpp"
using rclcpp::executors::StaticSingleThreadedExecutor;
StaticSingleThreadedExecutor::StaticSingleThreadedExecutor(const rclcpp::ExecutorOptions & options)
: rclcpp::Executor(options)
{
}
StaticSingleThreadedExecutor::~StaticSingleThreadedExecutor() {}
void
StaticSingleThreadedExecutor::spin()
{
if (spinning.exchange(true)) {
throw std::runtime_error("spin() called while already spinning");
}
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
// This is essentially the contents of the rclcpp::Executor::wait_for_work method,
// except we need to keep the wait result to reproduce the StaticSingleThreadedExecutor
// behavior.
while (rclcpp::ok(this->context_) && spinning.load()) {
this->spin_once_impl(std::chrono::nanoseconds(-1));
}
}
void
StaticSingleThreadedExecutor::spin_some(std::chrono::nanoseconds max_duration)
{
// In this context a 0 input max_duration means no duration limit
if (std::chrono::nanoseconds(0) == max_duration) {
max_duration = std::chrono::nanoseconds::max();
}
return this->spin_some_impl(max_duration, false);
}
void
StaticSingleThreadedExecutor::spin_all(std::chrono::nanoseconds max_duration)
{
if (max_duration < std::chrono::nanoseconds(0)) {
throw std::invalid_argument("max_duration must be greater than or equal to 0");
}
return this->spin_some_impl(max_duration, true);
}
void
StaticSingleThreadedExecutor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
{
auto start = std::chrono::steady_clock::now();
auto max_duration_not_elapsed = [max_duration, start]() {
const auto spin_forever = std::chrono::nanoseconds(0) == max_duration;
const auto cur_duration = std::chrono::steady_clock::now() - start;
return spin_forever || (cur_duration < max_duration);
};
if (spinning.exchange(true)) {
throw std::runtime_error("spin_some() called while already spinning");
}
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false););
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
// Get executables that are ready now
std::lock_guard<std::mutex> guard(mutex_);
auto wait_result = this->collect_and_wait(std::chrono::nanoseconds(0));
if (wait_result.has_value()) {
// Execute ready executables
bool work_available = this->execute_ready_executables(
current_collection_,
wait_result.value(),
false);
if (!work_available || !exhaustive) {
break;
}
}
}
}
void
StaticSingleThreadedExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
{
if (rclcpp::ok(context_) && spinning.load()) {
std::lock_guard<std::mutex> guard(mutex_);
auto wait_result = this->collect_and_wait(timeout);
if (wait_result.has_value()) {
this->execute_ready_executables(current_collection_, wait_result.value(), true);
}
}
}
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
StaticSingleThreadedExecutor::collect_and_wait(std::chrono::nanoseconds timeout)
{
// we need to make sure that callback groups don't get out of scope
// during the wait. As in jazzy, they are not covered by the DynamicStorage,
// we explicitly hold them here as a bugfix
std::vector<rclcpp::CallbackGroup::SharedPtr> cbgs;
if (this->entities_need_rebuild_.exchange(false) || current_collection_.empty()) {
this->collect_entities();
}
auto callback_groups = this->collector_.get_all_callback_groups();
cbgs.resize(callback_groups.size());
for(const auto & w_ptr : callback_groups) {
auto shr_ptr = w_ptr.lock();
if(shr_ptr) {
cbgs.push_back(std::move(shr_ptr));
}
}
auto wait_result = wait_set_.wait(std::chrono::nanoseconds(timeout));
// drop references to the callback groups, before trying to execute anything
cbgs.clear();
if (wait_result.kind() == WaitResultKind::Empty) {
RCUTILS_LOG_WARN_NAMED(
"rclcpp",
"empty wait set received in wait(). This should never happen.");
return {};
} else {
if (wait_result.kind() == WaitResultKind::Ready && current_notify_waitable_) {
auto & rcl_wait_set = wait_result.get_wait_set().get_rcl_wait_set();
if (current_notify_waitable_->is_ready(rcl_wait_set)) {
current_notify_waitable_->execute(current_notify_waitable_->take_data());
}
}
}
return wait_result;
}
// This preserves the "scheduling semantics" of the StaticSingleThreadedExecutor
// from the original implementation.
bool StaticSingleThreadedExecutor::execute_ready_executables(
const rclcpp::executors::ExecutorEntitiesCollection & collection,
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
bool spin_once)
{
bool any_ready_executable = false;
if (wait_result.kind() != rclcpp::WaitResultKind::Ready) {
return any_ready_executable;
}
while (auto subscription = wait_result.next_ready_subscription()) {
auto entity_iter = collection.subscriptions.find(subscription->get_subscription_handle().get());
if (entity_iter != collection.subscriptions.end()) {
execute_subscription(subscription);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
size_t current_timer_index = 0;
while (true) {
auto [timer, timer_index] = wait_result.peek_next_ready_timer(current_timer_index);
if (nullptr == timer) {
break;
}
current_timer_index = timer_index;
auto entity_iter = collection.timers.find(timer->get_timer_handle().get());
if (entity_iter != collection.timers.end()) {
wait_result.clear_timer_with_index(current_timer_index);
auto data = timer->call();
if (!data) {
// someone canceled the timer between is_ready and call
continue;
}
execute_timer(std::move(timer), data);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
while (auto client = wait_result.next_ready_client()) {
auto entity_iter = collection.clients.find(client->get_client_handle().get());
if (entity_iter != collection.clients.end()) {
execute_client(client);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
while (auto service = wait_result.next_ready_service()) {
auto entity_iter = collection.services.find(service->get_service_handle().get());
if (entity_iter != collection.services.end()) {
execute_service(service);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
while (auto waitable = wait_result.next_ready_waitable()) {
auto entity_iter = collection.waitables.find(waitable.get());
if (entity_iter != collection.waitables.end()) {
const auto data = waitable->take_data();
waitable->execute(data);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
return any_ready_executable;
}

View File

@@ -275,16 +275,6 @@ NodeBase::get_associated_with_executor_atomic()
return associated_with_executor_;
}
rclcpp::GuardCondition &
NodeBase::get_notify_guard_condition()
{
std::lock_guard<std::recursive_mutex> notify_condition_lock(notify_guard_condition_mutex_);
if (!notify_guard_condition_is_valid_) {
throw std::runtime_error("failed to get notify guard condition because it is invalid");
}
return *notify_guard_condition_;
}
rclcpp::GuardCondition::SharedPtr
NodeBase::get_shared_notify_guard_condition()
{

View File

@@ -69,8 +69,10 @@ QoSInitialization::from_rmw(const rmw_qos_profile_t & rmw_qos)
return KeepLast(rmw_qos.depth, false);
case RMW_QOS_POLICY_HISTORY_KEEP_LAST:
case RMW_QOS_POLICY_HISTORY_UNKNOWN:
default:
return KeepLast(rmw_qos.depth);
default:
throw std::invalid_argument(
"Invalid history policy enum value passed to QoSInitialization::from_rmw");
}
}

View File

@@ -26,8 +26,13 @@ namespace rclcpp
inline void copy_rcl_message(const rcl_serialized_message_t & from, rcl_serialized_message_t & to)
{
const auto ret = rmw_serialized_message_init(
&to, from.buffer_capacity, &from.allocator);
auto ret = RCL_RET_ERROR;
if (nullptr == to.buffer) {
ret = rmw_serialized_message_init(&to, from.buffer_capacity, &from.allocator);
} else {
ret = rmw_serialized_message_resize(&to, from.buffer_capacity);
}
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
@@ -78,7 +83,6 @@ SerializedMessage::SerializedMessage(rcl_serialized_message_t && other)
SerializedMessage & SerializedMessage::operator=(const SerializedMessage & other)
{
if (this != &other) {
serialized_message_ = rmw_get_zero_initialized_serialized_message();
copy_rcl_message(other.serialized_message_, serialized_message_);
}
@@ -88,7 +92,6 @@ SerializedMessage & SerializedMessage::operator=(const SerializedMessage & other
SerializedMessage & SerializedMessage::operator=(const rcl_serialized_message_t & other)
{
if (&serialized_message_ != &other) {
serialized_message_ = rmw_get_zero_initialized_serialized_message();
copy_rcl_message(other, serialized_message_);
}
@@ -98,6 +101,14 @@ SerializedMessage & SerializedMessage::operator=(const rcl_serialized_message_t
SerializedMessage & SerializedMessage::operator=(SerializedMessage && other)
{
if (this != &other) {
if (nullptr != serialized_message_.buffer) {
const auto fini_ret = rmw_serialized_message_fini(&serialized_message_);
if (RCL_RET_OK != fini_ret) {
RCLCPP_ERROR(
get_logger("rclcpp"),
"Failed to destroy serialized message: %s", rcl_get_error_string().str);
}
}
serialized_message_ =
std::exchange(other.serialized_message_, rmw_get_zero_initialized_serialized_message());
}
@@ -108,6 +119,14 @@ SerializedMessage & SerializedMessage::operator=(SerializedMessage && other)
SerializedMessage & SerializedMessage::operator=(rcl_serialized_message_t && other)
{
if (&serialized_message_ != &other) {
if (nullptr != serialized_message_.buffer) {
const auto fini_ret = rmw_serialized_message_fini(&serialized_message_);
if (RCL_RET_OK != fini_ret) {
RCLCPP_ERROR(
get_logger("rclcpp"),
"Failed to destroy serialized message: %s", rcl_get_error_string().str);
}
}
serialized_message_ =
std::exchange(other, rmw_get_zero_initialized_serialized_message());
}

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <chrono>
#include <memory>
#include <string>
#include <utility>

View File

@@ -529,13 +529,6 @@ if(TARGET test_executors_warmup)
target_link_libraries(test_executors_warmup ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_static_single_threaded_executor executors/test_static_single_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
ament_add_test_label(test_static_single_threaded_executor mimick)
if(TARGET test_static_single_threaded_executor)
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_multi_threaded_executor executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)

View File

@@ -22,40 +22,13 @@
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/executors/multi_threaded_executor.hpp"
// suppress deprecated StaticSingleThreadedExecutor warning
// we define an alias that explicitly indicates that this class is deprecated, while avoiding
// polluting a lot of files the gcc pragmas
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
using DeprecatedStaticSingleThreadedExecutor = rclcpp::executors::StaticSingleThreadedExecutor;
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
using ExecutorTypes =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor,
DeprecatedStaticSingleThreadedExecutor,
rclcpp::experimental::executors::EventsExecutor>;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
class ExecutorTypeNames
{
@@ -70,16 +43,6 @@ public:
if (std::is_same<T, rclcpp::executors::MultiThreadedExecutor>()) {
return "MultiThreadedExecutor";
}
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
if (std::is_same<T, DeprecatedStaticSingleThreadedExecutor>()) {
return "StaticSingleThreadedExecutor";
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif
if (std::is_same<T, rclcpp::experimental::executors::EventsExecutor>()) {
return "EventsExecutor";

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include "rclcpp/experimental/executors/events_executor/events_executor_event_types.hpp"

View File

@@ -285,20 +285,11 @@ public:
T executor;
};
#if !defined(_WIN32)
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# endif
#endif
using MainExecutorTypes =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor,
DeprecatedStaticSingleThreadedExecutor>;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::MultiThreadedExecutor>;
// TODO(@fujitatomoya): this test excludes EventExecutor because it does not
// support simulation time used for this test to relax the racy condition.
// See more details for https://github.com/ros2/rclcpp/issues/2457.

View File

@@ -1,192 +0,0 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed 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 <gtest/gtest.h>
#include <chrono>
#include <future>
#include <memory>
#include <stdexcept>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/srv/empty.hpp"
#include "./executor_types.hpp"
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
using namespace std::chrono_literals;
class TestStaticSingleThreadedExecutor : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestStaticSingleThreadedExecutor, add_callback_group_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.add_callback_group(cb_group, node->get_node_base_interface(), true),
std::runtime_error("Failed to handle entities update on callback group add: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, add_node_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.add_node(node),
std::runtime_error("Failed to handle entities update on node add: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_callback_group_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
executor.add_callback_group(cb_group, node->get_node_base_interface(), true);
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.remove_callback_group(cb_group, true),
std::runtime_error(
"Failed to handle entities update on callback group remove: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_node_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.remove_node(node, true),
std::runtime_error("Node '/ns/node' needs to be associated with an executor."));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_node_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
executor.add_node(node);
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.remove_node(node, true),
std::runtime_error("Failed to handle entities update on node remove: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, execute_service) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
executor.add_node(node);
auto service =
node->create_service<test_msgs::srv::Empty>(
"service",
[](
const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {});
auto client = node->create_client<test_msgs::srv::Empty>("service");
std::promise<void> promise;
std::future<void> future = promise.get_future();
EXPECT_EQ(
rclcpp::FutureReturnCode::TIMEOUT,
executor.spin_until_future_complete(future, std::chrono::milliseconds(1)));
executor.remove_node(node);
executor.spin_until_future_complete(future, std::chrono::milliseconds(1));
}

View File

@@ -13,6 +13,7 @@
// limitations under the License.
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <thread>

View File

@@ -15,6 +15,7 @@
#include <gmock/gmock.h>
#include <chrono>
#include <future>
#include <memory>
#include <string>

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include <string>
#include <vector>

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include <string>
#include <utility>

View File

@@ -272,3 +272,15 @@ TEST(TestQoS, qos_check_compatible)
}
}
}
TEST(TestQoS, from_rmw_validity)
{
rmw_qos_profile_t invalid_qos;
memset(&invalid_qos, 0, sizeof(invalid_qos));
unsigned int n = 999;
memcpy(&invalid_qos.history, &n, sizeof(n));
EXPECT_THROW({
rclcpp::QoSInitialization::from_rmw(invalid_qos);
}, std::invalid_argument);
}

View File

@@ -164,3 +164,15 @@ TEST(TestRingBufferImplementation, test_buffer_clear) {
EXPECT_EQ('c', c);
EXPECT_EQ('d', d);
}
TEST(TestRingBufferImplementation, handle_nullptr_deletion) {
rclcpp::experimental::buffers::RingBufferImplementation<std::unique_ptr<int>> rb(3);
rb.enqueue(std::make_unique<int>(42));
rb.enqueue(nullptr); // intentionally enqueuing nullptr
rb.enqueue(std::make_unique<int>(84));
auto all_data = rb.get_all_data();
EXPECT_EQ(3u, all_data.size());
EXPECT_EQ(42, *(all_data[0]));
EXPECT_EQ(nullptr, all_data[1]);
EXPECT_EQ(84, *(all_data[2]));
}

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <string>
#include <memory>
#include <utility>

View File

@@ -15,6 +15,7 @@
#include <rcl/service_introspection.h>
#include <rmw/rmw.h>
#include <chrono>
#include <map>
#include <string>

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include <string>
#include <vector>

View File

@@ -3,6 +3,12 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.1 (2025-06-23)
-------------------
* Replace std::default_random_engine with std::mt19937 (rolling) (`#2843 <https://github.com/ros2/rclcpp/issues/2843>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* Contributors: Alejandro Hernández Cordero, keeponoiro
29.6.0 (2025-04-25)
-------------------

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_action</name>
<version>29.6.0</version>
<version>29.6.1</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -181,7 +181,7 @@ public:
std::recursive_mutex cancel_requests_mutex;
std::independent_bits_engine<
std::default_random_engine, 8, unsigned int> random_bytes_generator;
std::mt19937, 8, unsigned int> random_bytes_generator;
};
ClientBase::ClientBase(

View File

@@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <chrono>
#include <future>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <thread>
#include <chrono>
#include "gtest/gtest.h"

View File

@@ -67,7 +67,7 @@ TEST(TestActionTypes, goal_uuid_to_hashed_uuid_random) {
// Use std::random_device to seed the generator of goal IDs.
std::random_device rd;
std::independent_bits_engine<
std::default_random_engine, 8, decltype(rd())> random_bytes_generator(rd());
std::mt19937, 8, decltype(rd())> random_bytes_generator(rd());
std::vector<size_t> hashed_guuids;
constexpr size_t iterations = 1000;

View File

@@ -2,6 +2,12 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.1 (2025-06-23)
-------------------
* set thread names by node in component container isolated (`#2871 <https://github.com/ros2/rclcpp/issues/2871>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* Contributors: Adam Aposhian, Alejandro Hernández Cordero
29.6.0 (2025-04-25)
-------------------

View File

@@ -22,9 +22,10 @@
#include <utility>
#include <vector>
#include <unordered_map>
#include <system_error>
#include "rclcpp_components/component_manager.hpp"
#include "rcpputils/thread_name.hpp"
namespace rclcpp_components
{
@@ -77,8 +78,16 @@ protected:
DedicatedExecutorWrapper & wrapper = result.first->second;
wrapper.executor = exec;
auto & thread_initialized = wrapper.thread_initialized;
auto name = node_wrappers_[node_id].get_node_base_interface()->get_name();
// Copy name so that it doesn't deallocate before the thread is started
wrapper.thread = std::thread(
[exec, &thread_initialized]() {
[exec, &thread_initialized, name]() {
try {
rcpputils::set_thread_name(name);
} catch (const std::system_error & e) {
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to set thread name: %s (%s)", e.what(),
e.code().message().c_str());
}
thread_initialized = true;
exec->spin();
});

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_components</name>
<version>29.6.0</version>
<version>29.6.1</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include <string>

View File

@@ -3,6 +3,12 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.1 (2025-06-23)
-------------------
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* introduce rcl_lifecycle_get_transition_label_by_id(). (`#2827 <https://github.com/ros2/rclcpp/issues/2827>`_)
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita
29.6.0 (2025-04-25)
-------------------

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_lifecycle</name>
<version>29.6.0</version>
<version>29.6.1</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -14,6 +14,7 @@
#include <benchmark/benchmark.h>
#include <chrono>
#include <memory>
#include <string>
#include <vector>

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <map>
#include <memory>
#include <set>

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <string>
#include <memory>
#include <utility>