Compare commits

..

1 Commits

Author SHA1 Message Date
methylDragon
0dddb16bed Add type_description struct conversion utils
Signed-off-by: methylDragon <methylDragon@gmail.com>
2024-12-31 01:33:51 -08:00
150 changed files with 1291 additions and 5552 deletions

45
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,45 @@
<!--
For general questions, please ask on ROS answers: https://answers.ros.org, make sure to include at least the `ros2` tag and the rosdistro version you are running, e.g. `ardent`.
For general design discussions, please post on discourse: https://discourse.ros.org/c/ng-ros
Not sure if this is the right repository? Open an issue on https://github.com/ros2/ros2/issues
For Bug report or feature requests, please fill out the relevant category below
-->
## Bug report
**Required Info:**
- Operating System:
- <!-- OS and version (e.g. Windows 10, Ubuntu 16.04...) -->
- Installation type:
- <!-- binaries or from source -->
- Version or commit hash:
- <!-- Output of git rev-parse HEAD, release version, or repos file -->
- DDS implementation:
- <!-- rmw_implementation used (e.g. Fast-RTPS, RTI Connext, etc -->
- Client library (if applicable):
- <!-- e.g. rclcpp, rclpy, or N/A -->
#### Steps to reproduce issue
<!-- Detailed instructions on how to reliably reproduce this issue http://sscce.org/
``` code that can be copy-pasted is preferred ``` -->
```
```
#### Expected behavior
#### Actual behavior
#### Additional information
<!-- If you are reporting a bug delete everything below
If you are requesting a feature deleted everything above this line -->
----
## Feature request
#### Feature description
<!-- Description in a few sentences what the feature consists of and what problem it will solve -->
#### Implementation considerations
<!-- Relevant information on how the feature could be implemented and pros and cons of the different solutions -->

View File

@@ -2,74 +2,6 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.5.4 (2025-10-21)
-------------------
29.5.3 (2025-09-11)
-------------------
* Fix: improve exception context for parameter_value_from (`#2917 <https://github.com/ros2/rclcpp/issues/2917>`_) (`#2919 <https://github.com/ros2/rclcpp/issues/2919>`_)
* Allow for implicitly convertable loggers as well (`#2922 <https://github.com/ros2/rclcpp/issues/2922>`_) (`#2936 <https://github.com/ros2/rclcpp/issues/2936>`_)
* Fix `start_type_description_service` param handling (`#2897 <https://github.com/ros2/rclcpp/issues/2897>`_) (`#2908 <https://github.com/ros2/rclcpp/issues/2908>`_)
* Add qos parameter for wait_for_message function (`#2903 <https://github.com/ros2/rclcpp/issues/2903>`_) (`#2905 <https://github.com/ros2/rclcpp/issues/2905>`_)
* Expose `typesupport_helpers` API needed for the Rosbag2 (`#2858 <https://github.com/ros2/rclcpp/issues/2858>`_) (`#2901 <https://github.com/ros2/rclcpp/issues/2901>`_)
* Fujitatomoya/test append parameter override (`#2896 <https://github.com/ros2/rclcpp/issues/2896>`_) (`#2899 <https://github.com/ros2/rclcpp/issues/2899>`_)
* Add overload of `append_parameter_override` (`#2891 <https://github.com/ros2/rclcpp/issues/2891>`_) (`#2894 <https://github.com/ros2/rclcpp/issues/2894>`_)
* Contributors: Tim Clephas, mergify[bot]
29.5.2 (2025-07-07)
-------------------
* Shutdown deadlock fix jazzy (`#2887 <https://github.com/ros2/rclcpp/issues/2887>`_) (`#2888 <https://github.com/ros2/rclcpp/issues/2888>`_)
* Fix test_publisher_with_system_default_qos (`#2881 <https://github.com/ros2/rclcpp/issues/2881>`_) (`#2884 <https://github.com/ros2/rclcpp/issues/2884>`_)
* Contributors: Tomoya Fujita, Janosch Machowinski
29.5.1 (2025-06-23)
-------------------
* Removed warning test_qos (`#2859 <https://github.com/ros2/rclcpp/issues/2859>`_) (`#2873 <https://github.com/ros2/rclcpp/issues/2873>`_)
* Fix for memory leaks in rclcpp::SerializedMessage (`#2861 <https://github.com/ros2/rclcpp/issues/2861>`_) (`#2863 <https://github.com/ros2/rclcpp/issues/2863>`_)
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault (backport `#2840 <https://github.com/ros2/rclcpp/issues/2840>`_) (`#2850 <https://github.com/ros2/rclcpp/issues/2850>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
* QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (`#2841 <https://github.com/ros2/rclcpp/issues/2841>`_) (`#2846 <https://github.com/ros2/rclcpp/issues/2846>`_)
* Add missing 's' to 'NodeParametersInterface' in doc/comment (`#2831 <https://github.com/ros2/rclcpp/issues/2831>`_) (`#2833 <https://github.com/ros2/rclcpp/issues/2833>`_)
* subordinate node consistent behavior and update docstring. (`#2822 <https://github.com/ros2/rclcpp/issues/2822>`_) (`#2830 <https://github.com/ros2/rclcpp/issues/2830>`_)
* throws std::invalid_argument if ParameterEvent is NULL. (`#2814 <https://github.com/ros2/rclcpp/issues/2814>`_)
* Removed clang warnings (`#2823 <https://github.com/ros2/rclcpp/issues/2823>`_)
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita, mergify[bot]
29.5.0 (2025-04-18)
-------------------
* Fix a race condition (`#2819 <https://github.com/ros2/rclcpp/issues/2819>`_)
* Remove redundant typesupport check in serialization module (`#2808 <https://github.com/ros2/rclcpp/issues/2808>`_)
* Remove get_typesupport_handle implementation. (`#2806 <https://github.com/ros2/rclcpp/issues/2806>`_)
* Use NodeParameterInterface instead of /parameter_event to update "use_sim_time" (`#2378 <https://github.com/ros2/rclcpp/issues/2378>`_)
* Remove cancel_clock_executor_promise\_. (`#2797 <https://github.com/ros2/rclcpp/issues/2797>`_)
* Enable parameter update recursively only when QoS override parameters. (`#2742 <https://github.com/ros2/rclcpp/issues/2742>`_)
* Contributors: Pedro de Azeredo, Tanishq Chaudhary, Tomoya Fujita
29.4.0 (2025-04-04)
-------------------
* Removed trailing whitespace from the codebase. (`#2791 <https://github.com/ros2/rclcpp/issues/2791>`_)
* Expanded docstring of `get_rmw_qos_profile()` (`#2787 <https://github.com/ros2/rclcpp/issues/2787>`_)
* Set envars to run tests with rmw_zenoh_cpp with multicast discovery (`#2776 <https://github.com/ros2/rclcpp/issues/2776>`_)
* fix: Compilefix for clang (`#2775 <https://github.com/ros2/rclcpp/issues/2775>`_)
* add exception doc for configure_introspection. (`#2773 <https://github.com/ros2/rclcpp/issues/2773>`_)
* feat: Add ClockWaiter and ClockConditionalVariable (`#2691 <https://github.com/ros2/rclcpp/issues/2691>`_)
* doc: Added warning to not instantiate Clock directly with RCL_ROS_TIME (`#2768 <https://github.com/ros2/rclcpp/issues/2768>`_)
* Use rmw_event_type_is_supported in test_qos_event (`#2761 <https://github.com/ros2/rclcpp/issues/2761>`_)
* Support action typesupport helper (`#2750 <https://github.com/ros2/rclcpp/issues/2750>`_)
* use maybe_unused attribute for the portability. (`#2758 <https://github.com/ros2/rclcpp/issues/2758>`_)
* Executor strong reference fix (`#2745 <https://github.com/ros2/rclcpp/issues/2745>`_)
* Cleanup of https://github.com/ros2/rclcpp/pull/2683 (`#2714 <https://github.com/ros2/rclcpp/issues/2714>`_)
* Fix typo in doc section for get_service_typesupport_handle (`#2751 <https://github.com/ros2/rclcpp/issues/2751>`_)
* Test case and fix for for https://github.com/ros2/rclcpp/issues/2652 (`#2713 <https://github.com/ros2/rclcpp/issues/2713>`_)
* fix(timer): Delete node, after executor thread terminated (`#2737 <https://github.com/ros2/rclcpp/issues/2737>`_)
* update doc section for spin_xxx methods. (`#2730 <https://github.com/ros2/rclcpp/issues/2730>`_)
* fix: Expose timers used by rclcpp::Waitables (`#2699 <https://github.com/ros2/rclcpp/issues/2699>`_)
* use rmw_qos_profile_rosout_default instead of rcl. (`#2663 <https://github.com/ros2/rclcpp/issues/2663>`_)
* fix(Executor): Fixed entities not beeing executed after just beeing added (`#2724 <https://github.com/ros2/rclcpp/issues/2724>`_)
* fix: make the loop condition align with the description (`#2726 <https://github.com/ros2/rclcpp/issues/2726>`_)
* Collect log messages from rcl, and reset. (`#2720 <https://github.com/ros2/rclcpp/issues/2720>`_)
* Contributors: Abhishek Kashyap, Alejandro Hernández Cordero, Barry Xu, Janosch Machowinski, Leander Stephen D'Souza, Tomoya Fujita, Yuyuan Yuan
29.3.0 (2024-12-20)
-------------------
* Fix transient local IPC publish (`#2708 <https://github.com/ros2/rclcpp/issues/2708>`_)

View File

@@ -434,3 +434,4 @@
- (tfoote) There should be no jumps in steady time. If there's a big change in system time, it doesn't necessarily mean that time jumped, just that you might have been sleeping for a long time. Most ntp systems adjust the slew rate these days instead of jumping but still that's an external process and I don't know of any APIs to introspect the state of the clock. I'm not sure that we have a way to detect jumps in time for system or steady time. To that end I think that we should be clear that we only provide callbacks when simulation time starts or stops, or simulation time jumps. We should also strongly recommend that operators not actively adjust their system clocks while running ROS nodes.
- (jacobperron) I agree with Tully, if we don't have a way to detect system time jumps then I think we should just document that this only works with ROS time. In addition to documentation, we could log an info or warning message if the user registers jump callback with steady or system time, but it may be unnecessarily noisy.

View File

@@ -2,15 +2,15 @@
## Introduction:
The original requirement came in **gazebo_ros_pkgs** for setting individual wheel slip parameters based on global wheel slip value [link to original issue](https://github.com/ros-simulation/gazebo_ros_pkgs/pull/1365).
The original requirement came in **gazebo_ros_pkgs** for setting individual wheel slip parameters based on global wheel slip value [link to original issue](https://github.com/ros-simulation/gazebo_ros_pkgs/pull/1365).
The main requirement is to set one or more parameters after another parameter is set successfully.
The main requirement is to set one or more parameters after another parameter is set successfully.
Additionally, it would be nice if users could be notified locally (via a callback) when parameters have been set successfully (i.e. post validation).
Related discussion can be found in [#609](https://github.com/ros2/rclcpp/issues/609) [#1789](https://github.com/ros2/rclcpp/pull/1789)
With the current parameters API, the `add_on_set_parameters_callback` is intended for validation of parameter values before they are set, it should **not** cause any side-effects.
With the current parameters API, the `add_on_set_parameters_callback` is intended for validation of parameter values before they are set, it should **not** cause any side-effects.
There is also the `ParameterEventHandler` that publishes changes to node parameters on `/parameter_events` topic for external nodes to see. Though the node could subscribe to the `/parameter_events` topic to be notified of changes to its own parameters, it is less than ideal since there is a delay caused by waiting for an executor to process the callback.
@@ -19,11 +19,11 @@ We propose adding a `PostSetParametersCallbackHandle` for successful parameter s
The validation callback is often abused to trigger side effects in the code, for instance updating class attributes even before a parameter has been set successfully. Instead of relying on the `/parameter_events` topic to be notified of parameter changes, users can register a callback with a new API, `add_post_set_parameters_callback`.
It is possible to use the proposed `add_post_set_parameters_callback` for setting additional parameters, but this might result in infinite recursion and does not allow those additional parameters to be set atomically with the original parameter(s) changed.
To workaround these issues, we propose adding a "pre set" callback type that can be registered with `add_pre_set_parameters_callback`, which will be triggered before the validation callbacks and can be used to modify the parameter list.
To workaround these issues, we propose adding a "pre set" callback type that can be registered with `add_pre_set_parameters_callback`, which will be triggered before the validation callbacks and can be used to modify the parameter list.
![Desgin API](https://github.com/ros2/rclcpp/blob/deepanshu/local-param-changed-callback-support/rclcpp/doc/param_callback_design.png?raw=true)
## Alternatives
* Users could call `set_parameter` while processing a message from the `/parameter_events` topic, however, there is extra overhead in having to create subscription (as noted earlier).
* Users could call `set_parameter` inside the "on set" parameters callback, however it is not well-defined how side-effects should handle cases where parameter validation fails.
* Users could call `set_parameter` inside the "on set" parameters callback, however it is not well-defined how side-effects should handle cases where parameter validation fails.

View File

@@ -69,17 +69,18 @@ private:
};
template<typename Alloc, typename T, typename D>
void set_allocator_for_deleter([[maybe_unused]] D * deleter, [[maybe_unused]] Alloc * alloc)
void set_allocator_for_deleter(D * deleter, Alloc * alloc)
{
(void) alloc;
(void) deleter;
throw std::runtime_error("Reached unexpected template specialization");
}
template<typename T, typename U>
void set_allocator_for_deleter(
[[maybe_unused]] std::default_delete<T> * deleter,
[[maybe_unused]] std::allocator<U> * alloc)
void set_allocator_for_deleter(std::default_delete<T> * deleter, std::allocator<U> * alloc)
{
// This function is intentionally left empty.
(void) deleter;
(void) alloc;
}
template<typename Alloc, typename T>

View File

@@ -789,9 +789,6 @@ public:
* \param[in] clock clock to use to generate introspection timestamps
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
* \param[in] introspection_state the state to set introspection to
*
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw if
* it failed to configure introspection.
*/
void
configure_introspection(

View File

@@ -60,13 +60,6 @@ public:
/**
* Initializes the clock instance with the given clock_type.
*
* WARNING Don't instantiate a clock using RCL_ROS_TIME directly,
* unless you really know what you are doing. By default no TimeSource
* is attached to a new clock. This will lead to the unexpected behavior,
* that your RCL_ROS_TIME will run always on system time. If you want
* a RCL_ROS_TIME use Node::get_clock(), or make sure to attach a
* TimeSource yourself.
*
* \param clock_type type of the clock.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
@@ -201,16 +194,11 @@ public:
ros_time_is_active();
/**
* Deprecated. This API is broken, as there is no way to get a deep
* copy of a clock. Therefore one can experience spurious wakeups triggered
* by some other instance of a clock.
*
* Cancels an ongoing or future sleep operation of one thread.
*
* This function can be used by one thread, to wakeup another thread that is
* blocked using any of the sleep_ or wait_ methods of this class.
*/
[[deprecated("Use ClockConditionalVariable")]]
RCLCPP_PUBLIC
void
cancel_sleep_or_wait();
@@ -272,117 +260,6 @@ private:
std::shared_ptr<Impl> impl_;
};
/**
* A synchronization primitive, equal to std::conditional_variable,
* that works with the rclcpp::Clock.
*
* For more information on the API see https://en.cppreference.com/w/cpp/thread/condition_variable.
*
* Note, this class does not handle shutdowns, if you want to
* haven them handles as well, use ClockConditionalVariable.
*/
class ClockWaiter
{
private:
class ClockWaiterImpl;
std::unique_ptr<ClockWaiterImpl> impl_;
public:
RCLCPP_SMART_PTR_DEFINITIONS(ClockWaiter)
RCLCPP_PUBLIC
explicit ClockWaiter(const rclcpp::Clock::SharedPtr & clock);
RCLCPP_PUBLIC
~ClockWaiter();
/**
* Calling this function will block the current thread, until abs_time is reached,
* or pred returns true.
* @param lock A locked lock. The lock must be locked at call time, or this method will throw.
* The lock will be atomically released and this thread will blocked.
* @param abs_time The time until which this thread shall be blocked.
* @param pred may be called in cased of spurious wakeups, but must be called every time
* notify_one() was called. During the call to pred, the given lock will be locked.
* This method will return, if pred returns true.
*/
RCLCPP_PUBLIC
bool
wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred);
/**
* Notify the blocked thread, that it should reevaluate the wakeup condition.
* The given pred function in wait_until will be reevaluated and wait_until
* will return if it evaluates to true.
*/
RCLCPP_PUBLIC
void
notify_one();
};
/**
* A synchronization primitive, similar to std::conditional_variable,
* that works with the rclcpp::Clock.
*
* For more information on the API see https://en.cppreference.com/w/cpp/thread/condition_variable.
*
* This primitive will wake up if the context was shut down.
*/
class ClockConditionalVariable
{
class Impl;
std::unique_ptr<Impl> impl_;
public:
RCLCPP_SMART_PTR_DEFINITIONS(ClockConditionalVariable)
RCLCPP_PUBLIC
ClockConditionalVariable(
const rclcpp::Clock::SharedPtr & clock,
rclcpp::Context::SharedPtr context = rclcpp::contexts::get_global_default_context());
RCLCPP_PUBLIC
~ClockConditionalVariable();
/**
* Calling this function will block the current thread, until abs_time is reached,
* or pred returns true.
* @param lock A locked lock. The lock must be locked at call time, or this method will throw.
* The lock will be atomically released and this thread will blocked.
* The given lock must be created using the mutex returned my mutex().
* @param abs_time The time until which this thread shall be blocked.
* @param pred may be called in cased of spurious wakeups, but must be called every time
* notify_one() was called. During the call to pred, the given lock will be locked.
* This method will return, if pred returns true.
*
* @return true if until was reached.
*/
RCLCPP_PUBLIC
bool
wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred);
/**
* Notify the blocked thread, that is should reevaluate the wakeup condition.
* E.g. the given pred function in wait_until shall be reevaluated.
*/
RCLCPP_PUBLIC
void
notify_one();
/**
* Returns the internal mutex. In order to be race free with the context shutdown,
* this mutex must be used for the wait_until call.
*/
RCLCPP_PUBLIC
std::mutex &
mutex();
};
} // namespace rclcpp
#endif // RCLCPP__CLOCK_HPP_

View File

@@ -97,9 +97,6 @@ declare_parameter_or_get(
rcl_interfaces::msg::ParameterDescriptor descriptor)
{
try {
// enable parameter modification to make it possible
// to declare QoS override parameters during parameter callbacks.
parameters_interface.enable_parameter_modification();
return parameters_interface.declare_parameter(
param_name, param_value, descriptor);
} catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) {

View File

@@ -0,0 +1,215 @@
// Copyright 2025 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.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
#include "type_description_interfaces/msg/individual_type_description.hpp"
#include "type_description_interfaces/msg/type_description.hpp"
#include "type_description_interfaces/msg/type_source.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
// IndividualTypeDescription =======================================================================
/// Convert a runtime individual type description struct to its corresponding message.
/**
* This function converts a rosidl_runtime_cpp::type_description::IndividualTypeDescription
* struct to the corresponding type_description_interfaces/msg/IndividualTypeDescription
* msg.
*
* \param[in] runtime_individual_description the runtime struct to convert
* \return the converted individual type description msg
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT>
convert_individual_type_description_runtime_to_msg(
const rosidl_runtime_cpp::type_description::IndividualTypeDescription_<FromAllocatorT> &
runtime_individual_description, const ToAllocatorT & alloc = ToAllocatorT())
{
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT> out(alloc);
out.type_name = runtime_individual_description.type_name;
for (const auto & field : runtime_individual_description.fields) {
out.fields.emplace_back();
out.fields.back().name = field.name;
out.fields.back().default_value = field.default_value;
out.fields.back().type.type_id = field.type.type_id;
out.fields.back().type.capacity = field.type.capacity;
out.fields.back().type.string_capacity = field.type.string_capacity;
out.fields.back().type.nested_type_name = field.type.nested_type_name;
}
return out;
}
/// Convert a individual type description message to its corresponding runtime struct.
/**
* This function converts a type_description_interfaces/msg/IndividualTypeDescription msg
* to the corresponding rosidl_runtime_cpp::type_description::IndividualTypeDescription
* struct.
*
* \param[in] description_msg the message to convert
* \return the converted runtime struct
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT>
convert_individual_type_description_msg_to_runtime(
const type_description_interfaces::msg::IndividualTypeDescription_<FromAllocatorT> &
individual_description_msg, const ToAllocatorT & alloc = ToAllocatorT())
{
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT> out(alloc);
out.type_name = individual_description_msg.type_name;
for (const auto & field : individual_description_msg.fields) {
out.fields.emplace_back();
out.fields.back().name = field.name;
out.fields.back().default_value = field.default_value;
out.fields.back().type.type_id = field.type.type_id;
out.fields.back().type.capacity = field.type.capacity;
out.fields.back().type.string_capacity = field.type.string_capacity;
out.fields.back().type.nested_type_name = field.type.nested_type_name;
}
return out;
}
// TypeDescription =================================================================================
/// Convert a runtime type description struct to its corresponding message.
/**
* This function converts a rosidl_runtime_cpp::type_description::TypeDescription
* struct to the corresponding type_description_interfaces/msg/TypeDescription
* msg.
*
* \param[in] runtime_description the runtime struct to convert
* \return the converted message
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
type_description_interfaces::msg::TypeDescription_<ToAllocatorT>
convert_type_description_runtime_to_msg(
const rosidl_runtime_cpp::type_description::TypeDescription_<FromAllocatorT> & runtime_description,
const ToAllocatorT & alloc = ToAllocatorT())
{
type_description_interfaces::msg::TypeDescription_<ToAllocatorT> out(alloc);
out.type_description =
convert_individual_type_description_runtime_to_msg(runtime_description.type_description, alloc);
for (const auto & referenced_type_description :
runtime_description.referenced_type_descriptions)
{
out.referenced_type_descriptions.push_back(convert_individual_type_description_runtime_to_msg(
referenced_type_description, alloc));
}
return out;
}
/// Convert a type description message to its corresponding runtime struct.
/**
* This function converts a type_description_interfaces/msg/TypeDescription msg
* to the corresponding rosidl_runtime_cpp::type_description::TypeDescription
* struct.
*
* \param[in] description_msg the message to convert
* \return the converted runtime struct
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT>
convert_type_description_msg_to_runtime(
const type_description_interfaces::msg::TypeDescription_<FromAllocatorT> & description_msg,
const ToAllocatorT & alloc = ToAllocatorT())
{
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT> out(alloc);
out.type_description =
convert_individual_type_description_msg_to_runtime(description_msg.type_description, alloc);
for (const auto & referenced_type_description : description_msg.referenced_type_descriptions) {
out.referenced_type_descriptions.push_back(convert_individual_type_description_msg_to_runtime(
referenced_type_description, alloc));
}
return out;
}
// TypeSource ======================================================================================
/// Convert a runtime type source struct to its corresponding message.
/**
* This function converts a rosidl_runtime_cpp::type_description::TypeSource
* struct to the corresponding type_description_interfaces/msg/TypeSource msg.
*
* \param[in] runtime_type_source the runtime struct to convert
* \return the converted message
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
type_description_interfaces::msg::TypeSource_<ToAllocatorT>
convert_type_source_sequence_runtime_to_msg(
const rosidl_runtime_cpp::type_description::TypeSource_<FromAllocatorT> & runtime_type_source,
const ToAllocatorT & alloc = ToAllocatorT())
{
type_description_interfaces::msg::TypeSource_<ToAllocatorT> out(alloc);
out.type_name = runtime_type_source.type_name;
out.encoding = runtime_type_source.encoding;
out.raw_file_contents = runtime_type_source.raw_file_contents;
return out;
}
/// Convert a type source message to its corresponding runtime struct.
/**
* This function converts a type_description_interfaces/msg/TypeSource msg to
* the corresponding rosidl_runtime_cpp::type_description::TypeSource struct.
*
* \param[in] type_source_msg the message to convert
* \return the converted runtime struct
*/
template<
typename ToAllocatorT = std::allocator<void>,
typename FromAllocatorT
>
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT>
convert_type_source_sequence_msg_to_runtime(
const type_description_interfaces::msg::TypeSource_<FromAllocatorT> & type_source_msg,
const ToAllocatorT & alloc = ToAllocatorT())
{
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT> out(alloc);
out.type_name = type_source_msg.type_name;
out.encoding = type_source_msg.encoding;
out.raw_file_contents = type_source_msg.raw_file_contents;
return out;
}
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_

View File

@@ -20,7 +20,6 @@
#include <mutex>
#include <stdexcept>
#include <string>
#include <vector>
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
@@ -222,13 +221,6 @@ public:
}
}
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override
{
return {};
}
protected:
RCLCPP_PUBLIC
void
@@ -286,15 +278,15 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't take event info: %s", rcl_get_error_string().str);
rcl_reset_error();
return nullptr;
}
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
}
std::shared_ptr<void>
take_data_by_entity_id([[maybe_unused]] size_t id) override
take_data_by_entity_id(size_t id) override
{
(void)id;
return take_data();
}

View File

@@ -287,18 +287,6 @@ public:
* Adding subscriptions, timers, services, etc. with blocking or long running
* callbacks may cause the function exceed the max_duration significantly.
*
* Work that is ready to be done is collected only once, and when collecting that work
* entities which may have multiple pieces of work ready will only be executed at most
* one time.
* The reason for this is that it is not possible to tell if, for example, a ready
* subscription has only one message ready or multiple without checking again.
* Because, in order to find out if there are multiple messages, one message must
* be taken and executed before checking again if that subscription is still ready.
* However, this function only checks for ready entities to work on once,
* and so it will never execute a single entity more than once per call to this function.
* See spin_all() variants for a function that will repeatedly work on a single entity
* in a single call.
*
* If there is no work to be done when this called, it will return immediately
* because the collecting of available work is non-blocking.
* Before each piece of ready work is executed this function checks if the

View File

@@ -19,7 +19,6 @@
#include <memory>
#include <mutex>
#include <set>
#include <vector>
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/waitable.hpp"
@@ -42,9 +41,7 @@ public:
* of this waitable has signaled the wait_set.
*/
RCLCPP_PUBLIC
explicit ExecutorNotifyWaitable(
std::function<void(void)> on_execute_callback = {}, const rclcpp::Context::SharedPtr & context =
rclcpp::contexts::get_global_default_context());
explicit ExecutorNotifyWaitable(std::function<void(void)> on_execute_callback = {});
// Destructor
RCLCPP_PUBLIC
@@ -149,14 +146,6 @@ public:
size_t
get_number_of_ready_guard_conditions() override;
/// Returns the number of used Timers
/**
* Will always return an empty vector.
*/
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override;
private:
/// Callback to run when waitable executes
std::function<void(void)> execute_callback_;
@@ -169,17 +158,8 @@ private:
std::function<void(size_t)> on_ready_callback_;
/// The collection of guard conditions to be waited on.
std::set<rclcpp::GuardCondition::SharedPtr> notify_guard_conditions_;
/// The indixes were our guard conditions were stored in the
/// rcl waitset
std::vector<size_t> idxs_of_added_guard_condition_;
/// set to true, if we got a pending trigger
bool needs_processing = false;
/// A guard condition needed to generate wakeups
rclcpp::GuardCondition::SharedPtr guard_condition_;
std::set<rclcpp::GuardCondition::WeakPtr,
std::owner_less<rclcpp::GuardCondition::WeakPtr>> notify_guard_conditions_;
};
} // namespace executors

View File

@@ -255,13 +255,9 @@ private:
std::vector<BufferT> result_vtr;
result_vtr.reserve(size_);
for (size_t id = 0; id < size_; ++id) {
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);
}
result_vtr.emplace_back(
new typename is_std_unique_ptr<T>::Ptr_type(
*(ring_buffer_[(read_index_ + id) % capacity_])));
}
return result_vtr;
}

View File

@@ -19,7 +19,6 @@
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "rcl/wait.h"
#include "rmw/impl/cpp/demangle.hpp"
@@ -79,8 +78,9 @@ public:
take_data() override = 0;
std::shared_ptr<void>
take_data_by_entity_id([[maybe_unused]] size_t id) override
take_data_by_entity_id(size_t id) override
{
(void)id;
return take_data();
}
@@ -180,13 +180,6 @@ public:
on_new_message_callback_ = nullptr;
}
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override
{
return {};
}
protected:
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_message_callback_ {nullptr};

View File

@@ -110,8 +110,9 @@ public:
}
bool
is_ready([[maybe_unused]] const rcl_wait_set_t & wait_set) override
is_ready(const rcl_wait_set_t & wait_set) override
{
(void) wait_set;
return buffer_->has_data();
}

View File

@@ -1559,10 +1559,6 @@ public:
* which has been created using an existing instance of this class, but which
* has an additional sub-namespace (short for subordinate namespace)
* associated with it.
* A subordinate node and an instance of this class share all the node interfaces
* such as `rclcpp::node_interfaces::NodeParametersInterface`.
* Subordinate nodes are primarily used to organize namespaces and provide a
* hierarchical structure, but they are not meant to be completely independent nodes.
* The sub-namespace will extend the node's namespace for the purpose of
* creating additional entities, such as Publishers, Subscriptions, Service
* Clients and Servers, and so on.

View File

@@ -323,9 +323,11 @@ template<typename ParameterT>
bool
Node::get_parameter(const std::string & name, ParameterT & parameter) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
rclcpp::Parameter parameter_variant;
bool result = get_parameter(name, parameter_variant);
bool result = get_parameter(sub_name, parameter_variant);
if (result) {
parameter = static_cast<ParameterT>(parameter_variant.get_value<ParameterT>());
}
@@ -340,7 +342,9 @@ Node::get_parameter_or(
ParameterT & parameter,
const ParameterT & alternative_value) const
{
bool got_parameter = get_parameter(name, parameter);
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
bool got_parameter = get_parameter(sub_name, parameter);
if (!got_parameter) {
parameter = alternative_value;
}

View File

@@ -214,10 +214,6 @@ public:
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const override;
RCLCPP_PUBLIC
void
enable_parameter_modification() override;
using PreSetCallbacksHandleContainer = std::list<PreSetParametersCallbackHandle::WeakPtr>;
using OnSetCallbacksHandleContainer = std::list<OnSetParametersCallbackHandle::WeakPtr>;
using PostSetCallbacksHandleContainer = std::list<PostSetParametersCallbackHandle::WeakPtr>;

View File

@@ -270,26 +270,6 @@ public:
virtual
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const = 0;
/// Enable parameter modification recursively during parameter callbacks.
/**
* This function is used to enable parameter modification during parameter callbacks.
*
* There are times when it does not allow parameter modification, such as when the parameter
* callbacks are being called and tries to modify the parameters with set_parameter and
* declare_parameter to avoid recursive parameter modification.
* This is protected by rclcpp::node_interfaces::ParameterMutationRecursionGuard.
*
* This function is explicitly called to allow the recursive parameter operation during
* parameter callbacks by the application.
* Once it is enabled, the next parameter operation set/declare/undeclare_parameter are
* allowed to execute in the parameter callback. But, no more further recursive operation
* is allowed, unless user application calls this API again.
*/
RCLCPP_PUBLIC
virtual
void
enable_parameter_modification() = 0;
};
} // namespace node_interfaces

View File

@@ -146,14 +146,6 @@ public:
return *this;
}
/// Append a single parameter override, parameter idiom style.
NodeOptions &
append_parameter_override(const rclcpp::Parameter & param)
{
this->parameter_overrides().push_back(param);
return *this;
}
/// Return the use_global_arguments flag.
RCLCPP_PUBLIC
bool

View File

@@ -45,7 +45,6 @@ public:
* \param[in] names A list of parameter names of interest.
* \param[in] types A list of the types of parameter events of iterest.
* EventType NEW, DELETED, or CHANGED
* \throws std::invalid_argument if event is NULL.
*
* Example Usage:
*

View File

@@ -143,9 +143,12 @@ public:
post_init_setup(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
[[maybe_unused]] const rclcpp::QoS & qos,
[[maybe_unused]] const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
{
(void)qos;
(void)options;
// If needed, setup intra process communication.
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
auto context = node_base->get_context();

View File

@@ -146,18 +146,10 @@ public:
QoS(size_t history_depth); // NOLINT(runtime/explicit): conversion constructor
/// Return the rmw qos profile.
/**
* The profile consists of various QoS policies such as history, reliability, and durability.
* Use the corresponding getter functions to retrieve individual policies.
*/
rmw_qos_profile_t &
get_rmw_qos_profile();
/// Return the rmw qos profile.
/**
* The profile consists of various QoS policies such as history, reliability, and durability.
* Use the corresponding getter functions to retrieve individual policies.
*/
const rmw_qos_profile_t &
get_rmw_qos_profile() const;
@@ -483,7 +475,7 @@ public:
explicit
RosoutQoS(
const QoSInitialization & rosout_qos_initialization = (
QoSInitialization::from_rmw(rmw_qos_profile_rosout_default)
QoSInitialization::from_rmw(rcl_qos_profile_rosout_default)
));
};

View File

@@ -504,9 +504,6 @@ public:
* \param[in] clock clock to use to generate introspection timestamps
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
* \param[in] introspection_state the state to set introspection to
*
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw if
* it failed to configure introspection.
*/
void
configure_introspection(

View File

@@ -201,7 +201,6 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add subscription to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}
@@ -211,7 +210,6 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add client to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}
@@ -221,7 +219,6 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add service to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}
@@ -231,7 +228,6 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add timer to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}

View File

@@ -114,9 +114,9 @@ public:
* all references.
* \param[in] msg Shared pointer to the message to return.
*/
void return_message([[maybe_unused]] std::shared_ptr<MessageT> & msg)
void return_message(std::shared_ptr<MessageT> & msg)
{
// This function is intentionally left empty.
(void)msg;
}
protected:

View File

@@ -209,11 +209,13 @@ public:
/// Called after construction to continue setup that requires shared_from_this().
void
post_init_setup(
[[maybe_unused]] rclcpp::node_interfaces::NodeBaseInterface * node_base,
[[maybe_unused]] const rclcpp::QoS & qos,
[[maybe_unused]] const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const rclcpp::QoS & qos,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
{
// This function is intentionally left empty.
(void)node_base;
(void)qos;
(void)options;
}
/// Take the next message from the inter-process subscription.
@@ -420,17 +422,20 @@ public:
void
return_dynamic_message(
[[maybe_unused]] rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override
{
(void) message;
throw rclcpp::exceptions::UnimplementedError(
"return_dynamic_message is not implemented for Subscription");
}
void
handle_dynamic_message(
[[maybe_unused]] const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
[[maybe_unused]] const rclcpp::MessageInfo & message_info) override
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) override
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_dynamic_message is not implemented for Subscription");
}

View File

@@ -20,8 +20,8 @@
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <utility>
#include "rcl/event_callback.h"
#include "rcl/subscription.h"

View File

@@ -21,7 +21,6 @@
#include <tuple>
#include "rcpputils/shared_library.hpp"
#include "rosidl_runtime_cpp/action_type_support_decl.hpp"
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
#include "rosidl_runtime_cpp/service_type_support_decl.hpp"
@@ -29,48 +28,26 @@
namespace rclcpp
{
/// \brief Extract the package name, middle module, and type name from a full type string.
/// \details This function takes a full type string (e.g., "std_msgs/msg/String") and extracts
/// the package name, middle module (if any), and type name. The middle module is the part
/// between the package name and the type name, which is typically used for message types.
/// For example, for "std_msgs/msg/String", it returns ("std_msgs", "msg", "String").
/// \param[in] full_type
/// \throws std::runtime_error if the input full type string is malformed or does not follow the
/// expected format.
/// \return A tuple containing the package name, middle module (if any), and type name.
RCLCPP_PUBLIC
std::tuple<std::string, std::string, std::string>
extract_type_identifier(const std::string & full_type);
/// \brief Look for the library in the ament prefix paths and return the path to the type support
/// library.
/// \param[in] package_name The name of the package containing the type support library,
/// e.g. "std_msgs".
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \throws std::runtime_error if the library is not found.
/// \return The path to the type support library.
RCLCPP_PUBLIC
std::string get_typesupport_library_path(
const std::string & package_name, const std::string & typesupport_identifier);
/// \brief Load the type support library for the given type.
/// \param[in] type The topic type, e.g. "std_msgs/msg/String"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \throws std::runtime_error if the library is not found or cannot be loaded.
/// \return A shared library
/// Load the type support library for the given type.
/**
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \return A shared library
*/
RCLCPP_PUBLIC
std::shared_ptr<rcpputils::SharedLibrary>
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier);
/// \brief Extracts the message type support handle from the library.
/// \note The library needs to match the topic type. The shared library must stay loaded for the
/// lifetime of the result.
/// \param[in] type The topic type, e.g. "std_msgs/msg/String"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \param[in] library The shared type support library
/// \throws std::runtime_error if the symbol of type not found in the library.
/// \return A message type support handle
/// Extract the message type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \throws std::runtime_error if the symbol of type not found in the library.
* \return A message type support handle
*/
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_message_typesupport_handle(
@@ -78,14 +55,16 @@ get_message_typesupport_handle(
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// \brief Extracts the service type support handle from the library.
/// \note The library needs to match the service type. The shared library must stay loaded for the
/// lifetime of the result.
/// \param[in] type The service type, e.g. "std_srvs/srv/Empty"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \param[in] library The shared type support library
/// \throws std::runtime_error if the symbol of type not found in the library.
/// \return A service type support handle
/// Extract the service type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \param[in] type The service type, e.g. "std_srvs/srv/Empty"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \throws std::runtime_error if the symbol of type not found in the library.
* \return A service type support handle
*/
RCLCPP_PUBLIC
const rosidl_service_type_support_t *
get_service_typesupport_handle(
@@ -93,21 +72,6 @@ get_service_typesupport_handle(
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// \brief Extracts the action type support handle from the library.
/// \note The library needs to match the action type. The shared library must stay loaded for the
/// lifetime of the result.
/// \param[in] type The action type, e.g. "example_interfaces/action/Fibonacci"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \param[in] library The shared type support library
/// \throws std::runtime_error if the symbol of type not found in the library.
/// \return A action type support handle
RCLCPP_PUBLIC
const rosidl_action_type_support_t *
get_action_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
} // namespace rclcpp
#endif // RCLCPP__TYPESUPPORT_HELPERS_HPP_

View File

@@ -15,7 +15,6 @@
#ifndef RCLCPP__WAIT_FOR_MESSAGE_HPP_
#define RCLCPP__WAIT_FOR_MESSAGE_HPP_
#include <future>
#include <memory>
#include <string>
@@ -24,7 +23,6 @@
#include "rclcpp/node.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
#include "rclcpp/qos.hpp"
namespace rclcpp
{
@@ -81,11 +79,10 @@ bool wait_for_message(
/**
* Wait for the next incoming message to arrive on a specified topic before the specified timeout.
*
* \param[out] out is the message to be filled when a new message is arriving
* \param[out] out is the message to be filled when a new message is arriving.
* \param[in] node the node pointer to initialize the subscription on.
* \param[in] topic the topic to wait for messages.
* \param[in] time_to_wait parameter specifying the timeout before returning.
* \param[in] qos parameter specifying QoS settings for the subscription.
* \return true if a message was successfully received, false if message could not
* be obtained or shutdown was triggered asynchronously on the context.
*/
@@ -94,10 +91,9 @@ bool wait_for_message(
MsgT & out,
rclcpp::Node::SharedPtr node,
const std::string & topic,
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1),
const rclcpp::QoS & qos = rclcpp::SystemDefaultsQoS())
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
{
auto sub = node->create_subscription<MsgT>(topic, qos, [](const std::shared_ptr<const MsgT>) {});
auto sub = node->create_subscription<MsgT>(topic, 1, [](const std::shared_ptr<const MsgT>) {});
return wait_for_message<MsgT, Rep, Period>(
out, sub, node->get_node_options().context(), time_to_wait);
}

View File

@@ -176,9 +176,7 @@ public:
for (; ii < wait_set.size_of_timers(); ++ii) {
if (rcl_wait_set.timers[ii] != nullptr) {
ret = wait_set.timers(ii);
if (ret) {
break;
}
break;
}
}
}
@@ -219,9 +217,7 @@ public:
if (rcl_wait_set.subscriptions[ii] != nullptr) {
ret = wait_set.subscriptions(ii);
rcl_wait_set.subscriptions[ii] = nullptr;
if (ret) {
break;
}
break;
}
}
}
@@ -241,9 +237,7 @@ public:
if (rcl_wait_set.services[ii] != nullptr) {
ret = wait_set.services(ii);
rcl_wait_set.services[ii] = nullptr;
if (ret) {
break;
}
break;
}
}
}
@@ -263,9 +257,7 @@ public:
if (rcl_wait_set.clients[ii] != nullptr) {
ret = wait_set.clients(ii);
rcl_wait_set.clients[ii] = nullptr;
if (ret) {
break;
}
break;
}
}
}

View File

@@ -216,11 +216,6 @@ public:
shared_waitables_
);
if (this->needs_pruning_) {
this->storage_prune_deleted_entities();
this->needs_pruning_ = false;
}
this->storage_release_ownerships();
}
@@ -460,60 +455,59 @@ public:
size_t size_of_subscriptions() const
{
return subscriptions_.size();
return shared_subscriptions_.size();
}
size_t size_of_timers() const
{
return timers_.size();
return shared_timers_.size();
}
size_t size_of_clients() const
{
return clients_.size();
return shared_clients_.size();
}
size_t size_of_services() const
{
return services_.size();
return shared_services_.size();
}
size_t size_of_waitables() const
{
return waitables_.size();
return shared_waitables_.size();
}
std::shared_ptr<rclcpp::SubscriptionBase>
subscriptions(size_t ii) const
{
return subscriptions_[ii].lock();
return shared_subscriptions_[ii].subscription;
}
std::shared_ptr<rclcpp::TimerBase>
timers(size_t ii) const
{
return timers_[ii].lock();
return shared_timers_[ii];
}
std::shared_ptr<rclcpp::ClientBase>
clients(size_t ii) const
{
return clients_[ii].lock();
return shared_clients_[ii];
}
std::shared_ptr<rclcpp::ServiceBase>
services(size_t ii) const
{
return services_[ii].lock();
return shared_services_[ii];
}
std::shared_ptr<rclcpp::Waitable>
waitables(size_t ii) const
{
return waitables_[ii].lock();
return shared_waitables_[ii].waitable;
}
private:
size_t ownership_reference_counter_ = 0;
SequenceOfWeakSubscriptions subscriptions_;

View File

@@ -160,15 +160,6 @@ public:
services_,
waitables_
);
if(this->needs_pruning_) {
// we need to throw here, as the indexing of the rcl_waitset is broken,
// in case of invalid entries
throw std::runtime_error(
"StaticStorage::storage_rebuild_rcl_wait_set(): entity weak_ptr "
"unexpectedly expired in static entity storage");
}
}
// storage_add_subscription() explicitly not declared here

View File

@@ -734,6 +734,8 @@ private:
wait_result_dirty_ = false;
// this method comes from the SynchronizationPolicy
this->sync_wait_result_acquire();
// this method comes from the StoragePolicy
this->storage_acquire_ownerships();
}
/// Called by the WaitResult's destructor to release resources.
@@ -750,6 +752,8 @@ private:
}
wait_result_holding_ = false;
wait_result_dirty_ = false;
// this method comes from the StoragePolicy
this->storage_release_ownerships();
// this method comes from the SynchronizationPolicy
this->sync_wait_result_release();
}

View File

@@ -18,7 +18,6 @@
#include <atomic>
#include <functional>
#include <memory>
#include <vector>
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -28,8 +27,6 @@
namespace rclcpp
{
class TimerBase;
class Waitable
{
public:
@@ -261,17 +258,6 @@ public:
void
clear_on_ready_callback() = 0;
/// Returns all timers used by this waitable
/**
* Must return all timers used within the waitable.
* Note, it is not supported, that timers are added
* or removed over the lifetime of the waitable.
*/
RCLCPP_PUBLIC
virtual
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const = 0;
private:
std::atomic<bool> in_use_by_wait_set_{false};
}; // class Waitable

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.5.4</version>
<version>29.3.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -124,7 +124,8 @@ def get_rclcpp_suffix_from_features(features):
) \
do { \
static_assert( \
::std::is_convertible_v<decltype(logger), ::rclcpp::Logger>, \
::std::is_same<typename std::remove_cv_t<typename std::remove_reference_t<decltype(logger)>>, \
typename ::rclcpp::Logger>::value, \
"First argument to logging macros must be an rclcpp::Logger"); \
@[ if 'throttle' in feature_combination]@ \
auto get_time_point = [&c=clock](rcutils_time_point_value_t * time_point) -> rcutils_ret_t { \

View File

@@ -367,245 +367,4 @@ Clock::create_jump_callback(
// *INDENT-ON*
}
class ClockWaiter::ClockWaiterImpl
{
private:
std::condition_variable cv_;
rclcpp::Clock::SharedPtr clock_;
bool time_source_changed_ = false;
std::function<void(const rcl_time_jump_t &)> post_time_jump_callback;
bool
wait_until_system_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
auto system_time = std::chrono::system_clock::time_point(
// Cast because system clock resolution is too big for nanoseconds on some systems
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(abs_time.nanoseconds())));
return cv_.wait_until(lock, system_time, pred);
}
bool
wait_until_steady_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
// Synchronize because RCL steady clock epoch might differ from chrono::steady_clock epoch
const rclcpp::Time rcl_entry = clock_->now();
const std::chrono::steady_clock::time_point chrono_entry = std::chrono::steady_clock::now();
const rclcpp::Duration delta_t = abs_time - rcl_entry;
const std::chrono::steady_clock::time_point chrono_until =
chrono_entry + std::chrono::nanoseconds(delta_t.nanoseconds());
return cv_.wait_until(lock, chrono_until, pred);
}
bool
wait_until_ros_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
// Install jump handler for any amount of time change, for two purposes:
// - if ROS time is active, check if time reached on each new clock sample
// - Trigger via on_clock_change to detect if time source changes, to invalidate sleep
rcl_jump_threshold_t threshold;
threshold.on_clock_change = true;
// 0 is disable, so -1 and 1 are smallest possible time changes
threshold.min_backward.nanoseconds = -1;
threshold.min_forward.nanoseconds = 1;
time_source_changed_ = false;
post_time_jump_callback = [this, &lock] (const rcl_time_jump_t & jump)
{
if (jump.clock_change != RCL_ROS_TIME_NO_CHANGE) {
std::lock_guard<std::mutex> lk(*lock.mutex());
time_source_changed_ = true;
}
cv_.notify_one();
};
// Note this is a trade-off. Adding the callback for every call
// is expensive for high frequency calls. For low frequency waits
// its more overhead to have the callback being called all the time.
// As we expect the use case to be low frequency calls to wait_until
// with relative big pauses between the calls, we install it on demand.
auto clock_handler = clock_->create_jump_callback(
nullptr,
post_time_jump_callback,
threshold);
if (!clock_->ros_time_is_active()) {
auto system_time = std::chrono::system_clock::time_point(
// Cast because system clock resolution is too big for nanoseconds on some systems
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(abs_time.nanoseconds())));
return cv_.wait_until(lock, system_time, [this, &pred] () {
return time_source_changed_ || pred();
});
}
// RCL_ROS_TIME with ros_time_is_active.
// Just wait without "until" because installed
// jump callbacks wake the cv on every new sample.
cv_.wait(lock, [this, &pred, &abs_time] () {
return clock_->now() >= abs_time || time_source_changed_ || pred();
});
return clock_->now() < abs_time;
}
public:
explicit ClockWaiterImpl(const rclcpp::Clock::SharedPtr & clock)
:clock_(clock)
{
}
bool
wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
switch(clock_->get_clock_type()) {
case RCL_CLOCK_UNINITIALIZED:
throw std::runtime_error("Error, wait on uninitialized clock called");
case RCL_ROS_TIME:
return wait_until_ros_time(lock, abs_time, pred);
break;
case RCL_STEADY_TIME:
return wait_until_steady_time(lock, abs_time, pred);
break;
case RCL_SYSTEM_TIME:
return wait_until_system_time(lock, abs_time, pred);
break;
}
return false;
}
void
notify_one()
{
cv_.notify_one();
}
};
ClockWaiter::ClockWaiter(const rclcpp::Clock::SharedPtr & clock)
:impl_(std::make_unique<ClockWaiterImpl>(clock))
{
}
ClockWaiter::~ClockWaiter() = default;
bool
ClockWaiter::wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
return impl_->wait_until(lock, abs_time, pred);
}
void
ClockWaiter::notify_one()
{
impl_->notify_one();
}
class ClockConditionalVariable::Impl
{
std::mutex pred_mutex_;
bool shutdown_ = false;
rclcpp::Context::SharedPtr context_;
rclcpp::OnShutdownCallbackHandle shutdown_cb_handle_;
ClockWaiter::UniquePtr clock_;
public:
Impl(const rclcpp::Clock::SharedPtr & clock, rclcpp::Context::SharedPtr context)
:context_(context),
clock_(std::make_unique<ClockWaiter>(clock))
{
if (!context_ || !context_->is_valid()) {
throw std::runtime_error("context cannot be slept with because it's invalid");
}
// Wake this thread if the context is shutdown
shutdown_cb_handle_ = context_->add_on_shutdown_callback(
[this]() {
{
std::unique_lock lock(pred_mutex_);
shutdown_ = true;
}
clock_->notify_one();
});
}
~Impl()
{
context_->remove_on_shutdown_callback(shutdown_cb_handle_);
}
bool
wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred)
{
if(lock.mutex() != &pred_mutex_) {
throw std::runtime_error(
"ClockConditionalVariable::wait_until: Internal error, given lock does not use"
" mutex returned by this->mutex()");
}
clock_->wait_until(lock, until, [this, &pred] () -> bool {
return shutdown_ || pred();
});
return true;
}
void
notify_one()
{
clock_->notify_one();
}
std::mutex &
mutex()
{
return pred_mutex_;
}
};
ClockConditionalVariable::ClockConditionalVariable(
const rclcpp::Clock::SharedPtr & clock,
rclcpp::Context::SharedPtr context)
:impl_(std::make_unique<Impl>(clock, context))
{
}
ClockConditionalVariable::~ClockConditionalVariable() = default;
void
ClockConditionalVariable::notify_one()
{
impl_->notify_one();
}
bool
ClockConditionalVariable::wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred)
{
return impl_->wait_until(lock, until, pred);
}
std::mutex &
ClockConditionalVariable::mutex()
{
return impl_->mutex();
}
} // namespace rclcpp

View File

@@ -14,7 +14,6 @@
#include "rclcpp/context.hpp"
#include <map>
#include <memory>
#include <mutex>
#include <sstream>
@@ -143,52 +142,11 @@ rclcpp_logging_output_handler(
}
} // extern "C"
/**
* Global storage for pre and post shutdown recursive mutexes.
* Note, this is a ABI compatibility hack.
*/
class MutexLookup
{
std::mutex m;
struct MutexHolder
{
std::recursive_mutex on_shutdown_callbacks_mutex_;
std::recursive_mutex pre_shutdown_callbacks_mutex_;
};
std::map<const Context *, std::unique_ptr<MutexHolder>> mutexMap;
public:
MutexHolder & getMutexes(const Context *forContext)
{
auto it = mutexMap.find(forContext);
if(it == mutexMap.end()) {
it = mutexMap.emplace(forContext, std::make_unique<MutexHolder>()).first;
}
return *(it->second);
}
/**
* Only supposed to be called on deletion of context
*/
void removeMutexes(const Context *forContext)
{
mutexMap.erase(forContext);
}
};
MutexLookup mutexStorage;
Context::Context()
: rcl_context_(nullptr),
shutdown_reason_(""),
logging_mutex_(nullptr)
{
// allocate mutexes
mutexStorage.getMutexes(this);
}
{}
Context::~Context()
{
@@ -207,9 +165,6 @@ Context::~Context()
} catch (...) {
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context()");
}
// delete mutexes
mutexStorage.removeMutexes(this);
}
RCLCPP_LOCAL
@@ -355,17 +310,9 @@ Context::shutdown(const std::string & reason)
// call each pre-shutdown callback
{
std::lock_guard<std::recursive_mutex> lock{mutexStorage.getMutexes(
this).pre_shutdown_callbacks_mutex_};
// callbacks may delete other callbacks during the execution,
// therefore we need to save a copy and check before execution
// if the next callback is still present
auto cpy = pre_shutdown_callbacks_;
for (const auto & callback : cpy) {
auto it = std::find(pre_shutdown_callbacks_.begin(), pre_shutdown_callbacks_.end(), callback);
if(it != pre_shutdown_callbacks_.end()) {
(*callback)();
}
std::lock_guard<std::mutex> lock{pre_shutdown_callbacks_mutex_};
for (const auto & callback : pre_shutdown_callbacks_) {
(*callback)();
}
}
@@ -378,17 +325,9 @@ Context::shutdown(const std::string & reason)
shutdown_reason_ = reason;
// call each shutdown callback
{
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
this).on_shutdown_callbacks_mutex_);
// callbacks may delete other callbacks during the execution,
// therefore we need to save a copy and check before execution
// if the next callback is still present
auto cpy = on_shutdown_callbacks_;
for (const auto & callback : cpy) {
auto it = std::find(on_shutdown_callbacks_.begin(), on_shutdown_callbacks_.end(), callback);
if(it != on_shutdown_callbacks_.end()) {
(*callback)();
}
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
for (const auto & callback : on_shutdown_callbacks_) {
(*callback)();
}
}
@@ -459,12 +398,10 @@ Context::add_shutdown_callback(
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
this).pre_shutdown_callbacks_mutex_);
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
} else {
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
this).on_shutdown_callbacks_mutex_);
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
}
@@ -484,7 +421,7 @@ Context::remove_shutdown_callback(
}
const auto remove_callback = [&callback_shared_ptr](auto & mutex, auto & callback_vector) {
const std::lock_guard<std::recursive_mutex> lock(mutex);
const std::lock_guard<std::mutex> lock(mutex);
auto iter = callback_vector.begin();
for (; iter != callback_vector.end(); iter++) {
if ((*iter).get() == callback_shared_ptr.get()) {
@@ -495,7 +432,6 @@ Context::remove_shutdown_callback(
return false;
}
callback_vector.erase(iter);
return true;
};
@@ -503,11 +439,9 @@ Context::remove_shutdown_callback(
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
return remove_callback(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
pre_shutdown_callbacks_);
return remove_callback(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
} else {
return remove_callback(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
on_shutdown_callbacks_);
return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
}
}
@@ -528,7 +462,7 @@ std::vector<rclcpp::Context::ShutdownCallback>
Context::get_shutdown_callback() const
{
const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
const std::lock_guard<std::recursive_mutex> lock(mutex);
const std::lock_guard<std::mutex> lock(mutex);
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
for (auto & callback : callback_set) {
callbacks.push_back(*callback);
@@ -540,11 +474,9 @@ Context::get_shutdown_callback() const
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
return get_callback_vector(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
pre_shutdown_callbacks_);
return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
} else {
return get_callback_vector(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
on_shutdown_callbacks_);
return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
}
}

View File

@@ -23,9 +23,10 @@ namespace detail
void
RMWImplementationSpecificPublisherPayload::modify_rmw_publisher_options(
[[maybe_unused]] rmw_publisher_options_t & rmw_publisher_options) const
rmw_publisher_options_t & rmw_publisher_options) const
{
// By default, do not mutate the rmw publisher options.
(void)rmw_publisher_options;
}
} // namespace detail

View File

@@ -23,9 +23,10 @@ namespace detail
void
RMWImplementationSpecificSubscriptionPayload::modify_rmw_subscription_options(
[[maybe_unused]] rmw_subscription_options_t & rmw_subscription_options) const
rmw_subscription_options_t & rmw_subscription_options) const
{
// By default, do not mutate the rmw subscription options.
(void)rmw_subscription_options;
}
} // namespace detail

View File

@@ -31,10 +31,11 @@ namespace detail
std::vector<std::string>
get_unparsed_ros_arguments(
[[maybe_unused]] int argc, char const * const * argv,
int argc, char const * const * argv,
rcl_arguments_t * arguments,
rcl_allocator_t allocator)
{
(void)argc;
std::vector<std::string> unparsed_ros_arguments;
int unparsed_ros_args_count = rcl_arguments_get_count_unparsed_ros(arguments);
if (unparsed_ros_args_count > 0) {

View File

@@ -93,9 +93,7 @@ throw_from_rcl_error(
RCLErrorBase::RCLErrorBase(rcl_ret_t ret, const rcl_error_state_t * error_state)
: ret(ret), message(error_state->message), file(error_state->file), line(error_state->line_number),
formatted_message(rcl_get_error_string().str)
{
rcl_reset_error();
}
{}
RCLError::RCLError(
rcl_ret_t ret,

View File

@@ -66,7 +66,7 @@ Executor::Executor(const rclcpp::ExecutorOptions & options)
notify_waitable_(std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(
[this]() {
this->entities_need_rebuild_.store(true);
}, options.context)),
})),
entities_need_rebuild_(true),
collector_(notify_waitable_),
wait_set_({}, {}, {}, {}, {}, {}, options.context),
@@ -84,9 +84,7 @@ Executor::Executor(const rclcpp::ExecutorOptions & options)
notify_waitable_->add_guard_condition(interrupt_guard_condition_);
notify_waitable_->add_guard_condition(shutdown_guard_condition_);
// we need to initially rebuild the collection,
// so that the notify_waitable_ is added
collect_entities();
wait_set_.add_waitable(notify_waitable_);
}
Executor::~Executor()
@@ -169,9 +167,10 @@ Executor::get_automatically_added_callback_groups_from_nodes()
void
Executor::add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
[[maybe_unused]] rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify)
{
(void) node_ptr;
this->collector_.add_callback_group(group_ptr);
try {
@@ -372,14 +371,7 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
// both spin_some and spin_all wait for work at the beginning
wait_result_.reset();
wait_for_work(std::chrono::milliseconds(0));
bool entity_states_fully_polled = true;
if (entities_need_rebuild_) {
// if the last wait triggered a collection rebuild, we need to call
// wait_for_work once more, in order to do a collection rebuild and collect
// events from the just added entities
entity_states_fully_polled = false;
}
bool just_waited = true;
// The logic of this while loop is as follows:
//
@@ -401,14 +393,12 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
AnyExecutable any_exec;
if (get_next_ready_executable(any_exec)) {
execute_any_executable(any_exec);
// during the execution some entity might got ready therefore we need
// to repoll the states of all entities
entity_states_fully_polled = false;
just_waited = false;
} else {
// if nothing is ready, reset the result to clear it
wait_result_.reset();
if (entity_states_fully_polled) {
if (just_waited) {
// there was no work after just waiting, always exit in this case
// before the exhaustive condition can be checked
break;
@@ -418,13 +408,7 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
// if exhaustive, wait for work again
// this only happens for spin_all; spin_some only waits at the start
wait_for_work(std::chrono::milliseconds(0));
entity_states_fully_polled = true;
if (entities_need_rebuild_) {
// if the last wait triggered a collection rebuild, we need to call
// wait_for_work once more, in order to do a collection rebuild and
// collect events from the just added entities
entity_states_fully_polled = false;
}
just_waited = true;
} else {
break;
}
@@ -584,7 +568,6 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
"rcl_return_loaned_message_from_subscription() failed for subscription on topic "
"'%s': %s",
subscription->get_topic_name(), rcl_get_error_string().str);
rcl_reset_error();
}
loaned_msg = nullptr;
}
@@ -746,16 +729,33 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
// Clear any previous wait result
this->wait_result_.reset();
// 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;
{
std::lock_guard<std::mutex> guard(mutex_);
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));
}
}
}
this->wait_result_.emplace(wait_set_.wait(timeout));
// drop references to the callback groups, before trying to execute anything
cbgs.clear();
if (!this->wait_result_ || this->wait_result_->kind() == WaitResultKind::Empty) {
RCUTILS_LOG_WARN_NAMED(
"rclcpp",

View File

@@ -20,11 +20,8 @@ namespace rclcpp
namespace executors
{
ExecutorNotifyWaitable::ExecutorNotifyWaitable(
std::function<void(void)> on_execute_callback,
const rclcpp::Context::SharedPtr & context)
: execute_callback_(on_execute_callback),
guard_condition_(std::make_shared<rclcpp::GuardCondition>(context))
ExecutorNotifyWaitable::ExecutorNotifyWaitable(std::function<void(void)> on_execute_callback)
: execute_callback_(on_execute_callback)
{
}
@@ -33,9 +30,6 @@ ExecutorNotifyWaitable::ExecutorNotifyWaitable(ExecutorNotifyWaitable & other)
std::lock_guard<std::mutex> lock(other.guard_condition_mutex_);
this->execute_callback_ = other.execute_callback_;
this->notify_guard_conditions_ = other.notify_guard_conditions_;
this->guard_condition_ = other.guard_condition_;
this->idxs_of_added_guard_condition_ = other.idxs_of_added_guard_condition_;
this->needs_processing = other.needs_processing;
}
ExecutorNotifyWaitable & ExecutorNotifyWaitable::operator=(ExecutorNotifyWaitable & other)
@@ -44,9 +38,6 @@ ExecutorNotifyWaitable & ExecutorNotifyWaitable::operator=(ExecutorNotifyWaitabl
std::lock_guard<std::mutex> lock(other.guard_condition_mutex_);
this->execute_callback_ = other.execute_callback_;
this->notify_guard_conditions_ = other.notify_guard_conditions_;
this->guard_condition_ = other.guard_condition_;
this->idxs_of_added_guard_condition_ = other.idxs_of_added_guard_condition_;
this->needs_processing = other.needs_processing;
}
return *this;
}
@@ -56,42 +47,21 @@ ExecutorNotifyWaitable::add_to_wait_set(rcl_wait_set_t & wait_set)
{
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
idxs_of_added_guard_condition_.clear();
idxs_of_added_guard_condition_.reserve(notify_guard_conditions_.size());
if(needs_processing) {
rcl_guard_condition_t * cond = &guard_condition_->get_rcl_guard_condition();
size_t rcl_index;
rcl_ret_t ret = rcl_wait_set_add_guard_condition(&wait_set, cond, &rcl_index);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(
ret, "failed to add guard condition to wait set");
}
idxs_of_added_guard_condition_.push_back(rcl_index);
// we want to directly wake up any way, not need to add the other guard conditions
guard_condition_->trigger();
return;
}
// Note: no guard conditions need to be re-triggered, since the guard
// conditions in this class are not tracking a stateful condition, but instead
// only serve to interrupt the wait set when new information is available to
// consider.
for (const auto & guard_condition : this->notify_guard_conditions_) {
for (auto weak_guard_condition : this->notify_guard_conditions_) {
auto guard_condition = weak_guard_condition.lock();
if (!guard_condition) {continue;}
rcl_guard_condition_t * cond = &guard_condition->get_rcl_guard_condition();
size_t rcl_index;
rcl_ret_t ret = rcl_wait_set_add_guard_condition(&wait_set, cond, &rcl_index);
rcl_ret_t ret = rcl_wait_set_add_guard_condition(&wait_set, cond, NULL);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(
ret, "failed to add guard condition to wait set");
}
idxs_of_added_guard_condition_.push_back(rcl_index);
}
}
@@ -101,23 +71,20 @@ ExecutorNotifyWaitable::is_ready(const rcl_wait_set_t & wait_set)
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
bool any_ready = false;
for (size_t rcl_index : idxs_of_added_guard_condition_) {
if(rcl_index >= wait_set.size_of_guard_conditions) {
throw std::runtime_error(
"ExecutorNotifyWaitable::is_ready: Internal error, got index out of range");
}
const auto * rcl_guard_condition = wait_set.guard_conditions[rcl_index];
for (size_t ii = 0; ii < wait_set.size_of_guard_conditions; ++ii) {
const auto * rcl_guard_condition = wait_set.guard_conditions[ii];
if (nullptr == rcl_guard_condition) {
continue;
}
any_ready = true;
needs_processing = true;
break;
for (const auto & weak_guard_condition : this->notify_guard_conditions_) {
auto guard_condition = weak_guard_condition.lock();
if (guard_condition && &guard_condition->get_rcl_guard_condition() == rcl_guard_condition) {
any_ready = true;
break;
}
}
}
return any_ready;
}
@@ -125,9 +92,6 @@ void
ExecutorNotifyWaitable::execute(const std::shared_ptr<void> & /*data*/)
{
std::lock_guard<std::mutex> lock(execute_mutex_);
needs_processing = false;
this->execute_callback_();
}
@@ -138,8 +102,9 @@ ExecutorNotifyWaitable::take_data()
}
std::shared_ptr<void>
ExecutorNotifyWaitable::take_data_by_entity_id([[maybe_unused]] size_t id)
ExecutorNotifyWaitable::take_data_by_entity_id(size_t id)
{
(void) id;
return nullptr;
}
@@ -157,7 +122,11 @@ ExecutorNotifyWaitable::set_on_ready_callback(std::function<void(size_t, int)> c
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
on_ready_callback_ = gc_callback;
for (const auto & gc : notify_guard_conditions_) {
for (auto weak_gc : notify_guard_conditions_) {
auto gc = weak_gc.lock();
if (!gc) {
continue;
}
gc->set_on_trigger_callback(on_ready_callback_);
}
}
@@ -169,7 +138,11 @@ ExecutorNotifyWaitable::clear_on_ready_callback()
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
on_ready_callback_ = nullptr;
for (const auto & gc : notify_guard_conditions_) {
for (auto weak_gc : notify_guard_conditions_) {
auto gc = weak_gc.lock();
if (!gc) {
continue;
}
gc->set_on_trigger_callback(nullptr);
}
}
@@ -186,9 +159,9 @@ void
ExecutorNotifyWaitable::add_guard_condition(rclcpp::GuardCondition::WeakPtr weak_guard_condition)
{
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
const auto & guard_condition = weak_guard_condition.lock();
if (guard_condition && notify_guard_conditions_.count(guard_condition) == 0) {
notify_guard_conditions_.insert(guard_condition);
auto guard_condition = weak_guard_condition.lock();
if (guard_condition && notify_guard_conditions_.count(weak_guard_condition) == 0) {
notify_guard_conditions_.insert(weak_guard_condition);
if (on_ready_callback_) {
guard_condition->set_on_trigger_callback(on_ready_callback_);
}
@@ -199,17 +172,11 @@ void
ExecutorNotifyWaitable::remove_guard_condition(rclcpp::GuardCondition::WeakPtr weak_guard_condition)
{
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
const auto & guard_condition = weak_guard_condition.lock();
if (!guard_condition) {
// If the lock did not work, the guard condition can't be
// saved in the sets, therefore we don't need to remove it
return;
}
auto it = notify_guard_conditions_.find(guard_condition);
if (it != notify_guard_conditions_.end()) {
notify_guard_conditions_.erase(it);
if (notify_guard_conditions_.count(weak_guard_condition) != 0) {
notify_guard_conditions_.erase(weak_guard_condition);
auto guard_condition = weak_guard_condition.lock();
// If this notify waitable doesn't have an on_ready_callback, then there's nothing to unset
if (on_ready_callback_) {
if (guard_condition && on_ready_callback_) {
guard_condition->set_on_trigger_callback(nullptr);
}
}
@@ -222,12 +189,5 @@ ExecutorNotifyWaitable::get_number_of_ready_guard_conditions()
return notify_guard_conditions_.size();
}
std::vector<std::shared_ptr<rclcpp::TimerBase>>
ExecutorNotifyWaitable::get_timers() const
{
return {};
}
} // namespace executors
} // namespace rclcpp

View File

@@ -79,8 +79,9 @@ MultiThreadedExecutor::get_number_of_threads()
}
void
MultiThreadedExecutor::run([[maybe_unused]] size_t this_thread_number)
MultiThreadedExecutor::run(size_t this_thread_number)
{
(void)this_thread_number;
while (rclcpp::ok(this->context_) && spinning.load()) {
rclcpp::AnyExecutable any_exec;
{

View File

@@ -318,8 +318,10 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
void
EventsExecutor::handle_updated_entities([[maybe_unused]] bool notify)
EventsExecutor::handle_updated_entities(bool notify)
{
(void)notify;
// Do not rebuild if we don't need to.
// A rebuild event could be generated, but then
// this function could end up being called from somewhere else
@@ -406,16 +408,8 @@ EventsExecutor::refresh_current_collection(
[this](auto waitable) {
waitable->set_on_ready_callback(
this->create_waitable_callback(waitable.get()));
for (const auto & t : waitable->get_timers()) {
timers_manager_->add_timer(t);
}
},
[this](auto waitable) {
waitable->clear_on_ready_callback();
for (const auto & t : waitable->get_timers()) {
timers_manager_->remove_timer(t);
}
});
[](auto waitable) {waitable->clear_on_ready_callback();});
}
std::function<void(size_t)>

View File

@@ -56,9 +56,10 @@ GenericSubscription::handle_serialized_message(
void
GenericSubscription::handle_loaned_message(
[[maybe_unused]] void * message,
[[maybe_unused]] const rclcpp::MessageInfo & message_info)
void * message, const rclcpp::MessageInfo & message_info)
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_loaned_message is not implemented for GenericSubscription");
}
@@ -110,17 +111,20 @@ GenericSubscription::create_dynamic_message()
void
GenericSubscription::return_dynamic_message(
[[maybe_unused]] rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
{
(void) message;
throw rclcpp::exceptions::UnimplementedError(
"return_dynamic_message is not implemented for GenericSubscription");
}
void
GenericSubscription::handle_dynamic_message(
[[maybe_unused]] const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
[[maybe_unused]] const rclcpp::MessageInfo & message_info)
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info)
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_dynamic_message is not implemented for GenericSubscription");
}

View File

@@ -689,7 +689,7 @@ Node::create_generic_client(
node_base_,
node_graph_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
service_name,
service_type,
qos,
group);

View File

@@ -132,7 +132,6 @@ NodeBase::NodeBase(
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Error in destruction of rosout publisher: %s", rcl_get_error_string().str);
rcl_reset_error();
}
}
}
@@ -140,7 +139,6 @@ NodeBase::NodeBase(
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Error in destruction of rcl node handle: %s", rcl_get_error_string().str);
rcl_reset_error();
}
delete node;
});

View File

@@ -1191,10 +1191,3 @@ NodeParameters::get_parameter_overrides() const
{
return parameter_overrides_;
}
void
NodeParameters::enable_parameter_modification()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
parameter_modification_enabled_ = true;
}

View File

@@ -65,11 +65,11 @@ public:
: logger_(node_logging->get_logger()),
node_base_(node_base)
{
rclcpp::ParameterValue enable_param;
const std::string enable_param_name = "start_type_description_service";
if (!node_parameters->has_parameter(enable_param_name)) {
enable_param = node_parameters->declare_parameter(
bool enabled = false;
try {
auto enable_param = node_parameters->declare_parameter(
enable_param_name,
rclcpp::ParameterValue(true),
rcl_interfaces::msg::ParameterDescriptor()
@@ -77,21 +77,13 @@ public:
.set__type(rclcpp::PARAMETER_BOOL)
.set__description("Start the ~/get_type_description service for this node.")
.set__read_only(true));
} else {
enable_param = node_parameters->get_parameter(enable_param_name).get_parameter_value();
}
if (enable_param.get_type() != rclcpp::PARAMETER_BOOL) {
RCLCPP_ERROR(
logger_,
"Invalid type '%s' for parameter 'start_type_description_service', should be 'bool'",
rclcpp::to_string(enable_param.get_type()).c_str());
std::ostringstream ss;
ss << "Wrong parameter type, parameter {" << enable_param_name << "} is of type {bool}, "
<< "setting it to {" << to_string(enable_param.get_type()) << "} is not allowed.";
throw rclcpp::exceptions::InvalidParameterTypeException(enable_param_name, ss.str());
enabled = enable_param.get<bool>();
} catch (const rclcpp::exceptions::InvalidParameterTypeException & exc) {
RCLCPP_ERROR(logger_, "%s", exc.what());
throw;
}
if (enable_param.get<bool>()) {
if (enabled) {
auto * rcl_node = node_base->get_rcl_node_handle();
std::shared_ptr<rcl_service_t> rcl_srv(
new rcl_service_t,
@@ -113,7 +105,6 @@ public:
RCLCPP_ERROR(
logger_, "Failed to initialize ~/get_type_description service: %s",
rcl_get_error_string().str);
rcl_reset_error();
throw std::runtime_error(
"Failed to initialize ~/get_type_description service.");
}

View File

@@ -28,9 +28,6 @@ ParameterEventsFilter::ParameterEventsFilter(
const std::vector<EventType> & types)
: event_(event)
{
if (!event) {
throw std::invalid_argument("event cannot be null");
}
if (std::find(types.begin(), types.end(), EventType::NEW) != types.end()) {
for (auto & new_parameter : event->new_parameters) {
if (std::find(names.begin(), names.end(), new_parameter.name) != names.end()) {

View File

@@ -81,15 +81,7 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * nod
throw InvalidParametersException(message);
}
const rcl_variant_t * const c_param_value = &(c_params_node->parameter_values[p]);
ParameterValue value;
try {
value = parameter_value_from(c_param_value);
} catch (const InvalidParameterValueException & e) {
throw InvalidParameterValueException(
std::string("parameter_value_from failed for parameter '") +
c_param_name + "': " + e.what());
}
params_node.emplace_back(c_param_name, value);
params_node.emplace_back(c_param_name, parameter_value_from(c_param_value));
}
}

View File

@@ -367,8 +367,10 @@ PublisherBase::default_incompatible_qos_callback(
void
PublisherBase::default_incompatible_type_callback(
[[maybe_unused]] rclcpp::IncompatibleTypeInfo & event) const
rclcpp::IncompatibleTypeInfo & event) const
{
(void)event;
RCLCPP_WARN(
rclcpp::get_logger(rcl_node_get_logger_name(rcl_node_handle_.get())),
"Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());

View File

@@ -69,10 +69,8 @@ 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:
return KeepLast(rmw_qos.depth);
default:
throw std::invalid_argument(
"Invalid history policy enum value passed to QoSInitialization::from_rmw");
return KeepLast(rmw_qos.depth);
}
}
@@ -409,7 +407,7 @@ ParameterEventsQoS::ParameterEventsQoS(const QoSInitialization & qos_initializat
{}
RosoutQoS::RosoutQoS(const QoSInitialization & rosout_initialization)
: QoS(rosout_initialization, rmw_qos_profile_rosout_default)
: QoS(rosout_initialization, rcl_qos_profile_rosout_default)
{}
SystemDefaultsQoS::SystemDefaultsQoS(const QoSInitialization & qos_initialization)

View File

@@ -36,6 +36,7 @@ SerializationBase::SerializationBase(const rosidl_message_type_support_t * type_
void SerializationBase::serialize_message(
const void * ros_message, SerializedMessage * serialized_message) const
{
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
rcpputils::check_true(nullptr != ros_message, "ROS message is nullpointer.");
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
@@ -51,6 +52,7 @@ void SerializationBase::serialize_message(
void SerializationBase::deserialize_message(
const SerializedMessage * serialized_message, void * ros_message) const
{
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
rcpputils::check_true(
0u != serialized_message->capacity(),

View File

@@ -26,13 +26,8 @@ namespace rclcpp
inline void copy_rcl_message(const rcl_serialized_message_t & from, rcl_serialized_message_t & to)
{
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);
}
const auto ret = rmw_serialized_message_init(
&to, from.buffer_capacity, &from.allocator);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
@@ -83,6 +78,7 @@ 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_);
}
@@ -92,6 +88,7 @@ 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_);
}
@@ -101,14 +98,6 @@ 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());
}
@@ -119,14 +108,6 @@ 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());
}
@@ -141,7 +122,6 @@ SerializedMessage::~SerializedMessage()
RCLCPP_ERROR(
get_logger("rclcpp"),
"Failed to destroy serialized message: %s", rcl_get_error_string().str);
rcl_reset_error();
}
}
}

View File

@@ -381,8 +381,10 @@ SubscriptionBase::default_incompatible_qos_callback(
void
SubscriptionBase::default_incompatible_type_callback(
[[maybe_unused]] rclcpp::IncompatibleTypeInfo & event) const
rclcpp::IncompatibleTypeInfo & event) const
{
(void)event;
RCLCPP_WARN(
rclcpp::get_logger(rcl_node_get_logger_name(node_handle_.get())),
"Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());

View File

@@ -276,8 +276,13 @@ public:
on_set_parameters_callback_ = node_parameters_->add_on_set_parameters_callback(
std::bind(&TimeSource::NodeState::on_set_parameters, this, std::placeholders::_1));
post_set_parameters_callback_ = node_parameters_->add_post_set_parameters_callback(
std::bind(&TimeSource::NodeState::post_set_parameters, this, std::placeholders::_1));
// TODO(tfoote) use parameters interface not subscribe to events via topic ticketed #609
parameter_subscription_ = rclcpp::AsyncParametersClient::on_parameter_event(
node_topics_,
[this](std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event) {
this->on_parameter_event(event);
});
}
// Detach the attached node
@@ -291,11 +296,8 @@ public:
if (on_set_parameters_callback_) {
node_parameters_->remove_on_set_parameters_callback(on_set_parameters_callback_.get());
}
if (post_set_parameters_callback_) {
node_parameters_->remove_post_set_parameters_callback(post_set_parameters_callback_.get());
}
on_set_parameters_callback_.reset();
post_set_parameters_callback_.reset();
parameter_subscription_.reset();
node_base_.reset();
node_topics_.reset();
node_graph_.reset();
@@ -344,6 +346,7 @@ private:
std::mutex clock_sub_lock_;
rclcpp::CallbackGroup::SharedPtr clock_callback_group_;
rclcpp::executors::SingleThreadedExecutor::SharedPtr clock_executor_;
std::promise<void> cancel_clock_executor_promise_;
// The clock callback itself
void clock_cb(std::shared_ptr<const rosgraph_msgs::msg::Clock> msg)
@@ -389,10 +392,12 @@ private:
clock_executor_ =
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(exec_options);
if (!clock_executor_thread_.joinable()) {
cancel_clock_executor_promise_ = std::promise<void>{};
clock_executor_thread_ = std::thread(
[this]() {
auto future = cancel_clock_executor_promise_.get_future();
clock_executor_->add_callback_group(clock_callback_group_, node_base_);
clock_executor_->spin();
clock_executor_->spin_until_future_complete(future);
}
);
}
@@ -424,6 +429,7 @@ private:
{
std::lock_guard<std::mutex> guard(clock_sub_lock_);
if (clock_executor_thread_.joinable()) {
cancel_clock_executor_promise_.set_value();
clock_executor_->cancel();
clock_executor_thread_.join();
clock_executor_->remove_callback_group(clock_callback_group_);
@@ -434,9 +440,9 @@ private:
// On set Parameters callback handle
node_interfaces::OnSetParametersCallbackHandle::SharedPtr on_set_parameters_callback_{nullptr};
// Post set Parameters callback handle
node_interfaces::PostSetParametersCallbackHandle::SharedPtr
post_set_parameters_callback_{nullptr};
// Parameter Event subscription
using ParamSubscriptionT = rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>;
std::shared_ptr<ParamSubscriptionT> parameter_subscription_;
// Callback for parameter settings
rcl_interfaces::msg::SetParametersResult on_set_parameters(
@@ -459,27 +465,52 @@ private:
return result;
}
// Callback for post parameter updates
void post_set_parameters(const std::vector<rclcpp::Parameter> & parameters)
// Callback for parameter updates
void on_parameter_event(std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event)
{
// "use_sim_time" has been set, so just applys it to internal states
for (const auto & param : parameters) {
if (param.get_name() == "use_sim_time") {
if (param.as_bool()) {
parameter_state_ = SET_TRUE;
clocks_state_.enable_ros_time();
create_clock_sub();
} else {
parameter_state_ = SET_FALSE;
destroy_clock_sub();
clocks_state_.disable_ros_time();
}
std::lock_guard<std::mutex> guard(node_base_lock_);
if (node_base_ == nullptr) {
// Do nothing if node_base_ is nullptr because it means the TimeSource is now
// without an attached node
return;
}
// Filter out events on 'use_sim_time' parameter instances in other nodes.
if (event->node != node_base_->get_fully_qualified_name()) {
return;
}
// Filter for only 'use_sim_time' being added or changed.
rclcpp::ParameterEventsFilter filter(event, {"use_sim_time"},
{rclcpp::ParameterEventsFilter::EventType::NEW,
rclcpp::ParameterEventsFilter::EventType::CHANGED});
for (auto & it : filter.get_events()) {
if (it.second->value.type != ParameterType::PARAMETER_BOOL) {
RCLCPP_ERROR(logger_, "use_sim_time parameter cannot be set to anything but a bool");
continue;
}
if (it.second->value.bool_value) {
parameter_state_ = SET_TRUE;
clocks_state_.enable_ros_time();
create_clock_sub();
} else {
parameter_state_ = SET_FALSE;
destroy_clock_sub();
clocks_state_.disable_ros_time();
}
}
// Handle the case that use_sim_time was deleted.
rclcpp::ParameterEventsFilter deleted(event, {"use_sim_time"},
{rclcpp::ParameterEventsFilter::EventType::DELETED});
for (auto & it : deleted.get_events()) {
(void) it; // if there is a match it's already matched, don't bother reading it.
// If the parameter is deleted mark it as unset but don't change state.
parameter_state_ = UNSET;
}
}
// An enum to hold the parameter state
enum UseSimTimeParameterState {SET_TRUE, SET_FALSE};
enum UseSimTimeParameterState {UNSET, SET_TRUE, SET_FALSE};
UseSimTimeParameterState parameter_state_;
};

View File

@@ -35,6 +35,62 @@ namespace rclcpp
namespace
{
// Look for the library in the ament prefix paths.
std::string get_typesupport_library_path(
const std::string & package_name, const std::string & typesupport_identifier)
{
const char * dynamic_library_folder;
#ifdef _WIN32
dynamic_library_folder = "/bin/";
#elif __APPLE__
dynamic_library_folder = "/lib/";
#else
dynamic_library_folder = "/lib/";
#endif
std::string package_prefix;
try {
package_prefix = ament_index_cpp::get_package_prefix(package_name);
} catch (ament_index_cpp::PackageNotFoundError & e) {
throw std::runtime_error(e.what());
}
const std::string library_path = rcpputils::path_for_library(
package_prefix + dynamic_library_folder,
package_name + "__" + typesupport_identifier);
if (library_path.empty()) {
throw std::runtime_error(
"Typesupport library for " + package_name + " does not exist in '" + package_prefix +
"'.");
}
return library_path;
}
std::tuple<std::string, std::string, std::string>
extract_type_identifier(const std::string & full_type)
{
char type_separator = '/';
auto sep_position_back = full_type.find_last_of(type_separator);
auto sep_position_front = full_type.find_first_of(type_separator);
if (sep_position_back == std::string::npos ||
sep_position_back == 0 ||
sep_position_back == full_type.length() - 1)
{
throw std::runtime_error(
"Message type is not of the form package/type and cannot be processed");
}
std::string package_name = full_type.substr(0, sep_position_front);
std::string middle_module = "";
if (sep_position_back - sep_position_front > 0) {
middle_module =
full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
}
std::string type_name = full_type.substr(sep_position_back + 1);
return std::make_tuple(package_name, middle_module, type_name);
}
const void * get_typesupport_handle_impl(
const std::string & type,
const std::string & typesupport_identifier,
@@ -75,61 +131,6 @@ const void * get_typesupport_handle_impl(
} // anonymous namespace
std::tuple<std::string, std::string, std::string>
extract_type_identifier(const std::string & full_type)
{
char type_separator = '/';
auto sep_position_back = full_type.find_last_of(type_separator);
auto sep_position_front = full_type.find_first_of(type_separator);
if (sep_position_back == std::string::npos ||
sep_position_back == 0 ||
sep_position_back == full_type.length() - 1)
{
throw std::runtime_error(
"Message type is not of the form package/type and cannot be processed");
}
std::string package_name = full_type.substr(0, sep_position_front);
std::string middle_module = "";
if (sep_position_back - sep_position_front > 0) {
middle_module =
full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
}
std::string type_name = full_type.substr(sep_position_back + 1);
return std::make_tuple(package_name, middle_module, type_name);
}
std::string get_typesupport_library_path(
const std::string & package_name, const std::string & typesupport_identifier)
{
const char * dynamic_library_folder;
#ifdef _WIN32
dynamic_library_folder = "/bin/";
#elif __APPLE__
dynamic_library_folder = "/lib/";
#else
dynamic_library_folder = "/lib/";
#endif
std::string package_prefix;
try {
package_prefix = ament_index_cpp::get_package_prefix(package_name);
} catch (ament_index_cpp::PackageNotFoundError & e) {
throw std::runtime_error(e.what());
}
const std::string library_path = rcpputils::path_for_library(
package_prefix + dynamic_library_folder,
package_name + "__" + typesupport_identifier);
if (library_path.empty()) {
throw std::runtime_error(
"Typesupport library for " + package_name + " does not exist in '" + package_prefix +
"'.");
}
return library_path;
}
std::shared_ptr<rcpputils::SharedLibrary>
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier)
{
@@ -138,6 +139,14 @@ get_typesupport_library(const std::string & type, const std::string & typesuppor
return std::make_shared<rcpputils::SharedLibrary>(library_path);
}
const rosidl_message_type_support_t * get_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library)
{
return get_message_typesupport_handle(type, typesupport_identifier, library);
}
const rosidl_message_type_support_t * get_message_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
@@ -168,19 +177,4 @@ const rosidl_service_type_support_t * get_service_typesupport_handle(
));
}
const rosidl_action_type_support_t * get_action_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library)
{
static const std::string typesupport_name = "action";
static const std::string symbol_part_name = "__get_action_type_support_handle__";
static const std::string middle_module_additional = "action";
return static_cast<const rosidl_action_type_support_t *>(get_typesupport_handle_impl(
type, typesupport_identifier, typesupport_name, symbol_part_name,
middle_module_additional, library
));
}
} // namespace rclcpp

View File

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

View File

@@ -1 +1 @@
string data
string data

View File

@@ -28,6 +28,13 @@ ament_add_gtest(
if(TARGET test_allocator_deleter)
target_link_libraries(test_allocator_deleter ${PROJECT_NAME})
endif()
ament_add_gtest(test_type_description_conversions
dynamic_typesupport/test_type_description_conversions.cpp)
if(TARGET test_type_description_conversions)
target_link_libraries(test_type_description_conversions ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
endif()
ament_add_gtest(
test_exceptions
exceptions/test_exceptions.cpp)
@@ -62,11 +69,6 @@ ament_add_test_label(test_clock mimick)
if(TARGET test_clock)
target_link_libraries(test_clock ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_clock_conditional test_clock_conditional.cpp)
ament_add_test_label(test_clock_conditional mimick)
if(TARGET test_clock_conditional)
target_link_libraries(test_clock_conditional ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_copy_all_parameter_values test_copy_all_parameter_values.cpp)
if(TARGET test_copy_all_parameter_values)
target_link_libraries(test_copy_all_parameter_values ${PROJECT_NAME})
@@ -196,7 +198,7 @@ ament_add_gtest(test_node_interfaces__node_parameters
node_interfaces/test_node_parameters.cpp)
ament_add_test_label(test_node_interfaces__node_parameters mimick)
if(TARGET test_node_interfaces__node_parameters)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick rcpputils::rcpputils ${test_msgs_TARGETS})
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick rcpputils::rcpputils)
endif()
ament_add_gtest(test_node_interfaces__node_services
node_interfaces/test_node_services.cpp)
@@ -674,14 +676,6 @@ endif()
function(test_on_all_rmws)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
# If the rmw_implementation is rmw_zenoh_cpp, run the tests with multicast discovery enabled.
# Note: This is a temporary change that will be reverted before we branch into Kilted.
if(rmw_implementation STREQUAL "rmw_zenoh_cpp")
list(APPEND rmw_implementation_env_var
ZENOH_CONFIG_OVERRIDE=scouting/multicast/enabled=true
)
endif()
ament_add_gmock_test(test_qos_event
TEST_NAME test_qos_event${target_suffix}
ENV ${rmw_implementation_env_var}

View File

@@ -0,0 +1,118 @@
// Copyright 2025 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 "rclcpp/dynamic_typesupport/type_description_conversions.hpp"
#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
#include "type_description_interfaces/msg/individual_type_description.hpp"
#include "type_description_interfaces/msg/type_description.hpp"
#include "type_description_interfaces/msg/type_source.hpp"
using rclcpp::dynamic_typesupport::
convert_individual_type_description_msg_to_runtime;
using rclcpp::dynamic_typesupport::
convert_individual_type_description_runtime_to_msg;
using rclcpp::dynamic_typesupport::convert_type_description_msg_to_runtime;
using rclcpp::dynamic_typesupport::convert_type_description_runtime_to_msg;
using rclcpp::dynamic_typesupport::convert_type_source_sequence_msg_to_runtime;
using rclcpp::dynamic_typesupport::convert_type_source_sequence_runtime_to_msg;
TEST(TestTypeDescriptionConversions, individual_type_description_roundtrip)
{
rosidl_runtime_cpp::type_description::IndividualTypeDescription original;
original.type_name = "test_type_name";
original.fields.emplace_back();
original.fields.back().name = "field1";
original.fields.back().type.type_id = 1;
original.fields.emplace_back();
original.fields.back().name = "field2";
original.fields.back().type.type_id = 2;
type_description_interfaces::msg::IndividualTypeDescription msg =
convert_individual_type_description_runtime_to_msg(original);
rosidl_runtime_cpp::type_description::IndividualTypeDescription converted_back
=
convert_individual_type_description_msg_to_runtime(msg);
EXPECT_EQ(original.type_name, converted_back.type_name);
ASSERT_EQ(original.fields.size(), converted_back.fields.size());
for (size_t i = 0; i < original.fields.size(); ++i) {
EXPECT_EQ(original.fields[i].name, converted_back.fields[i].name);
EXPECT_EQ(original.fields[i].type, converted_back.fields[i].type);
}
}
TEST(TestTypeDescriptionConversions, type_description_roundtrip)
{
rosidl_runtime_cpp::type_description::TypeDescription original;
original.type_description.type_name = "main_type";
original.type_description.fields.emplace_back();
original.type_description.fields.back().name = "field1";
original.type_description.fields.back().type.type_id = 1;
original.type_description.fields.emplace_back();
original.type_description.fields.back().name = "field2";
original.type_description.fields.back().type.type_id = 2;
rosidl_runtime_cpp::type_description::IndividualTypeDescription ref1;
ref1.type_name = "ref_type_1";
ref1.fields.emplace_back();
ref1.fields.back().name = "ref_field1";
ref1.fields.back().type.type_id = 1;
rosidl_runtime_cpp::type_description::IndividualTypeDescription ref2;
ref2.type_name = "ref_type_2";
ref2.fields.emplace_back();
ref2.fields.back().name = "ref_field2";
ref2.fields.back().type.type_id = 2;
original.referenced_type_descriptions.push_back(ref1);
original.referenced_type_descriptions.push_back(ref2);
type_description_interfaces::msg::TypeDescription msg =
convert_type_description_runtime_to_msg(original);
rosidl_runtime_cpp::type_description::TypeDescription converted_back =
convert_type_description_msg_to_runtime(msg);
EXPECT_EQ(original.type_description.type_name,
converted_back.type_description.type_name);
ASSERT_EQ(original.referenced_type_descriptions.size(),
converted_back.referenced_type_descriptions.size());
for (size_t i = 0; i < original.referenced_type_descriptions.size(); ++i) {
EXPECT_EQ(original.referenced_type_descriptions[i].type_name,
converted_back.referenced_type_descriptions[i].type_name);
}
}
TEST(TestTypeSourceConversions, type_source_roundtrip)
{
rosidl_runtime_cpp::type_description::TypeSource original;
original.type_name = "test_type_name";
original.encoding = "test_encoding";
original.raw_file_contents = "test_contents";
type_description_interfaces::msg::TypeSource msg =
convert_type_source_sequence_runtime_to_msg(original);
rosidl_runtime_cpp::type_description::TypeSource converted_back =
convert_type_source_sequence_msg_to_runtime(msg);
EXPECT_EQ(original.type_name, converted_back.type_name);
EXPECT_EQ(original.encoding, converted_back.encoding);
EXPECT_EQ(original.raw_file_contents, converted_back.raw_file_contents);
}

View File

@@ -61,8 +61,9 @@ class ExecutorTypeNames
{
public:
template<typename T>
static std::string GetName([[maybe_unused]] int idx)
static std::string GetName(int idx)
{
(void)idx;
if (std::is_same<T, rclcpp::executors::SingleThreadedExecutor>()) {
return "SingleThreadedExecutor";
}

View File

@@ -48,8 +48,9 @@ TEST_F(TestEventsExecutor, run_pub_sub)
bool msg_received = false;
auto subscription = node->create_subscription<test_msgs::msg::Empty>(
"topic", rclcpp::SensorDataQoS(),
[&msg_received]([[maybe_unused]] test_msgs::msg::Empty::ConstSharedPtr msg)
[&msg_received](test_msgs::msg::Empty::ConstSharedPtr msg)
{
(void)msg;
msg_received = true;
});
@@ -114,8 +115,8 @@ TEST_F(TestEventsExecutor, run_clients_servers)
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
client->async_send_request(
request,
[&response_received]([[maybe_unused]] rclcpp::Client<test_msgs::srv::Empty>::SharedFuture
result_future){
[&response_received](rclcpp::Client<test_msgs::srv::Empty>::SharedFuture result_future) {
(void)result_future;
response_received = true;
});
@@ -496,122 +497,3 @@ TEST_F(TestEventsExecutor, test_default_incompatible_qos_callbacks)
rcutils_logging_set_output_handler(original_output_handler);
}
class TestWaitableWithTimer : public rclcpp::Waitable
{
static constexpr int TimerCallbackType = 0;
public:
explicit TestWaitableWithTimer(const rclcpp::Context::SharedPtr & context)
{
auto timer_callback = [this] () {
timer_ready = true;
if (ready_callback) {
// inform executor that the waitable is ready to process a timer event
ready_callback(1, TimerCallbackType);
}
};
timer =
std::make_shared<rclcpp::WallTimer<decltype (timer_callback)>>(std::chrono::milliseconds(10),
std::move(timer_callback), context);
}
void
add_to_wait_set(rcl_wait_set_t & /*wait_set*/) override {}
bool
is_ready(const rcl_wait_set_t & /*wait_set*/) override
{
return false;
}
std::shared_ptr<void>
take_data() override
{
return std::shared_ptr<void>(nullptr);
}
std::shared_ptr<void>
take_data_by_entity_id(size_t id) override
{
if (id != TimerCallbackType) {
throw std::runtime_error("Internal error, got wrong ID for take data");
}
return nullptr;
}
void
execute(const std::shared_ptr<void> &) override
{
if (timer_ready) {
timer_triggered_waitable_and_waitable_was_executed = true;
}
}
void
set_on_ready_callback(std::function<void(size_t, int)> callback) override
{
ready_callback = callback;
}
void
clear_on_ready_callback() override
{
ready_callback = std::function<void(size_t, int)>();
}
size_t
get_number_of_ready_guard_conditions() override
{
return 0;
}
std::vector<std::shared_ptr<rclcpp::TimerBase>> get_timers() const override
{
return {timer};
}
bool timerTriggeredWaitable() const
{
return timer_triggered_waitable_and_waitable_was_executed;
}
private:
std::atomic_bool timer_triggered_waitable_and_waitable_was_executed = false;
std::atomic_bool timer_ready = false;
rclcpp::TimerBase::SharedPtr timer;
std::function<void(size_t, int)> ready_callback;
};
TEST_F(TestEventsExecutor, waitable_with_timer)
{
auto node = std::make_shared<rclcpp::Node>("node");
auto waitable =
std::make_shared<TestWaitableWithTimer>(rclcpp::contexts::get_global_default_context());
EventsExecutor executor;
executor.add_node(node);
node->get_node_waitables_interface()->add_waitable(waitable,
node->get_node_base_interface()->get_default_callback_group());
std::thread spinner([&executor]() {executor.spin();});
size_t cnt = 0;
while (!waitable->timerTriggeredWaitable()) {
std::this_thread::sleep_for(10ms);
cnt++;
// This should terminate after ~20 ms, so a timeout of 500ms should be plenty
EXPECT_LT(cnt, 51);
if (cnt > 50) {
// timeout case
break;
}
}
executor.cancel();
spinner.join();
EXPECT_TRUE(waitable->timerTriggeredWaitable());
}

View File

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

View File

@@ -76,7 +76,8 @@ TEST_F(TestExecutorNotifyWaitable, wait) {
std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(on_execute_callback);
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto notify_guard_condition = std::make_shared<rclcpp::GuardCondition>();
auto notify_guard_condition =
node->get_node_base_interface()->get_shared_notify_guard_condition();
EXPECT_NO_THROW(waitable->add_guard_condition(notify_guard_condition));
auto default_cbg = node->get_node_base_interface()->get_default_callback_group();
@@ -85,15 +86,12 @@ TEST_F(TestExecutorNotifyWaitable, wait) {
auto waitables = node->get_node_waitables_interface();
waitables->add_waitable(std::static_pointer_cast<rclcpp::Waitable>(waitable), default_cbg);
// notify the guard condition, this should trigger the on_execute_callback
notify_guard_condition->trigger();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
executor.spin_all(std::chrono::seconds(1));
EXPECT_EQ(1u, on_execute_calls);
// no further trigger, therefore no further callback
// on_execute_callback doesn't change if the topology doesn't change
executor.spin_all(std::chrono::seconds(1));
EXPECT_EQ(1u, on_execute_calls);
}

View File

@@ -749,7 +749,8 @@ TYPED_TEST(TestExecutors, notifyTwiceWhileSpinning)
this->publisher->publish(test_msgs::msg::Empty());
start = std::chrono::steady_clock::now();
while (
(sub1_msg_count == 1 || sub2_msg_count == 0) &&
sub1_msg_count == 1 &&
sub2_msg_count == 0 &&
(std::chrono::steady_clock::now() - start) < 10s)
{
std::this_thread::sleep_for(1ms);
@@ -889,276 +890,3 @@ TYPED_TEST(TestExecutors, testRaceDropCallbackGroupFromSecondThread)
executor.cancel();
executor_thread.join();
}
TYPED_TEST(TestExecutors, dropSomeTimer)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
bool timer1_works = false;
bool timer2_works = false;
auto timer1 = node->create_timer(std::chrono::milliseconds(10), [&timer1_works]() {
timer1_works = true;
});
auto timer2 = node->create_timer(std::chrono::milliseconds(10), [&timer2_works]() {
timer2_works = true;
});
executor.add_node(node);
// first let's make sure that both timers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer1_works || !timer2_works) {
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete timer 2. Note, the executor uses an unordered map internally, to order
// the entities added to the rcl waitset therefore the order is kind of undefined,
// and this test may be flaky. In case it triggers, something is most likely
// really broken.
timer2.reset();
timer1_works = false;
timer2_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer1_works && !timer2_works) {
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(timer1_works || timer2_works);
}
TYPED_TEST(TestExecutors, dropSomeNodeWithTimer)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node1 = std::make_shared<rclcpp::Node>("test_node_1");
auto node2 = std::make_shared<rclcpp::Node>("test_node_2");
bool timer1_works = false;
bool timer2_works = false;
auto timer1 = node1->create_timer(std::chrono::milliseconds(10), [&timer1_works]() {
timer1_works = true;
});
auto timer2 = node2->create_timer(std::chrono::milliseconds(10), [&timer2_works]() {
timer2_works = true;
});
executor.add_node(node1);
executor.add_node(node2);
// first let's make sure that both timers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer1_works || !timer2_works) {
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete node 1.
node1 = nullptr;
timer2_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer2_works) {
// let the executor pick up the node and the timer
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(timer2_works);
}
TYPED_TEST(TestExecutors, dropSomeSubscription)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
bool sub1_works = false;
bool sub2_works = false;
auto sub1 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub1_works](const test_msgs::msg::Empty &) {
sub1_works = true;
});
auto sub2 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub2_works](const test_msgs::msg::Empty &) {
sub2_works = true;
});
auto pub = node->create_publisher<test_msgs::msg::Empty>("/test_drop", 10);
executor.add_node(node);
// first let's make sure that both timers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works || !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete subscription 2. Note, the executor uses an unordered map internally, to order
// the entities added to the rcl waitset therefore the order is kind of undefined,
// and this test may be flaky. In case it triggers, something is most likely
// really broken.
sub2.reset();
sub1_works = false;
sub2_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works && !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(sub1_works || sub2_works);
}
TYPED_TEST(TestExecutors, dropSomeNodesWithSubscription)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
auto node1 = std::make_shared<rclcpp::Node>("test_node_1");
auto node2 = std::make_shared<rclcpp::Node>("test_node_2");
bool sub1_works = false;
bool sub2_works = false;
auto sub1 = node1->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub1_works](const test_msgs::msg::Empty &) {
sub1_works = true;
});
auto sub2 = node2->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub2_works](const test_msgs::msg::Empty &) {
sub2_works = true;
});
auto pub = node->create_publisher<test_msgs::msg::Empty>("/test_drop", 10);
executor.add_node(node);
executor.add_node(node1);
executor.add_node(node2);
// first let's make sure that both subscribers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works || !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete node 2.
node2 = nullptr;
sub1_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(sub1_works);
}
TYPED_TEST(TestExecutors, dropSubscriptionDuringCallback)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
bool sub1_works = false;
bool sub2_works = false;
auto cbg = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive, true);
rclcpp::SubscriptionOptions sub_ops;
sub_ops.callback_group = cbg;
rclcpp::SubscriptionBase::SharedPtr sub1;
rclcpp::SubscriptionBase::SharedPtr sub2;
// Note, the executor uses an unordered map internally, to order
// the entities added to the rcl waitset therefore the order of the subscriptions
// is kind of undefined. Therefore each sub deletes the other one.
sub1 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub1_works, &sub2](const test_msgs::msg::Empty &) {
sub1_works = true;
// delete the other subscriber
sub2.reset();
}, sub_ops);
sub2 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub2_works, &sub1](const test_msgs::msg::Empty &) {
sub2_works = true;
// delete the other subscriber
sub1.reset();
}, sub_ops);
auto pub = node->create_publisher<test_msgs::msg::Empty>("/test_drop", 10);
// wait for both subs to be connected
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(1500);
while ((sub1->get_publisher_count() == 0) || (sub2->get_publisher_count() == 0)) {
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
executor.add_node(node);
// publish some messages, until one subscriber fired. As both subscribers are
// connected to the same topic, they should fire in the same wait.
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while (!sub1_works && !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// only one subscriber must have worked, as the other
// one was deleted during the callback
ASSERT_TRUE(!sub1_works || !sub2_works);
}

View File

@@ -267,15 +267,12 @@ public:
void TearDown()
{
executor.cancel();
node.reset();
// Clean up thread object
if (standalone_thread.joinable()) {
standalone_thread.join();
}
node.reset();
sim_clock_node.reset();
}
std::shared_ptr<TimerNode> node;
@@ -313,6 +310,7 @@ TYPED_TEST(TestTimerCancelBehavior, testTimer1CancelledWithExecutorSpin) {
this->sim_clock_node->sleep_for(50ms);
this->node->CancelTimer1();
this->sim_clock_node->sleep_for(150ms);
this->executor.cancel();
int t1_runs = this->node->GetTimer1Cnt();
int t2_runs = this->node->GetTimer2Cnt();
@@ -330,6 +328,7 @@ TYPED_TEST(TestTimerCancelBehavior, testTimer2CancelledWithExecutorSpin) {
this->sim_clock_node->sleep_for(50ms);
this->node->CancelTimer2();
this->sim_clock_node->sleep_for(150ms);
this->executor.cancel();
int t1_runs = this->node->GetTimer1Cnt();
int t2_runs = this->node->GetTimer2Cnt();
@@ -356,6 +355,8 @@ TYPED_TEST(TestTimerCancelBehavior, testHeadTimerCancelThenResetBehavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T1 should have been restarted, and execute about 15 additional times.
// Check 10 greater than initial, to account for some timing jitter.
EXPECT_LT(t1_runs_initial + 50, t1_runs_final);
@@ -383,6 +384,8 @@ TYPED_TEST(TestTimerCancelBehavior, testBackTimerCancelThenResetBehavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T2 should have been restarted, and execute about 15 additional times.
// Check 10 greater than initial, to account for some timing jitter.
EXPECT_LT(t2_runs_initial + 50, t2_runs_final);
@@ -416,6 +419,8 @@ TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT1Behavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T1 and T2 should have the same initial count.
EXPECT_LE(std::abs(t1_runs_initial - t2_runs_initial), 1);
@@ -453,6 +458,8 @@ TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT2Behavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T1 and T2 should have the same initial count.
EXPECT_LE(std::abs(t1_runs_initial - t2_runs_initial), 1);

View File

@@ -99,6 +99,14 @@ TYPED_TEST(TestExecutorsWarmup, spin_all_doesnt_require_warmup_with_cbgroup)
{
using ExecutorType = TypeParam;
// TODO(alsora): Enable when https://github.com/ros2/rclcpp/pull/2595 gets merged
if (
std::is_same<ExecutorType, rclcpp::executors::SingleThreadedExecutor>() ||
std::is_same<ExecutorType, rclcpp::executors::MultiThreadedExecutor>())
{
GTEST_SKIP();
}
ExecutorType executor;
// Enable intra-process to guarantee deterministic and synchronous delivery of the message / event

View File

@@ -13,7 +13,6 @@
// limitations under the License.
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <thread>
@@ -65,8 +64,9 @@ TestWaitable::take_data()
}
std::shared_ptr<void>
TestWaitable::take_data_by_entity_id([[maybe_unused]] size_t id)
TestWaitable::take_data_by_entity_id(size_t id)
{
(void) id;
return nullptr;
}

View File

@@ -18,7 +18,6 @@
#include <atomic>
#include <functional>
#include <memory>
#include <vector>
#include "rclcpp/waitable.hpp"
#include "rclcpp/guard_condition.hpp"
@@ -65,11 +64,6 @@ public:
size_t
get_is_ready_call_count() const;
std::vector<std::shared_ptr<rclcpp::TimerBase>> get_timers() const override
{
return {};
}
private:
std::atomic<size_t> trigger_count_ = 0;
std::atomic<size_t> is_ready_count_ = 0;

View File

@@ -29,8 +29,6 @@
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_parameters.hpp"
#include "test_msgs/msg/empty.hpp"
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
@@ -128,7 +126,7 @@ TEST_F(TestNodeParameters, list_parameters)
list_result5.names.end());
}
TEST_F(TestNodeParameters, parameter_overrides_with_value)
TEST_F(TestNodeParameters, parameter_overrides)
{
rclcpp::NodeOptions node_options;
node_options.automatically_declare_parameters_from_overrides(true);
@@ -146,24 +144,6 @@ TEST_F(TestNodeParameters, parameter_overrides_with_value)
EXPECT_EQ(2u, parameter_overrides.size());
}
TEST_F(TestNodeParameters, parameter_overrides_with_parameter)
{
rclcpp::NodeOptions node_options;
node_options.automatically_declare_parameters_from_overrides(true);
node_options.append_parameter_override(rclcpp::Parameter("param1", true));
node_options.append_parameter_override(rclcpp::Parameter("param2", 42));
std::shared_ptr<rclcpp::Node> node2 = std::make_shared<rclcpp::Node>("node2", "ns", node_options);
auto * node_parameters_interface =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node2->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters_interface);
const auto & parameter_overrides = node_parameters_interface->get_parameter_overrides();
EXPECT_EQ(2u, parameter_overrides.size());
}
TEST_F(TestNodeParameters, set_parameters) {
rclcpp::NodeOptions node_options;
node_options.allow_undeclared_parameters(true);
@@ -349,89 +329,6 @@ TEST_F(TestNodeParameters, add_remove_post_set_parameters_callback) {
std::runtime_error("Post set parameter callback doesn't exist"));
}
TEST_F(TestNodeParameters, set_param_recursive_in_post_set_parameters_callback) {
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription_;
rclcpp::Publisher<test_msgs::msg::Empty>::SharedPtr publisher_;
rcl_interfaces::msg::ParameterDescriptor param_descriptor;
param_descriptor.name = "create_entities";
param_descriptor.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
param_descriptor.read_only = false;
bool result = node_parameters->declare_parameter(
"create_entities", rclcpp::ParameterValue(false), param_descriptor, false).get<bool>();
EXPECT_EQ(result, false);
// Register a callback to create/delete publisher and subscription with
// QoS override parameter options. This will call declare_parameter recursively
// during this callback.
auto sub_callback = [](test_msgs::msg::Empty::ConstSharedPtr) {};
auto callback = [&](const std::vector<rclcpp::Parameter> & parameters) {
for (const auto & parameter : parameters) {
if (parameter.get_name() == "create_entities" &&
parameter.get_type() == rclcpp::ParameterType::PARAMETER_BOOL)
{
if (parameter.as_bool()) {
ASSERT_EQ(subscription_, nullptr);
rclcpp::SubscriptionOptions sub_options;
// This will declare the QoS override parameters in this callback.
sub_options.qos_overriding_options =
rclcpp::QosOverridingOptions::with_default_policies();
subscription_ = node->create_subscription<test_msgs::msg::Empty>(
"empty",
rclcpp::QoS(10),
sub_callback,
sub_options);
ASSERT_NE(subscription_, nullptr);
ASSERT_EQ(publisher_, nullptr);
rclcpp::PublisherOptions pub_options;
// This will declare the QoS override parameters in this callback.
pub_options.qos_overriding_options =
rclcpp::QosOverridingOptions::with_default_policies();
publisher_ = node->create_publisher<test_msgs::msg::Empty>(
"empty",
rclcpp::QoS(10),
pub_options);
ASSERT_NE(publisher_, nullptr);
} else {
ASSERT_NE(subscription_, nullptr);
subscription_.reset();
ASSERT_EQ(subscription_, nullptr);
ASSERT_NE(publisher_, nullptr);
publisher_.reset();
ASSERT_EQ(publisher_, nullptr);
}
}
}
};
auto handle = node_parameters->add_post_set_parameters_callback(callback);
ASSERT_NE(handle, nullptr);
EXPECT_TRUE(node_parameters->has_parameter("create_entities"));
EXPECT_EQ(node_parameters->get_parameter("create_entities").get_value<bool>(), false);
// This will call the registered callback, that will create endpoints with
// declaring the QoS override parameters recursively.
auto results = node_parameters->set_parameters({rclcpp::Parameter("create_entities", true)});
EXPECT_TRUE(!results.empty() && results[0].successful);
EXPECT_TRUE(node_parameters->has_parameter("create_entities"));
EXPECT_EQ(node_parameters->get_parameter("create_entities").get_value<bool>(), true);
// Destroy publisher and subscription endpoints.
results = node_parameters->set_parameters({rclcpp::Parameter("create_entities", false)});
EXPECT_TRUE(!results.empty() && results[0].successful);
EXPECT_TRUE(node_parameters->has_parameter("create_entities"));
EXPECT_EQ(node_parameters->get_parameter("create_entities").get_value<bool>(), false);
// Make sure recreation can also work without any exception.
results = node_parameters->set_parameters({rclcpp::Parameter("create_entities", true)});
EXPECT_TRUE(!results.empty() && results[0].successful);
EXPECT_NO_THROW(node_parameters->remove_post_set_parameters_callback(handle.get()));
}
TEST_F(TestNodeParameters, wildcard_with_namespace)
{
rclcpp::NodeOptions opts;

View File

@@ -37,38 +37,6 @@ TEST_F(TestNodeTypeDescriptions, interface_created)
ASSERT_NE(nullptr, node.get_node_type_descriptions_interface());
}
TEST_F(TestNodeTypeDescriptions, automatically_declare_parameters_from_overrides)
{
rclcpp::NodeOptions node_options;
node_options.automatically_declare_parameters_from_overrides(true);
node_options.append_parameter_override("start_type_description_service", false);
ASSERT_NO_THROW(
{
auto node = std::make_shared<rclcpp::Node>("node", "ns", node_options);
(void) node;
});
}
TEST_F(TestNodeTypeDescriptions, bad_parameter_type)
{
rclcpp::NodeOptions node_options;
node_options.append_parameter_override("start_type_description_service", "unexpected_type");
ASSERT_THROW(
{
node_options.automatically_declare_parameters_from_overrides(false);
auto node = std::make_shared<rclcpp::Node>("node", "ns", node_options);
(void) node;
}, rclcpp::exceptions::InvalidParameterTypeException);
ASSERT_THROW(
{
node_options.automatically_declare_parameters_from_overrides(true);
auto node = std::make_shared<rclcpp::Node>("node", "ns", node_options);
(void) node;
}, rclcpp::exceptions::InvalidParameterTypeException);
}
TEST_F(TestNodeTypeDescriptions, disabled_no_service)
{
rclcpp::NodeOptions node_options;

View File

@@ -38,11 +38,6 @@ public:
void clear_on_ready_callback() override {}
std::shared_ptr<void> take_data_by_entity_id(size_t) override {return nullptr;}
std::vector<std::shared_ptr<rclcpp::TimerBase>> get_timers() const override
{
return {};
}
};
class TestNodeWaitables : public ::testing::Test

View File

@@ -58,11 +58,6 @@ public:
void clear_on_ready_callback() override {}
std::shared_ptr<void> take_data_by_entity_id(size_t) override {return nullptr;}
std::vector<std::shared_ptr<rclcpp::TimerBase>> get_timers() const override
{
return {};
}
};
struct RclWaitSetSizes
@@ -540,8 +535,8 @@ TEST_F(TestAllocatorMemoryStrategy, add_handles_to_wait_set_bad_arguments) {
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
EXPECT_FALSE(allocator_memory_strategy()->add_handles_to_wait_set(nullptr));
// The error message is collected and already reset.
EXPECT_FALSE(rcl_error_is_set());
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
TEST_F(TestAllocatorMemoryStrategy, add_handles_to_wait_set_subscription) {

View File

@@ -184,8 +184,9 @@ class ClientTypeNames
{
public:
template<typename T>
static std::string GetName([[maybe_unused]] int idx)
static std::string GetName(int idx)
{
(void)idx;
if (std::is_same_v<T, rclcpp::Client<test_msgs::srv::Empty>>) {
return "Client";
}

View File

@@ -15,7 +15,6 @@
#include <gtest/gtest.h>
#include <chrono>
#include <rcpputils/compile_warnings.hpp>
#include "rcl/error_handling.h"
#include "rcl/time.h"
@@ -42,10 +41,9 @@ public:
clock->sleep_until(clock->now() + std::chrono::seconds(3));
thread_finished = true;
});
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
@@ -74,10 +72,8 @@ public:
// make sure the thread is already sleeping before we send the cancel
std::this_thread::sleep_for(std::chrono::milliseconds(100));
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
@@ -163,10 +159,8 @@ TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_FALSE(thread_finished);
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
@@ -184,10 +178,7 @@ TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
std::vector<std::atomic_bool> thread_finished(10);
for (std::atomic_bool & finished : thread_finished) {
finished = false;
}
std::vector<bool> thread_finished(10, false);
std::vector<std::thread> threads;
@@ -205,7 +196,7 @@ TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
// wait a bit so all threads can execute the sleep_until
std::this_thread::sleep_for(std::chrono::milliseconds(500));
for (const std::atomic_bool & finished : thread_finished) {
for (const bool & finished : thread_finished) {
EXPECT_FALSE(finished);
}
@@ -216,7 +207,7 @@ TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
bool threads_finished = false;
while (!threads_finished && start_time + std::chrono::seconds(1) > cur_time) {
threads_finished = true;
for (const std::atomic_bool & finished : thread_finished) {
for (const bool finished : thread_finished) {
if (!finished) {
threads_finished = false;
}
@@ -226,7 +217,7 @@ TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
cur_time = std::chrono::steady_clock::now();
}
for (const std::atomic_bool & finished : thread_finished) {
for (const bool finished : thread_finished) {
EXPECT_TRUE(finished);
}

View File

@@ -1,246 +0,0 @@
// Copyright 2025 Cellumation GmbH
//
// 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 "rcl/error_handling.h"
#include "rcl/time.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/time_source.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
using namespace std::chrono_literals;
class TestClockWakeup : public ::testing::TestWithParam<rcl_clock_type_e>
{
public:
void test_wakeup_before_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
// make sure the thread starts sleeping late
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::unique_lock lk(cond.mutex());
cond.wait_until(lk, clock->now() + std::chrono::seconds(3),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
{
std::lock_guard lk(cond.mutex());
// stop sleeping after next notification
stopSleeping = true;
}
// notify the conditional, to recheck it pred
cond.notify_one();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
void test_wakeup_after_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
std::unique_lock lk(cond.mutex());
cond.wait_until(lk, clock->now() + std::chrono::seconds(3),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
// make sure the thread is already sleeping before we send the cancel
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
std::lock_guard lk(cond.mutex());
// stop sleeping after next notification
stopSleeping = true;
}
// notify the conditional, to recheck it pred
cond.notify_one();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("my_node");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
};
INSTANTIATE_TEST_SUITE_P(
ClockConditionalVariable,
TestClockWakeup,
::testing::Values(
RCL_SYSTEM_TIME, RCL_ROS_TIME, RCL_STEADY_TIME
));
TEST_P(TestClockWakeup, wakeup_sleep) {
auto clock = std::make_shared<rclcpp::Clock>(GetParam());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, wakeup_sleep_ros_time_active) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
EXPECT_FALSE(clock->ros_time_is_active());
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
std::unique_lock lk(cond.mutex());
// only sleep for an short period
cond.wait_until(lk, clock->now() + std::chrono::milliseconds(10),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
// make sure, that the sim time clock does not wakeup, as no clock is provided
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_FALSE(thread_finished);
{
std::lock_guard lk(cond.mutex());
// stop sleeping after next notification
stopSleeping = true;
}
// notify the conditional, to recheck it pred
cond.notify_one();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
TEST_F(TestClockWakeup, wakeup_on_ros_shutdown) {
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
std::unique_lock lk(cond.mutex());
// only sleep for an short period
cond.wait_until(lk, clock->now() + std::chrono::seconds(10),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
// wait a bit to be sure the thread is sleeping
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_FALSE(thread_finished);
rclcpp::shutdown();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
EXPECT_TRUE(thread_finished);
wait_thread.join();
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}

View File

@@ -19,16 +19,11 @@
#include <stdexcept>
#include <string>
#include "rcl_interfaces/msg/parameter_event.hpp"
#include "rclcpp/executor.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
#include "test_msgs/msg/empty.hpp"
#include "../mocking_utils/patch.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
@@ -336,17 +331,8 @@ TEST_F(TestExecutor, spin_all_fail_wait_set_clear) {
node->create_wall_timer(std::chrono::milliseconds(1), [&]() {});
dummy.add_node(node);
auto callback = [](test_msgs::msg::Empty::ConstSharedPtr) {};
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
auto node_topics = node->get_node_topics_interface();
subscription =
rclcpp::create_subscription<test_msgs::msg::Empty>(
node_topics, "test", rclcpp::QoS(10), std::move(callback));
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_clear, RCL_RET_ERROR);
dummy.spin_all(std::chrono::milliseconds(1));
// second spin_all triggers rcl_wait_set_clear that should be called
// whenever a waitset gets rebuild and it was not changed in size.
RCLCPP_EXPECT_THROW_EQ(
dummy.spin_all(std::chrono::milliseconds(1)),
std::runtime_error("Couldn't clear the wait set: error not set"));
@@ -368,14 +354,8 @@ TEST_F(TestExecutor, spin_some_fail_wait_set_resize) {
TEST_F(TestExecutor, spin_some_fail_add_handles_to_wait_set) {
DummyExecutor dummy;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
// create subscription explicitly, because we do not create subscription
// on /parameter_events for 'use_sim_time' parameter anymore.
auto callback = [](test_msgs::msg::Empty::ConstSharedPtr) {};
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
subscription =
node->create_subscription<test_msgs::msg::Empty>(
"test", rclcpp::QoS(10), std::move(callback));
auto timer =
node->create_wall_timer(std::chrono::milliseconds(1), [&]() {});
dummy.add_node(node);
auto mock = mocking_utils::patch_and_return(

View File

@@ -74,23 +74,29 @@ struct FunctionObjectOneIntOneChar
struct ObjectMember
{
int callback_one_bool([[maybe_unused]] bool a)
int callback_one_bool(bool a)
{
(void)a;
return 7;
}
int callback_one_bool_const([[maybe_unused]] bool a) const
int callback_one_bool_const(bool a) const
{
(void)a;
return 7;
}
int callback_two_bools([[maybe_unused]] bool a, [[maybe_unused]] bool b)
int callback_two_bools(bool a, bool b)
{
(void)a;
(void)b;
return 8;
}
int callback_one_bool_one_float([[maybe_unused]] bool a, [[maybe_unused]] float b)
int callback_one_bool_one_float(bool a, float b)
{
(void)a;
(void)b;
return 9;
}
};
@@ -206,15 +212,20 @@ TEST(TestFunctionTraits, arity) {
return 0;
};
auto lambda_one_int = []([[maybe_unused]] int one) {
auto lambda_one_int = [](int one) {
(void)one;
return 1;
};
auto lambda_two_ints = []([[maybe_unused]] int one, [[maybe_unused]] int two) {
auto lambda_two_ints = [](int one, int two) {
(void)one;
(void)two;
return 2;
};
auto lambda_one_int_one_char = []([[maybe_unused]] int one, [[maybe_unused]] char two) {
auto lambda_one_int_one_char = [](int one, char two) {
(void)one;
(void)two;
return 3;
};
@@ -292,15 +303,20 @@ TEST(TestFunctionTraits, argument_types) {
>::value, "Functor accepts a char as second argument");
// Test lambdas
auto lambda_one_int = []([[maybe_unused]] int one) {
auto lambda_one_int = [](int one) {
(void)one;
return 1;
};
auto lambda_two_ints = []([[maybe_unused]] int one, [[maybe_unused]] int two) {
auto lambda_two_ints = [](int one, int two) {
(void)one;
(void)two;
return 2;
};
auto lambda_one_int_one_char = []([[maybe_unused]] int one, [[maybe_unused]] char two) {
auto lambda_one_int_one_char = [](int one, char two) {
(void)one;
(void)two;
return 3;
};
@@ -517,17 +533,22 @@ TEST(TestFunctionTraits, check_arguments) {
"Functor accepts an int and a char as arguments");
// Test lambdas
auto lambda_one_int = []([[maybe_unused]] int one) {
auto lambda_one_int = [](int one) {
(void)one;
return 1;
};
(void)lambda_one_int; // to quiet clang
auto lambda_two_ints = []([[maybe_unused]] int one, [[maybe_unused]] int two) {
auto lambda_two_ints = [](int one, int two) {
(void)one;
(void)two;
return 2;
};
(void)lambda_two_ints; // to quiet clang
auto lambda_one_int_one_char = []([[maybe_unused]] int one, [[maybe_unused]] char two) {
auto lambda_one_int_one_char = [](int one, char two) {
(void)one;
(void)two;
return 3;
};
(void)lambda_one_int_one_char; // to quiet clang
@@ -582,11 +603,14 @@ TEST(TestFunctionTraits, check_arguments) {
Tests that same_arguments work.
*/
TEST(TestFunctionTraits, same_arguments) {
auto lambda_one_int = []([[maybe_unused]] int one) {
auto lambda_one_int = [](int one) {
(void)one;
return 1;
};
auto lambda_two_ints = []([[maybe_unused]] int one, [[maybe_unused]] int two) {
auto lambda_two_ints = [](int one, int two) {
(void)one;
(void)two;
return 1;
};
@@ -634,7 +658,8 @@ TEST(TestFunctionTraits, return_type) {
"Functor return ints");
// Test lambda
auto lambda_one_int_return_double = []([[maybe_unused]] int one) -> double {
auto lambda_one_int_return_double = [](int one) -> double {
(void)one;
return 1.0;
};
@@ -672,15 +697,20 @@ TEST(TestFunctionTraits, sfinae_match) {
return 0;
};
auto lambda_one_int = []([[maybe_unused]] int one) {
auto lambda_one_int = [](int one) {
(void)one;
return 1;
};
auto lambda_two_ints = []([[maybe_unused]] int one, [[maybe_unused]] int two) {
auto lambda_two_ints = [](int one, int two) {
(void)one;
(void)two;
return 2;
};
auto lambda_one_int_one_char = []([[maybe_unused]] int one, [[maybe_unused]] char two) {
auto lambda_one_int_one_char = [](int one, char two) {
(void)one;
(void)two;
return 3;
};

View File

@@ -221,7 +221,7 @@ TEST_F(TestGenericClient, wait_for_service) {
TEST_F(TestGenericClientSub, construction_and_destruction) {
{
auto client = subnode->create_generic_client("test_service", "test_msgs/srv/Empty");
EXPECT_STREQ(client->get_service_name(), "/ns/sub_ns/test_service");
EXPECT_STREQ(client->get_service_name(), "/ns/test_service");
}
{

View File

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

View File

@@ -193,14 +193,16 @@ public:
}
bool
operator==([[maybe_unused]] const rmw_gid_t & gid) const
operator==(const rmw_gid_t & gid) const
{
(void)gid;
return false;
}
bool
operator==([[maybe_unused]] const rmw_gid_t * gid) const
operator==(const rmw_gid_t * gid) const
{
(void)gid;
return false;
}
@@ -258,12 +260,12 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
explicit SubscriptionIntraProcessBase(
[[maybe_unused]] rclcpp::Context::SharedPtr context,
rclcpp::Context::SharedPtr context,
const std::string & topic,
const rclcpp::QoS & qos)
: topic_name(topic), qos_profile(qos)
{
// This function is intentionally left empty.
(void)context;
}
virtual ~SubscriptionIntraProcessBase() {}

View File

@@ -61,8 +61,9 @@ public:
return static_cast<T *>(std::malloc(size * sizeof(T)));
}
void deallocate(T * ptr, [[maybe_unused]] size_t size)
void deallocate(T * ptr, size_t size)
{
(void)size;
if (!ptr) {
return;
}

View File

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

View File

@@ -253,19 +253,9 @@ bool log_function_const_ref(const rclcpp::Logger & logger)
return true;
}
class DerivedLogger : public rclcpp::Logger
{
public:
explicit DerivedLogger(const rclcpp::Logger & logger)
: rclcpp::Logger(logger) {}
};
TEST_F(TestLoggingMacros, test_log_from_node) {
auto logger = rclcpp::get_logger("test_logging_logger");
EXPECT_TRUE(log_function(logger));
EXPECT_TRUE(log_function_const(logger));
EXPECT_TRUE(log_function_const_ref(logger));
DerivedLogger derived_logger(logger);
RCLCPP_INFO(derived_logger, "successful log from derived logger");
}

View File

@@ -45,11 +45,6 @@ public:
void clear_on_ready_callback() override {}
std::shared_ptr<void> take_data_by_entity_id(size_t) override {return nullptr;}
std::vector<std::shared_ptr<rclcpp::TimerBase>> get_timers() const override
{
return {};
}
};
class TestMemoryStrategy : public ::testing::Test

View File

@@ -306,39 +306,6 @@ TEST_F(TestNode, subnode_get_name_and_namespace) {
}, rclcpp::exceptions::NameValidationError);
}
}
TEST_F(TestNode, subnode_parameter_operation) {
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
auto subnode = node->create_sub_node("sub_ns");
auto value = subnode->declare_parameter("param", 5);
EXPECT_EQ(value, 5);
// node and sub-node shares NodeParametersInterface, so expecting the exception.
EXPECT_THROW(
node->declare_parameter("param", 0),
rclcpp::exceptions::ParameterAlreadyDeclaredException);
rclcpp::Parameter param;
node->get_parameter("param", param);
EXPECT_EQ(param.get_value<int>(), 5);
subnode->get_parameter("param", param);
EXPECT_EQ(param.get_value<int>(), 5);
int param_int;
node->get_parameter("param", param_int);
EXPECT_EQ(param_int, 5);
subnode->get_parameter("param", param_int);
EXPECT_EQ(param_int, 5);
EXPECT_EQ(node->get_parameter_or("param", 333), 5);
EXPECT_EQ(subnode->get_parameter_or("param", 666), 5);
node->get_parameter_or("param", param_int, 333);
EXPECT_EQ(param_int, 5);
subnode->get_parameter_or("param", param_int, 666);
EXPECT_EQ(param_int, 5);
}
/*
Testing node construction and destruction.
*/

View File

@@ -258,10 +258,8 @@ TEST(TestNodeOptions, append_parameter_override) {
auto options = rclcpp::NodeOptions().arguments(expected_args).use_global_arguments(false);
rclcpp::Parameter parameter("some_parameter", 10);
options.append_parameter_override("some_parameter", 10);
options.append_parameter_override(parameter);
EXPECT_EQ(2u, options.parameter_overrides().size());
EXPECT_EQ(1u, options.parameter_overrides().size());
EXPECT_EQ(std::string("some_parameter"), options.parameter_overrides()[0].get_name());
EXPECT_EQ(std::string("some_parameter"), options.parameter_overrides()[1].get_name());
}
TEST(TestNodeOptions, rcl_node_options_fini_error) {

View File

@@ -34,9 +34,9 @@ using namespace std::chrono_literals;
class TestParameterClient : public ::testing::Test
{
public:
void OnMessage([[maybe_unused]] rcl_interfaces::msg::ParameterEvent::ConstSharedPtr event)
void OnMessage(rcl_interfaces::msg::ParameterEvent::ConstSharedPtr event)
{
// This function is intentionally left empty.
(void)event;
}
protected:

View File

@@ -72,13 +72,6 @@ protected:
/*
Testing filters.
*/
TEST_F(TestParameterEventFilter, invalide_arguments) {
EXPECT_THROW(
rclcpp::ParameterEventsFilter(nullptr, {"new"}, {nt}),
std::invalid_argument
);
}
TEST_F(TestParameterEventFilter, full_by_type) {
auto res = rclcpp::ParameterEventsFilter(
full,

View File

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

View File

@@ -199,7 +199,7 @@ TEST_F(TestPublisher, test_publisher_with_system_default_qos) {
using test_msgs::msg::Empty;
ASSERT_NO_THROW(
{
auto publisher = node->create_publisher<Empty>("topic", rclcpp::SystemDefaultsQoS(), options);
auto publisher = node->create_publisher<Empty>("topic", rclcpp::SystemDefaultsQoS());
});
}

View File

@@ -122,9 +122,9 @@ public:
}
protected:
static void OnMessage([[maybe_unused]] test_msgs::msg::Empty::ConstSharedPtr msg)
static void OnMessage(test_msgs::msg::Empty::ConstSharedPtr msg)
{
// This function is intentionally left empty.
(void)msg;
}
std::chrono::milliseconds offset{2000};

View File

@@ -88,18 +88,21 @@ struct TypeAdapter<int, rclcpp::msg::String>
static void
convert_to_ros_message(
[[maybe_unused]] const custom_type & source,
[[maybe_unused]] ros_message_type & destination)
const custom_type & source,
ros_message_type & destination)
{
(void) source;
(void) destination;
throw std::runtime_error("This should not happen");
}
static void
convert_to_custom(
[[maybe_unused]] const ros_message_type & source,
[[maybe_unused]] custom_type & destination)
const ros_message_type & source,
custom_type & destination)
{
// This function is intentionally left empty.
(void) source;
(void) destination;
}
};
@@ -162,9 +165,9 @@ TEST_F(TestPublisher, conversion_exception_is_passed_up) {
options.use_intra_process_comms(is_intra_process);
auto callback =
[]([[maybe_unused]] const rclcpp::msg::String::ConstSharedPtr msg) -> void
[](const rclcpp::msg::String::ConstSharedPtr msg) -> void
{
// This function is intentionally left empty.
(void)msg;
};
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns", options);

View File

@@ -184,7 +184,7 @@ TEST(TestQoS, DerivedTypes) {
EXPECT_EQ(rmw_qos_profile_parameter_events, parameter_events_qos.get_rmw_qos_profile());
rclcpp::RosoutQoS rosout_qos;
EXPECT_EQ(rmw_qos_profile_rosout_default, rosout_qos.get_rmw_qos_profile());
EXPECT_EQ(rcl_qos_profile_rosout_default, rosout_qos.get_rmw_qos_profile());
rclcpp::SystemDefaultsQoS system_default_qos;
const rclcpp::KeepLast expected_initialization(RMW_QOS_POLICY_DEPTH_SYSTEM_DEFAULT);
@@ -272,15 +272,3 @@ 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

@@ -73,9 +73,7 @@ TEST_F(TestQosEvent, test_publisher_constructor)
auto publisher = node->create_publisher<test_msgs::msg::Empty>(
topic_name, 10, options);
if (rmw_event_type_is_supported(RMW_EVENT_OFFERED_DEADLINE_MISSED) &&
rmw_event_type_is_supported(RMW_EVENT_LIVELINESS_LOST))
{
if (rmw_implementation_str != "rmw_zenoh_cpp") {
// options arg with one of the callbacks
options.event_callbacks.deadline_callback =
[node = node.get()](rclcpp::QOSDeadlineOfferedInfo & event) {
@@ -123,9 +121,7 @@ TEST_F(TestQosEvent, test_subscription_constructor)
auto subscription = node->create_subscription<test_msgs::msg::Empty>(
topic_name, 10, message_callback, options);
if (rmw_event_type_is_supported(RMW_EVENT_REQUESTED_DEADLINE_MISSED) &&
rmw_event_type_is_supported(RMW_EVENT_LIVELINESS_CHANGED))
{
if (rmw_implementation_str != "rmw_zenoh_cpp") {
// options arg with one of the callbacks
options.event_callbacks.deadline_callback =
[node = node.get()](rclcpp::QOSDeadlineRequestedInfo & event) {
@@ -215,9 +211,10 @@ TEST_F(TestQosEvent, test_default_incompatible_qos_callbacks)
const auto timeout = std::chrono::seconds(10);
ex.spin_until_future_complete(log_msgs_future, timeout);
if (qos_check_compatible(qos_profile_publisher,
qos_profile_subscription).compatibility != rclcpp::QoSCompatibility::Ok)
{
if (rmw_implementation_str == "rmw_zenoh_cpp") {
EXPECT_EQ(rclcpp::QoSCompatibility::Ok,
qos_check_compatible(qos_profile_publisher, qos_profile_subscription).compatibility);
} else {
EXPECT_EQ(
"New subscription discovered on topic '/ns/test_topic', requesting incompatible QoS. "
"No messages will be sent to it. Last incompatible policy: DURABILITY_QOS_POLICY",
@@ -238,8 +235,7 @@ TEST_F(TestQosEvent, construct_destruct_rcl_error) {
// This callback requires some type of parameter, but it could be anything
auto callback = [](int) {};
const rcl_publisher_event_type_t event_type =
!rmw_event_type_is_supported(RMW_EVENT_OFFERED_DEADLINE_MISSED) ?
const rcl_publisher_event_type_t event_type = rmw_implementation_str == "rmw_zenoh_cpp" ?
RCL_PUBLISHER_MATCHED : RCL_PUBLISHER_OFFERED_DEADLINE_MISSED;
{
@@ -277,10 +273,9 @@ TEST_F(TestQosEvent, construct_destruct_rcl_error) {
}
TEST_F(TestQosEvent, execute) {
if (!rmw_event_type_is_supported(RMW_EVENT_OFFERED_DEADLINE_MISSED)) {
if (rmw_implementation_str == "rmw_zenoh_cpp") {
GTEST_SKIP();
}
auto publisher = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
auto rcl_handle = publisher->get_publisher_handle();
@@ -313,11 +308,9 @@ TEST_F(TestQosEvent, add_to_wait_set) {
// This callback requires some type of parameter, but it could be anything
auto callback = [](int) {};
const rcl_publisher_event_type_t event_type =
!rmw_event_type_is_supported(RMW_EVENT_OFFERED_DEADLINE_MISSED) ?
const rcl_publisher_event_type_t event_type = rmw_implementation_str == "rmw_zenoh_cpp" ?
RCL_PUBLISHER_MATCHED : RCL_PUBLISHER_OFFERED_DEADLINE_MISSED;
rclcpp::EventHandler<decltype(callback), decltype(rcl_handle)> handler(
rclcpp::EventHandler<decltype(callback), decltype(rcl_handle)> handler(
callback, rcl_publisher_event_init, rcl_handle, event_type);
EXPECT_EQ(1u, handler.get_number_of_ready_events());
@@ -338,9 +331,7 @@ TEST_F(TestQosEvent, add_to_wait_set) {
TEST_F(TestQosEvent, test_on_new_event_callback)
{
if (!rmw_event_type_is_supported(RMW_EVENT_REQUESTED_DEADLINE_MISSED) ||
!rmw_event_type_is_supported(RMW_EVENT_OFFERED_DEADLINE_MISSED))
{
if (rmw_implementation_str == "rmw_zenoh_cpp") {
GTEST_SKIP();
}
@@ -389,9 +380,7 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
auto sub = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
auto dummy_cb = [](size_t count_events) {(void)count_events;};
if (rmw_event_type_is_supported(RMW_EVENT_OFFERED_DEADLINE_MISSED) &&
rmw_event_type_is_supported(RMW_EVENT_LIVELINESS_LOST))
{
if (rmw_implementation_str != "rmw_zenoh_cpp") {
EXPECT_NO_THROW(
pub->set_on_new_qos_event_callback(dummy_cb, RCL_PUBLISHER_OFFERED_DEADLINE_MISSED));
@@ -416,9 +405,7 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
EXPECT_NO_THROW(
pub->clear_on_new_qos_event_callback(RCL_PUBLISHER_MATCHED));
if (rmw_event_type_is_supported(RMW_EVENT_REQUESTED_DEADLINE_MISSED) &&
rmw_event_type_is_supported(RMW_EVENT_LIVELINESS_CHANGED))
{
if (rmw_implementation_str == "rmw_zenoh_cpp") {
EXPECT_NO_THROW(
sub->set_on_new_qos_event_callback(dummy_cb, RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED));
@@ -443,9 +430,7 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
EXPECT_NO_THROW(
sub->clear_on_new_qos_event_callback(RCL_SUBSCRIPTION_MATCHED));
if (rmw_event_type_is_supported(RMW_EVENT_REQUESTED_DEADLINE_MISSED) &&
rmw_event_type_is_supported(RMW_EVENT_OFFERED_DEADLINE_MISSED))
{
if (rmw_implementation_str != "rmw_zenoh_cpp") {
std::function<void(size_t)> invalid_cb;
rclcpp::SubscriptionOptions sub_options;

Some files were not shown because too many files have changed in this diff Show More