Compare commits

..

1 Commits

Author SHA1 Message Date
Steve Wolter
952e22e087 Make get_rcl_allocator a function family
As explained in #1254, there's conceptually no way to implement RCL
allocators in terms of C++ allocators. In order to fix this behavior,
we have to delete the generic version of get_rcl_allocator. Since some
ROS code depends on this, we need to allow users to write their own
version of get_rcl_allocator for allocators that support the C-style
interface (most do).

So this CL changes get_rcl_allocator from a template function
into a family of (potentially templated) functions, which allows
users to add their own overloads and rely on the "most specialized"
mechanism for function specialization to select the right one. See
http://www.gotw.ca/publications/mill17.htm for details. This also
allows us to return get_rcl_default_allocator for all specializations
of std::allocator (previously, only for std::allocator), which will
already fix #1254 for pretty much all clients. I'll continue to work
on deleting the generic version, though, to make sure that nobody is
accidentally bitten by it.

I've tried to test this by doing a full ROS compilation following the
Dockerfile of the source Docker image, and all packages compile.

Signed-off-by: Steve Wolter <swolter@google.com>
2021-04-25 19:33:24 +00:00
57 changed files with 351 additions and 1688 deletions

View File

@@ -8,10 +8,10 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
Visit the [rclcpp API documentation](http://docs.ros2.org/galactic/api/rclcpp/) for a complete list of its main components.
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
### Examples
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/galactic/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
and [Writing a simple service and client](https://docs.ros.org/en/galactic/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
and [Writing a simple service and client](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
contain some examples of rclcpp APIs in use.

View File

@@ -2,40 +2,6 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9.2.2 (2022-12-06)
------------------
* Fix returning invalid namespace if sub_namespace is empty (`#1810 <https://github.com/ros2/rclcpp/issues/1810>`_)
* use regex for wildcard matching (`#1987 <https://github.com/ros2/rclcpp/issues/1987>`_)
* Add statistics for handle_loaned_message (`#1933 <https://github.com/ros2/rclcpp/issues/1933>`_)
* Contributors: Aaron Lipinski, Barry Xu, Chen Lihui, M. Hofstätter
9.2.1 (2022-04-28)
------------------
* Add test-dep ament_cmake_google_benchmark (`#1904 <https://github.com/ros2/rclcpp/issues/1904>`_) (`#1909 <https://github.com/ros2/rclcpp/issues/1909>`_)
* Use parantheses around logging macro parameter (`#1820 <https://github.com/ros2/rclcpp/issues/1820>`_) (`#1822 <https://github.com/ros2/rclcpp/issues/1822>`_)
* Contributors: mergify[bot]
9.2.0 (2021-09-17)
------------------
* Added thread safe for_each_callback_group method (`#1741 <https://github.com/ros2/rclcpp/issues/1741>`_)
* Added a function rclcpp::wait_for_message() convenience function (`#1705 <https://github.com/ros2/rclcpp/issues/1705>`_) (`#1740 <https://github.com/ros2/rclcpp/issues/1740>`_)
* Fixed a documentation bug (`#1719 <https://github.com/ros2/rclcpp/issues/1719>`_) (`#1720 <https://github.com/ros2/rclcpp/issues/1720>`_)
* Contributors: Aditya Pande, Karsten Knese, mergify[bot]
9.1.0 (2021-05-20)
------------------
* Allow declaring uninitialized statically typed parameters. (`#1673 <https://github.com/ros2/rclcpp/issues/1673>`_) (`#1681 <https://github.com/ros2/rclcpp/issues/1681>`_)
* [service] Don't use a weak_ptr to avoid leaking. (`#1668 <https://github.com/ros2/rclcpp/issues/1668>`_) (`#1670 <https://github.com/ros2/rclcpp/issues/1670>`_)
* Contributors: Jacob Perron, Ivan Santiago Paunovic
9.0.3 (2021-05-10)
------------------
* Use OnShutdown callback handle instead of OnShutdown callback (`#1639 <https://github.com/ros2/rclcpp/issues/1639>`_) (`#1650 <https://github.com/ros2/rclcpp/issues/1650>`_)
* use dynamic_pointer_cast to detect allocator mismatch in intra process manager (`#1643 <https://github.com/ros2/rclcpp/issues/1643>`_) (`#1644 <https://github.com/ros2/rclcpp/issues/1644>`_)
* Increase cppcheck timeout to 500s (`#1634 <https://github.com/ros2/rclcpp/issues/1634>`_)
* Clarify node parameters docs (`#1631 <https://github.com/ros2/rclcpp/issues/1631>`_)
* Contributors: Barry Xu, Jacob Perron, Michel Hidalgo, Shane Loretz, William Woodall
9.0.2 (2021-04-14)
------------------
* Avoid returning loan when none was obtained. (`#1629 <https://github.com/ros2/rclcpp/issues/1629>`_)

View File

@@ -29,71 +29,23 @@ namespace allocator
template<typename T, typename Alloc>
using AllocRebind = typename std::allocator_traits<Alloc>::template rebind_traits<T>;
template<typename Alloc>
void * retyped_allocate(size_t size, void * untyped_allocator)
/// Return the equivalent rcl_allocator_t for the C++ standard allocator.
/**
* This assumes that the user intent behind both allocators is the
* same: Using system malloc for allocation.
*
* If you're using a custom allocator in ROS, you'll need to provide
* your own overload for this function.
*/
template<typename T>
rcl_allocator_t get_rcl_allocator(std::allocator<T> allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
if (!typed_allocator) {
throw std::runtime_error("Received incorrect allocator type");
}
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
}
template<typename T, typename Alloc>
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
if (!typed_allocator) {
throw std::runtime_error("Received incorrect allocator type");
}
auto typed_ptr = static_cast<T *>(untyped_pointer);
std::allocator_traits<Alloc>::deallocate(*typed_allocator, typed_ptr, 1);
}
template<typename T, typename Alloc>
void * retyped_reallocate(void * untyped_pointer, size_t size, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
if (!typed_allocator) {
throw std::runtime_error("Received incorrect allocator type");
}
auto typed_ptr = static_cast<T *>(untyped_pointer);
std::allocator_traits<Alloc>::deallocate(*typed_allocator, typed_ptr, 1);
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
}
// Convert a std::allocator_traits-formatted Allocator into an rcl allocator
template<
typename T,
typename Alloc,
typename std::enable_if<!std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>
rcl_allocator_t get_rcl_allocator(Alloc & allocator)
{
rcl_allocator_t rcl_allocator = rcl_get_default_allocator();
#ifndef _WIN32
rcl_allocator.allocate = &retyped_allocate<Alloc>;
rcl_allocator.deallocate = &retyped_deallocate<T, Alloc>;
rcl_allocator.reallocate = &retyped_reallocate<T, Alloc>;
rcl_allocator.state = &allocator;
#else
(void)allocator; // Remove warning
#endif
return rcl_allocator;
}
// TODO(jacquelinekay) Workaround for an incomplete implementation of std::allocator<void>
template<
typename T,
typename Alloc,
typename std::enable_if<std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>
rcl_allocator_t get_rcl_allocator(Alloc & allocator)
{
(void)allocator;
return rcl_get_default_allocator();
}
} // namespace allocator
} // namespace rclcpp
#endif // RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_

View File

@@ -23,7 +23,6 @@
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -48,17 +47,6 @@ public:
/// Forward declare WeakContextsWrapper
class WeakContextsWrapper;
class OnShutdownCallbackHandle
{
friend class Context;
public:
using OnShutdownCallbackType = std::function<void ()>;
private:
std::weak_ptr<OnShutdownCallbackType> callback;
};
/// Context which encapsulates shared state between nodes and other similar entities.
/**
* A context also represents the lifecycle between init and shutdown of rclcpp.
@@ -189,7 +177,7 @@ public:
bool
shutdown(const std::string & reason);
using OnShutdownCallback = OnShutdownCallbackHandle::OnShutdownCallbackType;
using OnShutdownCallback = std::function<void ()>;
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/**
@@ -215,47 +203,23 @@ public:
OnShutdownCallback
on_shutdown(OnShutdownCallback callback);
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/// Return the shutdown callbacks as const.
/**
* These callbacks will be called in the order they are added as the second
* to last step in shutdown().
*
* When shutdown occurs due to the signal handler, these callbacks are run
* asynchronously in the dedicated singal handling thread.
*
* Also, shutdown() may be called from the destructor of this function.
* Therefore, it is not safe to throw exceptions from these callbacks.
* Instead, log errors or use some other mechanism to indicate an error has
* occurred.
*
* On shutdown callbacks may be registered before init and after shutdown,
* and persist on repeated init's.
*
* \param[in] callback the on_shutdown callback to be registered
* \return the created callback handle
* Using the returned reference is not thread-safe with calls that modify
* the list of "on shutdown" callbacks, i.e. on_shutdown().
*/
RCLCPP_PUBLIC
virtual
OnShutdownCallbackHandle
add_on_shutdown_callback(OnShutdownCallback callback);
/// Remove an registered on_shutdown callbacks.
/**
* \param[in] callback_handle the on_shutdown callback handle to be removed.
* \return true if the callback is found and removed, otherwise false.
*/
RCLCPP_PUBLIC
virtual
bool
remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle);
const std::vector<OnShutdownCallback> &
get_on_shutdown_callbacks() const;
/// Return the shutdown callbacks.
/**
* Returned callbacks are a copy of the registered callbacks.
* Using the returned reference is not thread-safe with calls that modify
* the list of "on shutdown" callbacks, i.e. on_shutdown().
*/
RCLCPP_PUBLIC
std::vector<OnShutdownCallback>
get_on_shutdown_callbacks() const;
std::vector<OnShutdownCallback> &
get_on_shutdown_callbacks();
/// Return the internal rcl context.
RCLCPP_PUBLIC
@@ -335,8 +299,8 @@ private:
// attempt to acquire another sub context.
std::recursive_mutex sub_contexts_mutex_;
std::unordered_set<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
mutable std::mutex on_shutdown_callbacks_mutex_;
std::vector<OnShutdownCallback> on_shutdown_callbacks_;
std::mutex on_shutdown_callbacks_mutex_;
/// Condition variable for timed sleep (see sleep_for).
std::condition_variable interrupt_condition_variable_;

View File

@@ -282,8 +282,8 @@ class ParameterModifiedInCallbackException : public std::runtime_error
using std::runtime_error::runtime_error;
};
/// Thrown when an uninitialized parameter is accessed.
class ParameterUninitializedException : public std::runtime_error
/// Thrown when a parameter override wasn't provided and one was required.
class NoParameterOverrideProvided : public std::runtime_error
{
public:
/// Construct an instance.
@@ -291,8 +291,8 @@ public:
* \param[in] name the name of the parameter.
* \param[in] message custom exception message.
*/
explicit ParameterUninitializedException(const std::string & name)
: std::runtime_error("parameter '" + name + "' is not initialized")
explicit NoParameterOverrideProvided(const std::string & name)
: std::runtime_error("parameter '" + name + "' requires an user provided parameter override")
{}
};

View File

@@ -30,7 +30,6 @@
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/context.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/executor_options.hpp"
@@ -572,9 +571,6 @@ protected:
/// nodes that are associated with the executor
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>
weak_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// shutdown callback handle registered to Context
rclcpp::OnShutdownCallbackHandle shutdown_callback_handle_;
};
} // namespace rclcpp

View File

@@ -202,8 +202,7 @@ public:
// None of the buffers require ownership, so we promote the pointer
std::shared_ptr<MessageT> msg = std::move(message);
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
msg, sub_ids.take_shared_subscriptions);
this->template add_shared_msg_to_buffers<MessageT>(msg, sub_ids.take_shared_subscriptions);
} else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
sub_ids.take_shared_subscriptions.size() <= 1)
{
@@ -228,7 +227,7 @@ public:
// for the buffers that do not require ownership
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg, sub_ids.take_shared_subscriptions);
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
std::move(message), sub_ids.take_ownership_subscriptions, allocator);
@@ -264,7 +263,7 @@ public:
// If there are no owning, just convert to shared.
std::shared_ptr<MessageT> shared_msg = std::move(message);
if (!sub_ids.take_shared_subscriptions.empty()) {
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg, sub_ids.take_shared_subscriptions);
}
return shared_msg;
@@ -274,7 +273,7 @@ public:
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
if (!sub_ids.take_shared_subscriptions.empty()) {
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg,
sub_ids.take_shared_subscriptions);
}
@@ -351,10 +350,7 @@ private:
bool
can_communicate(PublisherInfo pub_info, SubscriptionInfo sub_info) const;
template<
typename MessageT,
typename Alloc,
typename Deleter>
template<typename MessageT>
void
add_shared_msg_to_buffers(
std::shared_ptr<const MessageT> message,
@@ -367,16 +363,9 @@ private:
}
auto subscription_base = subscription_it->second.subscription.lock();
if (subscription_base) {
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT, Alloc, Deleter>
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
>(subscription_base);
if (nullptr == subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcess<MessageT, Alloc, Deleter>, which "
"can happen when the publisher and subscription use different "
"allocator types, which is not supported");
}
subscription->provide_intra_process_message(message);
} else {
@@ -405,16 +394,9 @@ private:
}
auto subscription_base = subscription_it->second.subscription.lock();
if (subscription_base) {
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT, Alloc, Deleter>
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
>(subscription_base);
if (nullptr == subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcess<MessageT, Alloc, Deleter>, which "
"can happen when the publisher and subscription use different "
"allocator types, which is not supported");
}
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership

View File

@@ -61,7 +61,7 @@ public:
message_allocator_ = std::make_shared<MessageAlloc>();
serialized_message_allocator_ = std::make_shared<SerializedMessageAlloc>();
buffer_allocator_ = std::make_shared<BufferAlloc>();
rcutils_allocator_ = allocator::get_rcl_allocator<char, BufferAlloc>(*buffer_allocator_.get());
rcutils_allocator_ = rclcpp::allocator::get_rcl_allocator(*buffer_allocator_.get());
}
explicit MessageMemoryStrategy(std::shared_ptr<Alloc> allocator)
@@ -69,7 +69,7 @@ public:
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
serialized_message_allocator_ = std::make_shared<SerializedMessageAlloc>(*allocator.get());
buffer_allocator_ = std::make_shared<BufferAlloc>(*allocator.get());
rcutils_allocator_ = allocator::get_rcl_allocator<char, BufferAlloc>(*buffer_allocator_.get());
rcutils_allocator_ = rclcpp::allocator::get_rcl_allocator(*buffer_allocator_.get());
}
virtual ~MessageMemoryStrategy() = default;

View File

@@ -153,17 +153,6 @@ public:
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
get_callback_groups() const;
/// Iterate over the callback groups in the node, calling the given function on each valid one.
/**
* This method is called in a thread-safe way, and also makes sure to only call the given
* function on those items that are still valid.
*
* \param[in] func The callback function to call on each valid callback group.
*/
RCLCPP_PUBLIC
void
for_each_callback_group(const node_interfaces::NodeBaseInterface::CallbackGroupFunction & func);
/// Create and return a Publisher.
/**
* The rclcpp::QoS has several convenient constructors, including a
@@ -995,15 +984,12 @@ public:
std::map<std::string, std::vector<std::string>>
get_service_names_and_types() const;
/// Return a map of existing service names to list of service types for a specific node.
/// Return the number of publishers that are advertised on a given topic.
/**
* This function only considers services - not clients.
* The returned names are the actual names used and do not have remap rules applied.
*
* \param[in] node_name name of the node.
* \param[in] namespace_ namespace of the node.
* \return a map of existing service names to list of service types.
* \throws std::runtime_error anything that rcl_error can throw.
* \param[in] node_name the node_name on which to count the publishers.
* \param[in] namespace_ the namespace of the node associated with the name
* \return number of publishers that are advertised on a given topic.
* \throws std::runtime_error if publishers could not be counted
*/
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>

View File

@@ -16,13 +16,10 @@
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include "rcl/node.h"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
@@ -33,34 +30,12 @@ namespace rclcpp
namespace node_interfaces
{
RCLCPP_PUBLIC
void global_for_each_callback_group(
NodeBaseInterface * node_base_interface,
const NodeBaseInterface::CallbackGroupFunction & func);
// Class to hold the global map of mutexes
class map_of_mutexes final
{
public:
// Methods need to be protected by internal mutex
void create_mutex_of_nodebase(const NodeBaseInterface * nodebase);
std::shared_ptr<std::mutex>
get_mutex_of_nodebase(const NodeBaseInterface * nodebase);
void delete_mutex_of_nodebase(const NodeBaseInterface * nodebase);
private:
std::unordered_map<const NodeBaseInterface *, std::shared_ptr<std::mutex>> data_;
std::mutex internal_mutex_;
};
/// Implementation of the NodeBase part of the Node API.
class NodeBase : public NodeBaseInterface
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBase)
static map_of_mutexes map_object;
RCLCPP_PUBLIC
NodeBase(
const std::string & node_name,

View File

@@ -38,8 +38,6 @@ class NodeBaseInterface
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBaseInterface)
using CallbackGroupFunction = std::function<void (rclcpp::CallbackGroup::SharedPtr)>;
RCLCPP_PUBLIC
virtual
~NodeBaseInterface() = default;

View File

@@ -41,16 +41,6 @@ RCLCPP_PUBLIC
ParameterMap
parameter_map_from(const rcl_params_t * const c_params);
/// Convert parameters from rcl_yaml_param_parser into C++ class instances.
/// \param[in] c_params C structures containing parameters for multiple nodes.
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
/// If it's not nullptr, return the relative node parameters belonging to this node_fqn.
/// \returns a map where the keys are fully qualified node names and values a list of parameters.
/// \throws InvalidParametersException if the `rcl_params_t` is inconsistent or invalid.
RCLCPP_PUBLIC
ParameterMap
parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn);
/// Convert parameter value from rcl_yaml_param_parser into a C++ class instance.
/// \param[in] c_value C structure containing a value of a parameter.
/// \returns an instance of a parameter value

View File

@@ -80,10 +80,7 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
to_rcl_publisher_options(const rclcpp::QoS & qos) const
{
rcl_publisher_options_t result = rcl_publisher_get_default_options();
using AllocatorTraits = std::allocator_traits<Allocator>;
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
result.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(*message_alloc);
result.allocator = rclcpp::allocator::get_rcl_allocator(*this->get_allocator());
result.qos = qos.get_rmw_qos_profile();
result.rmw_publisher_options.require_unique_network_flow_endpoints =
this->require_unique_network_flow_endpoints;

View File

@@ -177,16 +177,25 @@ public:
using rosidl_typesupport_cpp::get_service_type_support_handle;
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
std::weak_ptr<rcl_node_t> weak_node_handle(node_handle_);
// rcl does the static memory allocation here
service_handle_ = std::shared_ptr<rcl_service_t>(
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
new rcl_service_t, [weak_node_handle, service_name](rcl_service_t * service)
{
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
RCLCPP_ERROR(
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
auto handle = weak_node_handle.lock();
if (handle) {
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
RCLCPP_ERROR(
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
}
} else {
RCLCPP_ERROR_STREAM(
rclcpp::get_logger("rclcpp"),
"Error in destruction of rcl service handle " << service_name <<
": the Node Handle was destructed too early. You will leak memory");
}
delete service;
});

View File

@@ -437,7 +437,7 @@ public:
rcl_allocator_t get_allocator() override
{
return rclcpp::allocator::get_rcl_allocator<void *, VoidAlloc>(*allocator_.get());
return rclcpp::allocator::get_rcl_allocator(*allocator_.get());
}
size_t number_of_ready_subscriptions() const override

View File

@@ -295,31 +295,11 @@ public:
void * loaned_message,
const rclcpp::MessageInfo & message_info) override
{
if (matches_any_intra_process_publishers(&message_info.get_rmw_message_info().publisher_gid)) {
// In this case, the message will be delivered via intra process and
// we should ignore this copy of the message.
return;
}
auto typed_message = static_cast<CallbackMessageT *>(loaned_message);
// message is loaned, so we have to make sure that the deleter does not deallocate the message
auto sptr = std::shared_ptr<CallbackMessageT>(
typed_message, [](CallbackMessageT * msg) {(void) msg;});
std::chrono::time_point<std::chrono::system_clock> now;
if (subscription_topic_statistics_) {
// get current time before executing callback to
// exclude callback duration from topic statistics result.
now = std::chrono::system_clock::now();
}
any_callback_.dispatch(sptr, message_info);
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
}
}
/// Return the borrowed message.

View File

@@ -107,10 +107,7 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
to_rcl_subscription_options(const rclcpp::QoS & qos) const
{
rcl_subscription_options_t result = rcl_subscription_get_default_options();
using AllocatorTraits = std::allocator_traits<Allocator>;
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
result.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc);
result.allocator = rclcpp::allocator::get_rcl_allocator(*this->get_allocator());
result.qos = qos.get_rmw_qos_profile();
result.rmw_subscription_options.ignore_local_publications = this->ignore_local_publications;
result.rmw_subscription_options.require_unique_network_flow_endpoints =

View File

@@ -1,100 +0,0 @@
// Copyright 2021 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__WAIT_FOR_MESSAGE_HPP_
#define RCLCPP__WAIT_FOR_MESSAGE_HPP_
#include <memory>
#include <string>
#include "rclcpp/node.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
namespace rclcpp
{
/// Wait for the next incoming message.
/**
* Given an already initialized subscription,
* wait for the next incoming message to arrive before the specified timeout.
*
* \param[out] out is the message to be filled when a new message is arriving.
* \param[in] subscription shared pointer to a previously initialized subscription.
* \param[in] context shared pointer to a context to watch for SIGINT requests.
* \param[in] time_to_wait parameter specifying the timeout before returning.
* \return true if a message was successfully received, false if message could not
* be obtained or shutdown was triggered asynchronously on the context.
*/
template<class MsgT, class Rep = int64_t, class Period = std::milli>
bool wait_for_message(
MsgT & out,
std::shared_ptr<rclcpp::Subscription<MsgT>> subscription,
std::shared_ptr<rclcpp::Context> context,
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
{
auto gc = std::make_shared<rclcpp::GuardCondition>(context);
auto shutdown_callback_handle = context->add_on_shutdown_callback(
[weak_gc = std::weak_ptr<rclcpp::GuardCondition>{gc}]() {
auto strong_gc = weak_gc.lock();
if (strong_gc) {
strong_gc->trigger();
}
});
rclcpp::WaitSet wait_set;
wait_set.add_subscription(subscription);
wait_set.add_guard_condition(gc);
auto ret = wait_set.wait(time_to_wait);
if (ret.kind() != rclcpp::WaitResultKind::Ready) {
return false;
}
if (wait_set.get_rcl_wait_set().guard_conditions[0]) {
return false;
}
rclcpp::MessageInfo info;
if (!subscription->take(out, info)) {
return false;
}
return true;
}
/// Wait for the next incoming 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[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.
* \return true if a message was successfully received, false if message could not
* be obtained or shutdown was triggered asynchronously on the context.
*/
template<class MsgT, class Rep = int64_t, class Period = std::milli>
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))
{
auto sub = node->create_subscription<MsgT>(topic, 1, [](const std::shared_ptr<MsgT>) {});
return wait_for_message<MsgT, Rep, Period>(
out, sub, node->get_node_options().context(), time_to_wait);
}
} // namespace rclcpp
#endif // RCLCPP__WAIT_FOR_MESSAGE_HPP_

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>9.2.2</version>
<version>9.0.2</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
@@ -37,7 +37,6 @@
<depend>tracetools</depend>
<test_depend>ament_cmake_gmock</test_depend>
<test_depend>ament_cmake_google_benchmark</test_depend>
<test_depend>ament_cmake_gtest</test_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

View File

@@ -149,7 +149,7 @@ def get_rclcpp_suffix_from_features(features):
@[ if params]@
@(''.join([' ' + p + ', \\\n' for p in params if p != stream_arg]))@
@[ end if]@
(logger).get_name(), \
logger.get_name(), \
@[ if 'stream' not in feature_combination]@
__VA_ARGS__); \
@[ else]@

View File

@@ -315,13 +315,9 @@ Context::shutdown(const std::string & reason)
// set shutdown reason
shutdown_reason_ = reason;
// call each shutdown callback
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
for (const auto & callback : on_shutdown_callbacks_) {
(*callback)();
}
for (const auto & callback : on_shutdown_callbacks_) {
callback();
}
// interrupt all blocking sleep_for() and all blocking executors or wait sets
this->interrupt_all_sleep_for();
// remove self from the global contexts
@@ -348,48 +344,20 @@ Context::shutdown(const std::string & reason)
rclcpp::Context::OnShutdownCallback
Context::on_shutdown(OnShutdownCallback callback)
{
add_on_shutdown_callback(callback);
on_shutdown_callbacks_.push_back(callback);
return callback;
}
rclcpp::OnShutdownCallbackHandle
Context::add_on_shutdown_callback(OnShutdownCallback callback)
{
auto callback_shared_ptr = std::make_shared<OnShutdownCallback>(callback);
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
on_shutdown_callbacks_.emplace(callback_shared_ptr);
}
OnShutdownCallbackHandle callback_handle;
callback_handle.callback = callback_shared_ptr;
return callback_handle;
}
bool
Context::remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle)
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
auto callback_shared_ptr = callback_handle.callback.lock();
if (callback_shared_ptr == nullptr) {
return false;
}
return on_shutdown_callbacks_.erase(callback_shared_ptr) == 1;
}
std::vector<rclcpp::Context::OnShutdownCallback>
const std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks() const
{
std::vector<OnShutdownCallback> callbacks;
return on_shutdown_callbacks_;
}
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
for (auto & iter : on_shutdown_callbacks_) {
callbacks.emplace_back(*iter);
}
}
return callbacks;
std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks()
{
return on_shutdown_callbacks_;
}
std::shared_ptr<rcl_context_t>

View File

@@ -51,13 +51,18 @@ rclcpp::detail::resolve_parameter_overrides(
[params]() {
rcl_yaml_node_struct_fini(params);
});
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params, node_fqn.c_str());
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
if (initial_map.count(node_fqn) > 0) {
// Combine parameter yaml files, overwriting values in older ones
for (const rclcpp::Parameter & param : initial_map.at(node_fqn)) {
result[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
// Enforce wildcard matching precedence
// TODO(cottsay) implement further wildcard matching
const std::array<std::string, 2> node_matching_names{"/**", node_fqn};
for (const auto & node_name : node_matching_names) {
if (initial_map.count(node_name) > 0) {
// Combine parameter yaml files, overwriting values in older ones
for (const rclcpp::Parameter & param : initial_map.at(node_name)) {
result[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}
}
}
}

View File

@@ -30,7 +30,6 @@
#include "rclcpp/node.hpp"
#include "rclcpp/scope_exit.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rcutils/logging_macros.h"
@@ -57,7 +56,7 @@ Executor::Executor(const rclcpp::ExecutorOptions & options)
throw_from_rcl_error(ret, "Failed to create interrupt guard condition in Executor constructor");
}
shutdown_callback_handle_ = context_->add_on_shutdown_callback(
context_->on_shutdown(
[weak_gc = std::weak_ptr<rclcpp::GuardCondition>{shutdown_guard_condition_}]() {
auto strong_gc = weak_gc.lock();
if (strong_gc) {
@@ -139,14 +138,6 @@ Executor::~Executor()
}
// Remove and release the sigint guard condition
memory_strategy_->remove_guard_condition(&shutdown_guard_condition_->get_rcl_guard_condition());
// Remove shutdown callback handle registered to Context
if (!context_->remove_on_shutdown_callback(shutdown_callback_handle_)) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to remove registered on_shutdown callback");
rcl_reset_error();
}
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
@@ -191,13 +182,14 @@ Executor::add_callback_groups_from_nodes_associated_to_executor()
for (auto & weak_node : weak_nodes_) {
auto node = weak_node.lock();
if (node) {
rclcpp::node_interfaces::global_for_each_callback_group(
node.get(),
[this, node](rclcpp::CallbackGroup::SharedPtr shared_group_ptr)
auto group_ptrs = node->get_callback_groups();
std::for_each(
group_ptrs.begin(), group_ptrs.end(),
[this, node](rclcpp::CallbackGroup::WeakPtr group_ptr)
{
if (
shared_group_ptr->automatically_add_to_executor_with_node() &&
!shared_group_ptr->get_associated_with_executor_atomic().load())
auto shared_group_ptr = group_ptr.lock();
if (shared_group_ptr && shared_group_ptr->automatically_add_to_executor_with_node() &&
!shared_group_ptr->get_associated_with_executor_atomic().load())
{
this->add_callback_group_to_map(
shared_group_ptr,
@@ -271,21 +263,18 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
throw std::runtime_error("Node has already been added to an executor.");
}
std::lock_guard<std::mutex> guard{mutex_};
rclcpp::node_interfaces::global_for_each_callback_group(
node_ptr.get(),
[this, node_ptr, notify](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
if (!group_ptr->get_associated_with_executor_atomic().load() &&
for (auto & weak_group : node_ptr->get_callback_groups()) {
auto group_ptr = weak_group.lock();
if (group_ptr != nullptr && !group_ptr->get_associated_with_executor_atomic().load() &&
group_ptr->automatically_add_to_executor_with_node())
{
this->add_callback_group_to_map(
group_ptr,
node_ptr,
weak_groups_to_nodes_associated_with_executor_,
notify);
}
});
{
this->add_callback_group_to_map(
group_ptr,
node_ptr,
weak_groups_to_nodes_associated_with_executor_,
notify);
}
}
weak_nodes_.push_back(node_ptr);
}

View File

@@ -23,7 +23,6 @@
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
using rclcpp::executors::StaticExecutorEntitiesCollector;
@@ -291,21 +290,18 @@ StaticExecutorEntitiesCollector::add_node(
if (has_executor.exchange(true)) {
throw std::runtime_error("Node has already been added to an executor.");
}
rclcpp::node_interfaces::global_for_each_callback_group(
node_ptr.get(),
[this, node_ptr, &is_new_node](rclcpp::CallbackGroup::SharedPtr group_ptr)
for (const auto & weak_group : node_ptr->get_callback_groups()) {
auto group_ptr = weak_group.lock();
if (group_ptr != nullptr && !group_ptr->get_associated_with_executor_atomic().load() &&
group_ptr->automatically_add_to_executor_with_node())
{
if (
!group_ptr->get_associated_with_executor_atomic().load() &&
group_ptr->automatically_add_to_executor_with_node())
{
is_new_node = (add_callback_group(
is_new_node = (add_callback_group(
group_ptr,
node_ptr,
weak_groups_to_nodes_associated_with_executor_) ||
is_new_node);
}
});
}
}
weak_nodes_.push_back(node_ptr);
return is_new_node;
}
@@ -471,11 +467,13 @@ StaticExecutorEntitiesCollector::add_callback_groups_from_nodes_associated_to_ex
for (const auto & weak_node : weak_nodes_) {
auto node = weak_node.lock();
if (node) {
rclcpp::node_interfaces::global_for_each_callback_group(
node.get(),
[this, node](rclcpp::CallbackGroup::SharedPtr shared_group_ptr)
auto group_ptrs = node->get_callback_groups();
std::for_each(
group_ptrs.begin(), group_ptrs.end(),
[this, node](rclcpp::CallbackGroup::WeakPtr group_ptr)
{
if (shared_group_ptr->automatically_add_to_executor_with_node() &&
auto shared_group_ptr = group_ptr.lock();
if (shared_group_ptr && shared_group_ptr->automatically_add_to_executor_with_node() &&
!shared_group_ptr->get_associated_with_executor_atomic().load())
{
add_callback_group(

View File

@@ -61,12 +61,6 @@ extend_sub_namespace(const std::string & existing_sub_namespace, const std::stri
extension.c_str(),
"a sub-namespace should not have a leading /",
0);
} else if (existing_sub_namespace.empty() && extension.empty()) {
throw rclcpp::exceptions::NameValidationError(
"sub_namespace",
extension.c_str(),
"sub-nodes should not extend nodes by an empty sub-namespace",
0);
}
std::string new_sub_namespace;
@@ -92,11 +86,7 @@ create_effective_namespace(const std::string & node_namespace, const std::string
// and do not need trimming of `/` and other things, as they were validated
// in other functions already.
// A node may not have a sub_namespace if it is no sub_node. In this case,
// just return the original namespace
if (sub_namespace.empty()) {
return node_namespace;
} else if (node_namespace.back() == '/') {
if (node_namespace.back() == '/') {
// this is the special case where node_namespace is just `/`
return node_namespace + sub_namespace;
} else {
@@ -615,9 +605,3 @@ Node::get_node_options() const
{
return this->node_options_;
}
void Node::for_each_callback_group(
const node_interfaces::NodeBaseInterface::CallbackGroupFunction & func)
{
rclcpp::node_interfaces::global_for_each_callback_group(node_base_.get(), func);
}

View File

@@ -31,8 +31,6 @@ using rclcpp::exceptions::throw_from_rcl_error;
using rclcpp::node_interfaces::NodeBase;
using rclcpp::node_interfaces::map_of_mutexes;
NodeBase::NodeBase(
const std::string & node_name,
const std::string & namespace_,
@@ -48,9 +46,6 @@ NodeBase::NodeBase(
associated_with_executor_(false),
notify_guard_condition_is_valid_(false)
{
// Generate a mutex for this instance of NodeBase
NodeBase::map_object.create_mutex_of_nodebase(this);
// Setup the guard condition that is notified when changes occur in the graph.
rcl_guard_condition_options_t guard_condition_options = rcl_guard_condition_get_default_options();
rcl_ret_t ret = rcl_guard_condition_init(
@@ -171,8 +166,6 @@ NodeBase::~NodeBase()
"failed to destroy guard condition: %s", rcl_get_error_string().str);
}
}
NodeBase::map_object.delete_mutex_of_nodebase(this);
}
const char *
@@ -228,11 +221,12 @@ NodeBase::create_callback_group(
rclcpp::CallbackGroupType group_type,
bool automatically_add_to_executor_with_node)
{
auto group = std::make_shared<rclcpp::CallbackGroup>(
group_type,
automatically_add_to_executor_with_node);
auto mutex_ptr = NodeBase::map_object.get_mutex_of_nodebase(this);
std::lock_guard<std::mutex> lock(*mutex_ptr);
using rclcpp::CallbackGroup;
using rclcpp::CallbackGroupType;
auto group = CallbackGroup::SharedPtr(
new CallbackGroup(
group_type,
automatically_add_to_executor_with_node));
callback_groups_.push_back(group);
return group;
}
@@ -246,16 +240,14 @@ NodeBase::get_default_callback_group()
bool
NodeBase::callback_group_in_node(rclcpp::CallbackGroup::SharedPtr group)
{
auto mutex_ptr = NodeBase::map_object.get_mutex_of_nodebase(this);
std::lock_guard<std::mutex> lock(*mutex_ptr);
bool group_belongs_to_this_node = false;
for (auto & weak_group : this->callback_groups_) {
auto cur_group = weak_group.lock();
if (cur_group && (cur_group == group)) {
return true;
group_belongs_to_this_node = true;
}
}
return false;
return group_belongs_to_this_node;
}
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
@@ -318,41 +310,3 @@ NodeBase::resolve_topic_or_service_name(
allocator.deallocate(output_cstr, allocator.state);
return output;
}
map_of_mutexes NodeBase::map_object = map_of_mutexes();
void map_of_mutexes::create_mutex_of_nodebase(
const rclcpp::node_interfaces::NodeBaseInterface * nodebase)
{
std::lock_guard<std::mutex> guard(this->internal_mutex_);
this->data_.emplace(nodebase, std::make_shared<std::mutex>() );
}
std::shared_ptr<std::mutex> map_of_mutexes::get_mutex_of_nodebase(
const rclcpp::node_interfaces::NodeBaseInterface * nodebase)
{
std::lock_guard<std::mutex> guard(this->internal_mutex_);
return this->data_[nodebase];
}
void map_of_mutexes::delete_mutex_of_nodebase(
const rclcpp::node_interfaces::NodeBaseInterface * nodebase)
{
std::lock_guard<std::mutex> guard(this->internal_mutex_);
this->data_.erase(nodebase);
}
// For each callback group free function implementation
void rclcpp::node_interfaces::global_for_each_callback_group(
NodeBaseInterface * node_base_interface, const NodeBaseInterface::CallbackGroupFunction & func)
{
auto mutex_ptr = NodeBase::map_object.get_mutex_of_nodebase(node_base_interface);
std::lock_guard<std::mutex> lock(*mutex_ptr);
for (const auto & weak_group : node_base_interface->get_callback_groups()) {
auto group = weak_group.lock();
if (group) {
func(group);
}
}
}

View File

@@ -349,21 +349,6 @@ __declare_parameter_common(
initial_value = &overrides_it->second;
}
// If there is no initial value, then skip initialization
if (initial_value->get_type() == rclcpp::PARAMETER_NOT_SET) {
// Add declared parameters to storage (without a value)
parameter_infos[name].descriptor.name = name;
if (parameter_descriptor.dynamic_typing) {
parameter_infos[name].descriptor.type = rclcpp::PARAMETER_NOT_SET;
} else {
parameter_infos[name].descriptor.type = parameter_descriptor.type;
}
parameters_out[name] = parameter_infos.at(name);
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
return result;
}
// Check with the user's callback to see if the initial value can be set.
std::vector<rclcpp::Parameter> parameter_wrappers {rclcpp::Parameter(name, *initial_value)};
// This function also takes care of default vs initial value.
@@ -428,6 +413,14 @@ declare_parameter_helper(
parameter_descriptor.type = static_cast<uint8_t>(type);
}
if (
rclcpp::PARAMETER_NOT_SET == default_value.get_type() &&
overrides.find(name) == overrides.end() &&
parameter_descriptor.dynamic_typing == false)
{
throw rclcpp::exceptions::NoParameterOverrideProvided(name);
}
rcl_interfaces::msg::ParameterEvent parameter_event;
auto result = __declare_parameter_common(
name,
@@ -813,21 +806,14 @@ NodeParameters::get_parameters(const std::vector<std::string> & names) const
rclcpp::Parameter
NodeParameters::get_parameter(const std::string & name) const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
rclcpp::Parameter parameter;
auto param_iter = parameters_.find(name);
if (
parameters_.end() != param_iter &&
(param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
param_iter->second.descriptor.dynamic_typing))
{
return rclcpp::Parameter{name, param_iter->second.value};
if (get_parameter(name, parameter)) {
return parameter;
} else if (this->allow_undeclared_) {
return rclcpp::Parameter{};
} else if (parameters_.end() == param_iter) {
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
return parameter;
} else {
throw rclcpp::exceptions::ParameterUninitializedException(name);
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
}
}

View File

@@ -13,10 +13,8 @@
// limitations under the License.
#include <string>
#include <regex>
#include <vector>
#include "rcpputils/find_and_replace.hpp"
#include "rclcpp/parameter_map.hpp"
using rclcpp::exceptions::InvalidParametersException;
@@ -26,12 +24,6 @@ using rclcpp::ParameterValue;
ParameterMap
rclcpp::parameter_map_from(const rcl_params_t * const c_params)
{
return parameter_map_from(c_params, nullptr);
}
ParameterMap
rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn)
{
if (NULL == c_params) {
throw InvalidParametersException("parameters struct is NULL");
@@ -57,17 +49,6 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * nod
node_name = c_node_name;
}
if (node_fqn) {
// Update the regular expression ["/*" -> "(/\\w+)" and "/**" -> "(/\\w+)*"]
std::string regex = rcpputils::find_and_replace(node_name, "/*", "(/\\w+)");
if (!std::regex_match(node_fqn, std::regex(regex))) {
// No need to parse the items because the user just care about node_fqn
continue;
}
node_name = node_fqn;
}
const rcl_node_params_t * const c_params_node = &(c_params->params[n]);
std::vector<Parameter> & params_node = parameters[node_name];
@@ -84,7 +65,6 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * nod
params_node.emplace_back(c_param_name, parameter_value_from(c_param_value));
}
}
return parameters;
}

View File

@@ -143,13 +143,6 @@ if(TARGET test_intra_process_manager)
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
endif()
ament_add_gmock(test_intra_process_manager_with_allocators test_intra_process_manager_with_allocators.cpp)
if(TARGET test_intra_process_manager_with_allocators)
ament_target_dependencies(test_intra_process_manager_with_allocators
"test_msgs"
)
target_link_libraries(test_intra_process_manager_with_allocators ${PROJECT_NAME})
endif()
ament_add_gtest(test_ring_buffer_implementation test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
@@ -565,13 +558,6 @@ if(TARGET test_utilities)
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_wait_for_message test_wait_for_message.cpp)
if(TARGET test_wait_for_message)
ament_target_dependencies(test_wait_for_message
"test_msgs")
target_link_libraries(test_wait_for_message ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)

View File

@@ -18,42 +18,9 @@
#include "rclcpp/allocator/allocator_common.hpp"
TEST(TestAllocatorCommon, retyped_allocate) {
std::allocator<int> allocator;
void * untyped_allocator = &allocator;
void * allocated_mem =
rclcpp::allocator::retyped_allocate<std::allocator<char>>(1u, untyped_allocator);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
auto code = [&untyped_allocator, allocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
allocated_mem, untyped_allocator);
};
EXPECT_NO_THROW(code());
allocated_mem = allocator.allocate(1);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
void * reallocated_mem =
rclcpp::allocator::retyped_reallocate<int, std::allocator<int>>(
allocated_mem, 2u, untyped_allocator);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != reallocated_mem);
auto code2 = [&untyped_allocator, reallocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
reallocated_mem, untyped_allocator);
};
EXPECT_NO_THROW(code2());
}
TEST(TestAllocatorCommon, get_rcl_allocator) {
std::allocator<int> allocator;
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator<int>(allocator);
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator(allocator);
EXPECT_NE(nullptr, rcl_allocator.allocate);
EXPECT_NE(nullptr, rcl_allocator.deallocate);
EXPECT_NE(nullptr, rcl_allocator.reallocate);
@@ -63,8 +30,7 @@ TEST(TestAllocatorCommon, get_rcl_allocator) {
TEST(TestAllocatorCommon, get_void_rcl_allocator) {
std::allocator<void> allocator;
auto rcl_allocator =
rclcpp::allocator::get_rcl_allocator<void, std::allocator<void>>(allocator);
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator(allocator);
EXPECT_NE(nullptr, rcl_allocator.allocate);
EXPECT_NE(nullptr, rcl_allocator.deallocate);
EXPECT_NE(nullptr, rcl_allocator.reallocate);

View File

@@ -41,38 +41,38 @@ struct NumberOfEntities
std::unique_ptr<NumberOfEntities> get_number_of_default_entities(rclcpp::Node::SharedPtr node)
{
auto number_of_entities = std::make_unique<NumberOfEntities>();
node->for_each_callback_group(
[&number_of_entities](rclcpp::CallbackGroup::SharedPtr group)
{
if (!group->can_be_taken_from().load()) {
return;
}
group->find_subscription_ptrs_if(
[&number_of_entities](rclcpp::SubscriptionBase::SharedPtr &)
{
number_of_entities->subscriptions++; return false;
});
group->find_timer_ptrs_if(
[&number_of_entities](rclcpp::TimerBase::SharedPtr &)
{
number_of_entities->timers++; return false;
});
group->find_service_ptrs_if(
[&number_of_entities](rclcpp::ServiceBase::SharedPtr &)
{
number_of_entities->services++; return false;
});
group->find_client_ptrs_if(
[&number_of_entities](rclcpp::ClientBase::SharedPtr &)
{
number_of_entities->clients++; return false;
});
group->find_waitable_ptrs_if(
[&number_of_entities](rclcpp::Waitable::SharedPtr &)
{
number_of_entities->waitables++; return false;
});
});
for (auto & weak_group : node->get_callback_groups()) {
auto group = weak_group.lock();
EXPECT_NE(nullptr, group);
if (!group || !group->can_be_taken_from().load()) {
return nullptr;
}
group->find_subscription_ptrs_if(
[&number_of_entities](rclcpp::SubscriptionBase::SharedPtr &)
{
number_of_entities->subscriptions++; return false;
});
group->find_timer_ptrs_if(
[&number_of_entities](rclcpp::TimerBase::SharedPtr &)
{
number_of_entities->timers++; return false;
});
group->find_service_ptrs_if(
[&number_of_entities](rclcpp::ServiceBase::SharedPtr &)
{
number_of_entities->services++; return false;
});
group->find_client_ptrs_if(
[&number_of_entities](rclcpp::ClientBase::SharedPtr &)
{
number_of_entities->clients++; return false;
});
group->find_waitable_ptrs_if(
[&number_of_entities](rclcpp::Waitable::SharedPtr &)
{
number_of_entities->waitables++; return false;
});
}
return number_of_entities;
}

View File

@@ -31,8 +31,6 @@
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
#include "rcpputils/filesystem_helper.hpp"
class TestNodeParameters : public ::testing::Test
{
public:
@@ -49,7 +47,6 @@ public:
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
test_resources_path /= "test_node_parameters";
}
void TearDown()
@@ -60,8 +57,6 @@ public:
protected:
std::shared_ptr<rclcpp::Node> node;
rclcpp::node_interfaces::NodeParameters * node_parameters;
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
};
TEST_F(TestNodeParameters, construct_destruct_rcl_errors) {
@@ -204,130 +199,3 @@ TEST_F(TestNodeParameters, add_remove_parameters_callback) {
node_parameters->remove_on_set_parameters_callback(handle.get()),
std::runtime_error("Callback doesn't exist"));
}
TEST_F(TestNodeParameters, wildcard_with_namespace)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "wildcards.yaml").string()
});
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(7u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
EXPECT_EQ(
parameter_overrides.at("namespace_wild_another").get<std::string>(),
"namespace_wild_another");
EXPECT_EQ(
parameter_overrides.at("namespace_wild_one_star").get<std::string>(),
"namespace_wild_one_star");
EXPECT_EQ(parameter_overrides.at("node_wild_in_ns").get<std::string>(), "node_wild_in_ns");
EXPECT_EQ(
parameter_overrides.at("node_wild_in_ns_another").get<std::string>(),
"node_wild_in_ns_another");
EXPECT_EQ(parameter_overrides.at("explicit_in_ns").get<std::string>(), "explicit_in_ns");
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
}
TEST_F(TestNodeParameters, wildcard_no_namespace)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "wildcards.yaml").string()
});
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(5u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
EXPECT_EQ(
parameter_overrides.at("namespace_wild_another").get<std::string>(),
"namespace_wild_another");
EXPECT_EQ(parameter_overrides.at("node_wild_no_ns").get<std::string>(), "node_wild_no_ns");
EXPECT_EQ(parameter_overrides.at("explicit_no_ns").get<std::string>(), "explicit_no_ns");
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
// "/*" match exactly one token, not expect to get `namespace_wild_one_star`
EXPECT_EQ(parameter_overrides.count("namespace_wild_one_star"), 0u);
}
TEST_F(TestNodeParameters, params_by_order)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "params_by_order.yaml").string()
});
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(3u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("a_value").get<std::string>(), "last_one_win");
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
}
TEST_F(TestNodeParameters, complicated_wildcards)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "complicated_wildcards.yaml").string()
});
{
// regex matched: /**/foo/*/bar
std::shared_ptr<rclcpp::Node> node =
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/d/bar", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(2u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
}
{
// regex not matched: /**/foo/*/bar
std::shared_ptr<rclcpp::Node> node =
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/bar", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(0u, parameter_overrides.size());
}
}

View File

@@ -23,7 +23,6 @@
#include "rclcpp/scope_exit.hpp"
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/srv/empty.hpp"
@@ -115,11 +114,12 @@ protected:
{
auto node = std::make_shared<rclcpp::Node>(name, "ns");
node->for_each_callback_group(
[](rclcpp::CallbackGroup::SharedPtr group)
{
for (auto & group_weak_ptr : node->get_callback_groups()) {
auto group = group_weak_ptr.lock();
if (group) {
group->can_be_taken_from() = false;
});
}
}
return node;
}
@@ -201,13 +201,15 @@ protected:
const RclWaitSetSizes & expected)
{
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes,
&node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -232,13 +234,15 @@ protected:
const RclWaitSetSizes & insufficient_capacities)
{
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes,
&node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -312,22 +316,26 @@ protected:
{
auto basic_node = create_node_with_disabled_callback_groups("basic_node");
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
basic_node->for_each_callback_group(
[basic_node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = basic_node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes,
&basic_node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
basic_node->get_node_base_interface()));
});
node_with_entity1->for_each_callback_group(
[node_with_entity1, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups1 = node_with_entity1->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups1.begin(), callback_groups1.end(),
[&weak_groups_to_nodes,
&node_with_entity1](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node_with_entity1->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -340,23 +348,26 @@ protected:
auto basic_node2 = std::make_shared<rclcpp::Node>("basic_node2", "ns");
WeakCallbackGroupsToNodesMap weak_groups_to_uncollected_nodes;
basic_node2->for_each_callback_group(
[basic_node2, &weak_groups_to_uncollected_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups2 = basic_node2->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups2.begin(), callback_groups2.end(),
[&weak_groups_to_uncollected_nodes,
&basic_node2](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_uncollected_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
basic_node2->get_node_base_interface()));
});
node_with_entity2->for_each_callback_group(
[node_with_entity2,
&weak_groups_to_uncollected_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups3 = node_with_entity2->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups3.begin(), callback_groups3.end(),
[&weak_groups_to_uncollected_nodes,
&node_with_entity2](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_uncollected_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node_with_entity2->get_node_base_interface()));
});
rclcpp::AnyExecutable failed_result = get_next_entity_func(weak_groups_to_uncollected_nodes);
@@ -377,24 +388,24 @@ protected:
auto basic_node_base = basic_node->get_node_base_interface();
auto node_base = node_with_entity->get_node_base_interface();
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
rclcpp::node_interfaces::global_for_each_callback_group(
basic_node_base.get(),
[basic_node_base, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = basic_node_base->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &basic_node_base](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
basic_node_base));
});
rclcpp::node_interfaces::global_for_each_callback_group(
node_base.get(),
[node_base, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
callback_groups = node_base->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node_base](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node_base));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -436,13 +447,14 @@ private:
TEST_F(TestAllocatorMemoryStrategy, construct_destruct) {
auto basic_node = create_node_with_disabled_callback_groups("basic_node");
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
basic_node->for_each_callback_group(
[basic_node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = basic_node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &basic_node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
basic_node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -534,13 +546,14 @@ TEST_F(TestAllocatorMemoryStrategy, number_of_entities_with_timer) {
TEST_F(TestAllocatorMemoryStrategy, add_handles_to_wait_set_bad_arguments) {
auto node = create_node_with_subscription("subscription_node");
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -774,13 +787,14 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_subscription_out_of_scope) {
test_msgs::msg::Empty, decltype(subscription_callback)>(
"topic", qos, std::move(subscription_callback), subscription_options);
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -807,13 +821,14 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_service_out_of_scope) {
auto service = node->create_service<test_msgs::srv::Empty>(
"service", std::move(service_callback), rmw_qos_profile_services_default, callback_group);
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -828,13 +843,14 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_service_out_of_scope) {
TEST_F(TestAllocatorMemoryStrategy, get_next_client_out_of_scope) {
auto node = create_node_with_disabled_callback_groups("node");
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
// Force client to go out of scope and cleanup after collecting entities.
@@ -870,13 +886,14 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_timer_out_of_scope) {
rclcpp::CallbackGroupType::MutuallyExclusive);
auto timer = node->create_wall_timer(
std::chrono::seconds(10), []() {}, callback_group);
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -896,13 +913,14 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_waitable_out_of_scope) {
auto callback_group =
node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);

View File

@@ -216,10 +216,7 @@ public:
const char * topic_name;
};
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
template<typename MessageT>
class SubscriptionIntraProcess : public SubscriptionIntraProcessBase
{
public:

View File

@@ -1,276 +0,0 @@
// Copyright 2021 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 <gmock/gmock.h>
#include <chrono>
#include <list>
#include <memory>
#include <string>
#include <utility>
#include "test_msgs/msg/empty.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
// For demonstration purposes only, not necessary for allocator_traits
static uint32_t num_allocs = 0;
static uint32_t num_deallocs = 0;
// A very simple custom allocator. Counts calls to allocate and deallocate.
template<typename T = void>
struct MyAllocator
{
public:
using value_type = T;
using size_type = std::size_t;
using pointer = T *;
using const_pointer = const T *;
using difference_type = typename std::pointer_traits<pointer>::difference_type;
MyAllocator() noexcept
{
}
~MyAllocator() noexcept {}
template<typename U>
MyAllocator(const MyAllocator<U> &) noexcept
{
}
T * allocate(size_t size, const void * = 0)
{
if (size == 0) {
return nullptr;
}
num_allocs++;
return static_cast<T *>(std::malloc(size * sizeof(T)));
}
void deallocate(T * ptr, size_t size)
{
(void)size;
if (!ptr) {
return;
}
num_deallocs++;
std::free(ptr);
}
template<typename U>
struct rebind
{
typedef MyAllocator<U> other;
};
};
template<typename T, typename U>
constexpr bool operator==(
const MyAllocator<T> &,
const MyAllocator<U> &) noexcept
{
return true;
}
template<typename T, typename U>
constexpr bool operator!=(
const MyAllocator<T> &,
const MyAllocator<U> &) noexcept
{
return false;
}
template<
typename PublishedMessageAllocatorT,
typename PublisherAllocatorT,
typename SubscribedMessageAllocatorT,
typename SubscriptionAllocatorT,
typename MessageMemoryStrategyAllocatorT,
typename MemoryStrategyAllocatorT,
typename ExpectedExceptionT
>
void
do_custom_allocator_test(
PublishedMessageAllocatorT published_message_allocator,
PublisherAllocatorT publisher_allocator,
SubscribedMessageAllocatorT /* subscribed_message_allocator */, // intentionally unused
SubscriptionAllocatorT subscription_allocator,
MessageMemoryStrategyAllocatorT message_memory_strategy,
MemoryStrategyAllocatorT memory_strategy_allocator)
{
using PublishedMessageAllocTraits =
rclcpp::allocator::AllocRebind<test_msgs::msg::Empty, PublishedMessageAllocatorT>;
using PublishedMessageAlloc = typename PublishedMessageAllocTraits::allocator_type;
using PublishedMessageDeleter =
rclcpp::allocator::Deleter<PublishedMessageAlloc, test_msgs::msg::Empty>;
using SubscribedMessageAllocTraits =
rclcpp::allocator::AllocRebind<test_msgs::msg::Empty, SubscribedMessageAllocatorT>;
using SubscribedMessageAlloc = typename SubscribedMessageAllocTraits::allocator_type;
using SubscribedMessageDeleter =
rclcpp::allocator::Deleter<SubscribedMessageAlloc, test_msgs::msg::Empty>;
// init and node
auto context = std::make_shared<rclcpp::Context>();
context->init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>(
"custom_allocator_test",
rclcpp::NodeOptions().context(context).use_intra_process_comms(true));
// publisher
auto shared_publisher_allocator = std::make_shared<PublisherAllocatorT>(publisher_allocator);
rclcpp::PublisherOptionsWithAllocator<PublisherAllocatorT> publisher_options;
publisher_options.allocator = shared_publisher_allocator;
auto publisher =
node->create_publisher<test_msgs::msg::Empty>("custom_allocator_test", 10, publisher_options);
// callback for subscription
uint32_t counter = 0;
std::promise<std::unique_ptr<test_msgs::msg::Empty, SubscribedMessageDeleter>> received_message;
auto received_message_future = received_message.get_future();
auto callback =
[&counter, &received_message](
std::unique_ptr<test_msgs::msg::Empty, SubscribedMessageDeleter> msg)
{
++counter;
received_message.set_value(std::move(msg));
};
// subscription
auto shared_subscription_allocator =
std::make_shared<SubscriptionAllocatorT>(subscription_allocator);
rclcpp::SubscriptionOptionsWithAllocator<SubscriptionAllocatorT> subscription_options;
subscription_options.allocator = shared_subscription_allocator;
auto shared_message_strategy_allocator =
std::make_shared<MessageMemoryStrategyAllocatorT>(message_memory_strategy);
auto msg_mem_strat = std::make_shared<
rclcpp::message_memory_strategy::MessageMemoryStrategy<
test_msgs::msg::Empty,
MessageMemoryStrategyAllocatorT
>
>(shared_message_strategy_allocator);
using CallbackMessageT =
typename rclcpp::subscription_traits::has_message_type<decltype(callback)>::type;
auto subscriber = node->create_subscription<
test_msgs::msg::Empty,
decltype(callback),
SubscriptionAllocatorT,
CallbackMessageT,
rclcpp::Subscription<CallbackMessageT, SubscriptionAllocatorT>,
rclcpp::message_memory_strategy::MessageMemoryStrategy<
CallbackMessageT,
MessageMemoryStrategyAllocatorT
>
>(
"custom_allocator_test",
10,
std::forward<decltype(callback)>(callback),
subscription_options,
msg_mem_strat);
// executor memory strategy
using rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy;
auto shared_memory_strategy_allocator = std::make_shared<MemoryStrategyAllocatorT>(
memory_strategy_allocator);
std::shared_ptr<rclcpp::memory_strategy::MemoryStrategy> memory_strategy =
std::make_shared<AllocatorMemoryStrategy<MemoryStrategyAllocatorT>>(
shared_memory_strategy_allocator);
// executor
rclcpp::ExecutorOptions options;
options.memory_strategy = memory_strategy;
options.context = context;
rclcpp::executors::SingleThreadedExecutor executor(options);
executor.add_node(node);
// rebind message_allocator to ensure correct type
PublishedMessageDeleter message_deleter;
PublishedMessageAlloc rebound_message_allocator = published_message_allocator;
rclcpp::allocator::set_allocator_for_deleter(&message_deleter, &rebound_message_allocator);
// allocate a message
auto ptr = PublishedMessageAllocTraits::allocate(rebound_message_allocator, 1);
PublishedMessageAllocTraits::construct(rebound_message_allocator, ptr);
std::unique_ptr<test_msgs::msg::Empty, PublishedMessageDeleter> msg(ptr, message_deleter);
// publisher and receive
if constexpr (std::is_same_v<ExpectedExceptionT, void>) {
// no exception expected
EXPECT_NO_THROW(
{
publisher->publish(std::move(msg));
executor.spin_until_future_complete(received_message_future, std::chrono::seconds(10));
});
EXPECT_EQ(ptr, received_message_future.get().get());
EXPECT_EQ(1u, counter);
} else {
// exception expected
EXPECT_THROW(
{
publisher->publish(std::move(msg));
executor.spin_until_future_complete(received_message_future, std::chrono::seconds(10));
}, ExpectedExceptionT);
}
}
/*
This tests the case where a custom allocator is used correctly, i.e. the same
custom allocator on both sides.
*/
TEST(TestIntraProcessManagerWithAllocators, custom_allocator) {
using PublishedMessageAllocatorT = std::allocator<void>;
using PublisherAllocatorT = std::allocator<void>;
using SubscribedMessageAllocatorT = std::allocator<void>;
using SubscriptionAllocatorT = std::allocator<void>;
using MessageMemoryStrategyAllocatorT = std::allocator<void>;
using MemoryStrategyAllocatorT = std::allocator<void>;
auto allocator = std::allocator<void>();
do_custom_allocator_test<
PublishedMessageAllocatorT,
PublisherAllocatorT,
SubscribedMessageAllocatorT,
SubscriptionAllocatorT,
MessageMemoryStrategyAllocatorT,
MemoryStrategyAllocatorT,
void // no exception expected
>(allocator, allocator, allocator, allocator, allocator, allocator);
}
/*
This tests the case where a custom allocator is used incorrectly, i.e. different
custom allocators on both sides.
*/
TEST(TestIntraProcessManagerWithAllocators, custom_allocator_wrong) {
// explicitly use a different allocator here to provoke a failure
using PublishedMessageAllocatorT = std::allocator<void>;
using PublisherAllocatorT = std::allocator<void>;
using SubscribedMessageAllocatorT = MyAllocator<void>;
using SubscriptionAllocatorT = MyAllocator<void>;
using MessageMemoryStrategyAllocatorT = MyAllocator<void>;
using MemoryStrategyAllocatorT = std::allocator<void>;
auto allocator = std::allocator<void>();
auto my_allocator = MyAllocator<void>();
do_custom_allocator_test<
PublishedMessageAllocatorT,
PublisherAllocatorT,
SubscribedMessageAllocatorT,
SubscriptionAllocatorT,
MessageMemoryStrategyAllocatorT,
MemoryStrategyAllocatorT,
std::runtime_error // expected exception
>(allocator, allocator, my_allocator, my_allocator, my_allocator, allocator);
}

View File

@@ -229,12 +229,6 @@ TEST_F(TestLoggingMacros, test_throttle) {
}
}
TEST_F(TestLoggingMacros, test_parameter_expression) {
RCLCPP_DEBUG_STREAM(*&g_logger, "message");
EXPECT_EQ(1u, g_log_calls);
EXPECT_EQ("message", g_last_log_event.message);
}
bool log_function(rclcpp::Logger logger)
{
RCLCPP_INFO(logger, "successful log");

View File

@@ -21,7 +21,6 @@
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/srv/empty.hpp"
@@ -85,13 +84,14 @@ TEST_F(TestMemoryStrategy, get_subscription_by_handle) {
rclcpp::SubscriptionBase::SharedPtr found_subscription = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -131,13 +131,14 @@ TEST_F(TestMemoryStrategy, get_service_by_handle) {
rclcpp::ServiceBase::SharedPtr found_service = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -183,13 +184,14 @@ TEST_F(TestMemoryStrategy, get_client_by_handle) {
rclcpp::ClientBase::SharedPtr found_client = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -230,13 +232,14 @@ TEST_F(TestMemoryStrategy, get_timer_by_handle) {
rclcpp::TimerBase::SharedPtr found_timer = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -278,14 +281,14 @@ TEST_F(TestMemoryStrategy, get_node_by_group) {
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
auto node_handle = node->get_node_base_interface();
rclcpp::node_interfaces::global_for_each_callback_group(
node_handle.get(),
[node_handle, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node_handle->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node_handle](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node_handle));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -322,13 +325,14 @@ TEST_F(TestMemoryStrategy, get_group_by_subscription) {
rclcpp::CallbackGroup::SharedPtr callback_group = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -375,13 +379,14 @@ TEST_F(TestMemoryStrategy, get_group_by_service) {
rclcpp::ServiceBase::SharedPtr service = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -419,13 +424,14 @@ TEST_F(TestMemoryStrategy, get_group_by_client) {
rclcpp::ClientBase::SharedPtr client = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -458,13 +464,14 @@ TEST_F(TestMemoryStrategy, get_group_by_timer) {
rclcpp::TimerBase::SharedPtr timer = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);
@@ -497,13 +504,14 @@ TEST_F(TestMemoryStrategy, get_group_by_waitable) {
rclcpp::Waitable::SharedPtr waitable = nullptr;
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
std::for_each(
callback_groups.begin(), callback_groups.end(),
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
weak_group_ptr,
node->get_node_base_interface()));
});
memory_strategy()->collect_entities(weak_groups_to_nodes);

View File

@@ -99,7 +99,6 @@ TEST_F(TestNode, get_name_and_namespace) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
EXPECT_STREQ("my_node", node->get_name());
EXPECT_STREQ("/ns", node->get_namespace());
EXPECT_STREQ("/ns", node->get_effective_namespace().c_str());
EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name());
}
{
@@ -114,35 +113,30 @@ TEST_F(TestNode, get_name_and_namespace) {
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
EXPECT_STREQ("my_node", node->get_name());
EXPECT_STREQ("/ns", node->get_namespace());
EXPECT_STREQ("/ns", node->get_effective_namespace().c_str());
EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name());
}
{
auto node = std::make_shared<rclcpp::Node>("my_node");
EXPECT_STREQ("my_node", node->get_name());
EXPECT_STREQ("/", node->get_namespace());
EXPECT_STREQ("/", node->get_effective_namespace().c_str());
EXPECT_STREQ("/my_node", node->get_fully_qualified_name());
}
{
auto node = std::make_shared<rclcpp::Node>("my_node", "");
EXPECT_STREQ("my_node", node->get_name());
EXPECT_STREQ("/", node->get_namespace());
EXPECT_STREQ("/", node->get_effective_namespace().c_str());
EXPECT_STREQ("/my_node", node->get_fully_qualified_name());
}
{
auto node = std::make_shared<rclcpp::Node>("my_node", "/my/ns");
EXPECT_STREQ("my_node", node->get_name());
EXPECT_STREQ("/my/ns", node->get_namespace());
EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str());
EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name());
}
{
auto node = std::make_shared<rclcpp::Node>("my_node", "my/ns");
EXPECT_STREQ("my_node", node->get_name());
EXPECT_STREQ("/my/ns", node->get_namespace());
EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str());
EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name());
}
{
@@ -281,13 +275,6 @@ TEST_F(TestNode, subnode_construction_and_destruction) {
auto subnode = node->create_sub_node("~sub_ns");
}, rclcpp::exceptions::InvalidNamespaceError);
}
{
ASSERT_THROW(
{
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto subnode = node->create_sub_node("");
}, rclcpp::exceptions::NameValidationError);
}
}
TEST_F(TestNode, get_logger) {
@@ -346,14 +333,9 @@ TEST_F(TestNode, declare_parameter_with_no_initial_values) {
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
// no default, no initial
const std::string parameter_name = "parameter"_unq;
rclcpp::ParameterValue value = node->declare_parameter(
parameter_name, rclcpp::ParameterValue{}, descriptor);
"parameter"_unq, rclcpp::ParameterValue{}, descriptor);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_NOT_SET);
// Does not throw if unset before access
EXPECT_EQ(
rclcpp::PARAMETER_NOT_SET,
node->get_parameter(parameter_name).get_parameter_value().get_type());
}
{
// int default, no initial
@@ -2655,33 +2637,13 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
TEST_F(TestNode, callback_groups) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
size_t num_callback_groups_in_basic_node = 0;
node->for_each_callback_group(
[&num_callback_groups_in_basic_node](rclcpp::CallbackGroup::SharedPtr group)
{
(void)group;
num_callback_groups_in_basic_node++;
});
size_t num_callback_groups_in_basic_node = node->get_callback_groups().size();
auto group1 = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
size_t num_callback_groups = 0;
node->for_each_callback_group(
[&num_callback_groups](rclcpp::CallbackGroup::SharedPtr group)
{
(void)group;
num_callback_groups++;
});
EXPECT_EQ(1u + num_callback_groups_in_basic_node, num_callback_groups);
EXPECT_EQ(1u + num_callback_groups_in_basic_node, node->get_callback_groups().size());
auto group2 = node->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
size_t num_callback_groups2 = 0;
node->for_each_callback_group(
[&num_callback_groups2](rclcpp::CallbackGroup::SharedPtr group)
{
(void)group;
num_callback_groups2++;
});
EXPECT_EQ(2u + num_callback_groups_in_basic_node, num_callback_groups2);
EXPECT_EQ(2u + num_callback_groups_in_basic_node, node->get_callback_groups().size());
}
// This is tested more thoroughly in node_interfaces/test_node_graph
@@ -2799,20 +2761,9 @@ TEST_F(TestNode, static_and_dynamic_typing) {
EXPECT_EQ("hello!", param);
}
{
auto param = node->declare_parameter("integer_override_not_given", rclcpp::PARAMETER_INTEGER);
EXPECT_EQ(rclcpp::PARAMETER_NOT_SET, param.get_type());
// Throws if not set before access
EXPECT_THROW(
node->get_parameter("integer_override_not_given"),
rclcpp::exceptions::ParameterUninitializedException);
}
{
auto param = node->declare_parameter("integer_set_after_declare", rclcpp::PARAMETER_INTEGER);
EXPECT_EQ(rclcpp::PARAMETER_NOT_SET, param.get_type());
auto result = node->set_parameter(rclcpp::Parameter{"integer_set_after_declare", 44});
ASSERT_TRUE(result.successful) << result.reason;
auto get_param = node->get_parameter("integer_set_after_declare");
EXPECT_EQ(44, get_param.as_int());
node->declare_parameter("integer_override_not_given", rclcpp::PARAMETER_INTEGER),
rclcpp::exceptions::NoParameterOverrideProvided);
}
{
EXPECT_THROW(

View File

@@ -19,7 +19,6 @@
#include <cstdio>
#include <string>
#include <unordered_map>
#include <vector>
#include "rclcpp/parameter_map.hpp"
@@ -354,132 +353,3 @@ TEST(Test_parameter_map_from, string_array_param_value)
c_params->params[0].parameter_values[0].string_array_value = NULL;
rcl_yaml_node_struct_fini(c_params);
}
TEST(Test_parameter_map_from, one_node_one_param_by_node_fqn)
{
rcl_params_t * c_params = make_params({"foo"});
make_node_params(c_params, 0, {"string_param"});
std::string hello_world = "hello world";
char * c_hello_world = new char[hello_world.length() + 1];
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
c_params->params[0].parameter_values[0].string_value = c_hello_world;
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, "/foo");
const std::vector<rclcpp::Parameter> & params = map.at("/foo");
EXPECT_STREQ("string_param", params.at(0).get_name().c_str());
EXPECT_STREQ(hello_world.c_str(), params.at(0).get_value<std::string>().c_str());
c_params->params[0].parameter_values[0].string_value = NULL;
delete[] c_hello_world;
rcl_yaml_node_struct_fini(c_params);
}
TEST(Test_parameter_map_from, multi_nodes_same_param_name_by_node_fqn)
{
std::vector<std::string> node_names_keys = {
"/**", // index: 0
"/*", // index: 1
"/**/node", // index: 2
"/*/node", // index: 3
"/ns/node" // index: 4
};
rcl_params_t * c_params = make_params(node_names_keys);
std::vector<char *> param_values;
for (size_t i = 0; i < node_names_keys.size(); ++i) {
make_node_params(c_params, i, {"string_param"});
std::string hello_world = "hello world" + std::to_string(i);
char * c_hello_world = new char[hello_world.length() + 1];
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
c_params->params[i].parameter_values[0].string_value = c_hello_world;
param_values.push_back(c_hello_world);
}
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
{"/ns/foo/another_node", {0}},
{"/another", {0, 1}},
{"/node", {0, 1, 2}},
{"/another_ns/node", {0, 2, 3}},
{"/ns/node", {0, 2, 3, 4}},
};
for (auto & kv : node_fqn_expected) {
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
EXPECT_EQ(kv.second.size(), params.size());
for (size_t i = 0; i < params.size(); ++i) {
std::string param_value = "hello world" + std::to_string(kv.second[i]);
EXPECT_STREQ("string_param", params.at(i).get_name().c_str());
EXPECT_STREQ(param_value.c_str(), params.at(i).get_value<std::string>().c_str());
}
}
for (size_t i = 0; i < node_names_keys.size(); ++i) {
c_params->params[i].parameter_values[0].string_value = NULL;
}
for (auto c_hello_world : param_values) {
delete[] c_hello_world;
}
rcl_yaml_node_struct_fini(c_params);
}
TEST(Test_parameter_map_from, multi_nodes_diff_param_name_by_node_fqn)
{
std::vector<std::string> node_names_keys = {
"/**", // index: 0
"/*", // index: 1
"/**/node", // index: 2
"/*/node", // index: 3
"/ns/**", // index: 4
"/ns/*", // index: 5
"/ns/**/node", // index: 6
"/ns/*/node", // index: 7
"/ns/**/a/*/node", // index: 8
"/ns/node" // index: 9
};
rcl_params_t * c_params = make_params(node_names_keys);
for (size_t i = 0; i < node_names_keys.size(); ++i) {
std::string param_name = "string_param" + std::to_string(i);
make_node_params(c_params, i, {param_name});
}
std::string hello_world = "hello world";
char * c_hello_world = new char[hello_world.length() + 1];
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
for (size_t i = 0; i < node_names_keys.size(); ++i) {
c_params->params[i].parameter_values[0].string_value = c_hello_world;
}
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
{"/ns/node", {0, 2, 3, 4, 5, 6, 9}},
{"/node", {0, 1, 2}},
{"/ns/foo/node", {0, 2, 4, 6, 7}},
{"/ns/foo/a/node", {0, 2, 4, 6}},
{"/ns/foo/a/bar/node", {0, 2, 4, 6, 8}},
{"/ns/a/bar/node", {0, 2, 4, 6, 8}},
{"/ns/foo/zoo/a/bar/node", {0, 2, 4, 6, 8}},
};
for (auto & kv : node_fqn_expected) {
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
EXPECT_EQ(kv.second.size(), params.size());
for (size_t i = 0; i < params.size(); ++i) {
std::string param_name = "string_param" + std::to_string(kv.second[i]);
EXPECT_STREQ(param_name.c_str(), params.at(i).get_name().c_str());
EXPECT_STREQ(hello_world.c_str(), params.at(i).get_value<std::string>().c_str());
}
}
for (size_t i = 0; i < node_names_keys.size(); ++i) {
c_params->params[i].parameter_values[0].string_value = NULL;
}
delete[] c_hello_world;
rcl_yaml_node_struct_fini(c_params);
}

View File

@@ -1,74 +0,0 @@
// Copyright 2021 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 <memory>
#include <string>
#include <vector>
#include "rclcpp/node.hpp"
#include "rclcpp/wait_for_message.hpp"
#include "test_msgs/msg/strings.hpp"
#include "test_msgs/message_fixtures.hpp"
using namespace std::chrono_literals;
TEST(TestUtilities, wait_for_message) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("wait_for_message_node");
using MsgT = test_msgs::msg::Strings;
auto pub = node->create_publisher<MsgT>("wait_for_message_topic", 10);
MsgT out;
auto received = false;
auto wait = std::async(
[&]() {
auto ret = rclcpp::wait_for_message(out, node, "wait_for_message_topic", 5s);
EXPECT_TRUE(ret);
received = true;
});
for (auto i = 0u; i < 10 && received == false; ++i) {
pub->publish(*get_messages_strings()[0]);
std::this_thread::sleep_for(1s);
}
ASSERT_TRUE(received);
EXPECT_EQ(out, *get_messages_strings()[0]);
rclcpp::shutdown();
}
TEST(TestUtilities, wait_for_message_indefinitely) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("wait_for_message_node2");
using MsgT = test_msgs::msg::Strings;
MsgT out;
auto received = false;
auto wait = std::async(
[&]() {
auto ret = rclcpp::wait_for_message(out, node, "wait_for_message_topic" /*, -1 */);
EXPECT_TRUE(ret);
received = true;
});
rclcpp::shutdown();
ASSERT_FALSE(received);
}

View File

@@ -1,5 +0,0 @@
/**/foo/*/bar:
node2:
ros__parameters:
foo: "foo"
bar: "bar"

View File

@@ -1,16 +0,0 @@
/**:
node2:
ros__parameters:
a_value: "first"
foo: "foo"
/ns:
node2:
ros__parameters:
a_value: "second"
bar: "bar"
/*:
node2:
ros__parameters:
a_value: "last_one_win"

View File

@@ -1,57 +0,0 @@
/**:
ros__parameters:
full_wild: "full_wild"
/**:
node2:
ros__parameters:
namespace_wild: "namespace_wild"
/**/node2:
ros__parameters:
namespace_wild_another: "namespace_wild_another"
/*:
node2:
ros__parameters:
namespace_wild_one_star: "namespace_wild_one_star"
ns:
"*":
ros__parameters:
node_wild_in_ns: "node_wild_in_ns"
/ns/*:
ros__parameters:
node_wild_in_ns_another: "node_wild_in_ns_another"
ns:
node2:
ros__parameters:
explicit_in_ns: "explicit_in_ns"
"*":
ros__parameters:
node_wild_no_ns: "node_wild_no_ns"
node2:
ros__parameters:
explicit_no_ns: "explicit_no_ns"
ns:
nodeX:
ros__parameters:
should_not_appear: "incorrect_node_name"
/**/nodeX:
ros__parameters:
should_not_appear: "incorrect_node_name"
nsX:
node2:
ros__parameters:
should_not_appear: "incorrect_namespace"
/nsX/*:
ros__parameters:
should_not_appear: "incorrect_namespace"

View File

@@ -3,29 +3,6 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9.2.2 (2022-12-06)
------------------
9.2.1 (2022-04-28)
------------------
9.2.0 (2021-09-17)
------------------
* Fixed a bug where it would occasionally miss a goal result, which was caused by race condition (`#1677 <https://github.com/ros2/rclcpp/issues/1677>`_) (`#1683 <https://github.com/ros2/rclcpp/issues/1683>`_)
* Co-authored-by: Kaven Yau <kavenyau@foxmail.com>
* Contributors: Tomoya Fujita
9.1.0 (2021-05-20)
------------------
* Bump the benchmark timeout for benchmark_action_client (`#1672 <https://github.com/ros2/rclcpp/issues/1672>`_)
* Contributors: Scott K Logan
9.0.3 (2021-05-10)
------------------
* Returns CancelResponse::REJECT while goal handle failed to transit to CANCELING state (`#1641 <https://github.com/ros2/rclcpp/issues/1641>`_) (`#1653 <https://github.com/ros2/rclcpp/issues/1653>`_)
* Fix action server deadlock issue that caused by other mutexes locked in CancelCallback (`#1635 <https://github.com/ros2/rclcpp/issues/1635>`_) (`#1646 <https://github.com/ros2/rclcpp/issues/1646>`_)
* Contributors: Jacob Perron, Kaven Yau, William Woodall
9.0.2 (2021-04-14)
------------------

View File

@@ -356,26 +356,15 @@ protected:
CancelResponse
call_handle_cancel_callback(const GoalUUID & uuid) override
{
std::shared_ptr<ServerGoalHandle<ActionT>> goal_handle;
{
std::lock_guard<std::mutex> lock(goal_handles_mutex_);
auto element = goal_handles_.find(uuid);
if (element != goal_handles_.end()) {
goal_handle = element->second.lock();
}
}
std::lock_guard<std::mutex> lock(goal_handles_mutex_);
CancelResponse resp = CancelResponse::REJECT;
if (goal_handle) {
resp = handle_cancel_(goal_handle);
if (CancelResponse::ACCEPT == resp) {
try {
auto element = goal_handles_.find(uuid);
if (element != goal_handles_.end()) {
std::shared_ptr<ServerGoalHandle<ActionT>> goal_handle = element->second.lock();
if (goal_handle) {
resp = handle_cancel_(goal_handle);
if (CancelResponse::ACCEPT == resp) {
goal_handle->_cancel_goal();
} catch (const rclcpp::exceptions::RCLError & ex) {
RCLCPP_DEBUG(
rclcpp::get_logger("rclcpp_action"),
"Failed to cancel goal in call_handle_cancel_callback: %s", ex.what());
return CancelResponse::REJECT;
}
}
}

View File

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

View File

@@ -500,13 +500,9 @@ ServerBase::execute_result_request_received(std::shared_ptr<void> & data)
result_response = create_result_response(action_msgs::msg::GoalStatus::STATUS_UNKNOWN);
} else {
// Goal exists, check if a result is already available
std::lock_guard<std::recursive_mutex> lock(pimpl_->unordered_map_mutex_);
auto iter = pimpl_->goal_results_.find(uuid);
if (iter != pimpl_->goal_results_.end()) {
result_response = iter->second;
} else {
// Store the request so it can be responded to later
pimpl_->result_requests_[uuid].push_back(request_header);
}
}
@@ -518,6 +514,10 @@ ServerBase::execute_result_request_received(std::shared_ptr<void> & data)
if (RCL_RET_OK != rcl_ret) {
rclcpp::exceptions::throw_from_rcl_error(rcl_ret);
}
} else {
// Store the request so it can be responded to later
std::lock_guard<std::recursive_mutex> lock(pimpl_->unordered_map_mutex_);
pimpl_->result_requests_[uuid].push_back(request_header);
}
data.reset();
}
@@ -627,30 +627,19 @@ ServerBase::publish_result(const GoalUUID & uuid, std::shared_ptr<void> result_m
}
{
/**
* NOTE: There is a potential deadlock issue if both unordered_map_mutex_ and
* action_server_reentrant_mutex_ locked in other block scopes. Unless using
* std::scoped_lock, locking order must be consistent with the current.
*
* Current locking order:
*
* 1. unordered_map_mutex_
* 2. action_server_reentrant_mutex_
*
*/
std::lock_guard<std::recursive_mutex> unordered_map_lock(pimpl_->unordered_map_mutex_);
std::lock_guard<std::recursive_mutex> lock(pimpl_->unordered_map_mutex_);
pimpl_->goal_results_[uuid] = result_msg;
}
// if there are clients who already asked for the result, send it to them
auto iter = pimpl_->result_requests_.find(uuid);
if (iter != pimpl_->result_requests_.end()) {
// if there are clients who already asked for the result, send it to them
auto iter = pimpl_->result_requests_.find(uuid);
if (iter != pimpl_->result_requests_.end()) {
for (auto & request_header : iter->second) {
std::lock_guard<std::recursive_mutex> lock(pimpl_->action_server_reentrant_mutex_);
for (auto & request_header : iter->second) {
rcl_ret_t ret = rcl_action_send_result_response(
pimpl_->action_server_.get(), &request_header, result_msg.get());
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
rcl_ret_t ret = rcl_action_send_result_response(
pimpl_->action_server_.get(), &request_header, result_msg.get());
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
}

View File

@@ -7,7 +7,7 @@ find_package(performance_test_fixture REQUIRED)
add_performance_test(
benchmark_action_client
benchmark_action_client.cpp
TIMEOUT 240)
TIMEOUT 120)
if(TARGET benchmark_action_client)
target_link_libraries(benchmark_action_client ${PROJECT_NAME})
ament_target_dependencies(benchmark_action_client rclcpp test_msgs)

View File

@@ -1306,15 +1306,3 @@ TEST_F(TestDeadlockServer, deadlock_while_canceled)
send_goal_request(node_, uuid2_); // deadlock here
t.join();
}
TEST_F(TestDeadlockServer, deadlock_while_succeed_and_canceled)
{
send_goal_request(node_, uuid1_);
std::thread t(&TestDeadlockServer::GoalSucceeded, this);
rclcpp::sleep_for(std::chrono::milliseconds(50));
auto response_ptr = send_cancel_request(node_, uuid1_);
// current goal handle is not cancelable, so it returns ERROR_REJECTED
EXPECT_EQ(CancelResponse::ERROR_REJECTED, response_ptr->return_code);
t.join();
}

View File

@@ -2,21 +2,6 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9.2.2 (2022-12-06)
------------------
9.2.1 (2022-04-28)
------------------
9.2.0 (2021-09-17)
------------------
9.1.0 (2021-05-20)
------------------
9.0.3 (2021-05-10)
------------------
9.0.2 (2021-04-14)
------------------

View File

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

View File

@@ -3,25 +3,6 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9.2.2 (2022-12-06)
------------------
9.2.1 (2022-04-28)
------------------
9.2.0 (2021-09-17)
------------------
* Added thread safe for_each_callback_group method (`#1741 <https://github.com/ros2/rclcpp/issues/1741>`_)
* Contributors: Aditya Pande
9.1.0 (2021-05-20)
------------------
* Fix destruction order in lifecycle benchmark (`#1676 <https://github.com/ros2/rclcpp/issues/1676>`_)
* Contributors: Scott K Logan
9.0.3 (2021-05-10)
------------------
9.0.2 (2021-04-14)
------------------

View File

@@ -200,18 +200,6 @@ public:
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
get_callback_groups() const;
/// Iterate over the callback groups in the node, calling the given function on each valid one.
/**
* This method is called in a thread-safe way, and also makes sure to only call the given
* function on those items that are still valid.
*
* \param[in] func The callback function to call on each valid callback group.
*/
RCLCPP_LIFECYCLE_PUBLIC
void
for_each_callback_group(
const rclcpp::node_interfaces::NodeBaseInterface::CallbackGroupFunction & func);
/// Create and return a Publisher.
/**
* \param[in] topic_name The topic for this publisher to publish on.

View File

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

View File

@@ -651,11 +651,4 @@ LifecycleNode::add_timer_handle(std::shared_ptr<rclcpp::TimerBase> timer)
impl_->add_timer_handle(timer);
}
void
LifecycleNode::for_each_callback_group(
const rclcpp::node_interfaces::NodeBaseInterface::CallbackGroupFunction & func)
{
rclcpp::node_interfaces::global_for_each_callback_group(node_base_.get(), func);
}
} // namespace rclcpp_lifecycle

View File

@@ -212,9 +212,8 @@ public:
performance_test_fixture::PerformanceTest::TearDown(state);
executor->cancel();
spinner_.join();
executor.reset();
lifecycle_client.reset();
lifecycle_node.reset();
lifecycle_client.reset();
rclcpp::shutdown();
}

View File

@@ -717,27 +717,16 @@ TEST_F(TestDefaultStateMachine, test_graph_services_by_node) {
TEST_F(TestDefaultStateMachine, test_callback_groups) {
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
size_t num_groups = 0;
test_node->for_each_callback_group(
[&num_groups](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
(void)group_ptr;
num_groups++;
});
EXPECT_EQ(num_groups, 1u);
auto groups = test_node->get_callback_groups();
EXPECT_EQ(groups.size(), 1u);
auto group = test_node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive, true);
EXPECT_NE(nullptr, group);
num_groups = 0;
test_node->for_each_callback_group(
[&num_groups](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
(void)group_ptr;
num_groups++;
});
EXPECT_EQ(num_groups, 2u);
groups = test_node->get_callback_groups();
EXPECT_EQ(groups.size(), 2u);
EXPECT_EQ(groups[1].lock().get(), group.get());
}
TEST_F(TestDefaultStateMachine, wait_for_graph_change)