Compare commits
1 Commits
fix_wait_s
...
rcl_alloca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
952e22e087 |
@@ -2,26 +2,6 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
* Allow declare uninitialized parameters (`#1673 <https://github.com/ros2/rclcpp/issues/1673>`_)
|
||||
* Fix syntax issue with gcc (`#1674 <https://github.com/ros2/rclcpp/issues/1674>`_)
|
||||
* [service] Don't use a weak_ptr to avoid leaking (`#1668 <https://github.com/ros2/rclcpp/issues/1668>`_)
|
||||
* Contributors: Ivan Santiago Paunovic, Jacob Perron, William Woodall
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
* Fix doc typo (`#1663 <https://github.com/ros2/rclcpp/issues/1663>`_)
|
||||
* [rclcpp] Type Adaptation feature (`#1557 <https://github.com/ros2/rclcpp/issues/1557>`_)
|
||||
* Do not attempt to use void allocators for memory allocation. (`#1657 <https://github.com/ros2/rclcpp/issues/1657>`_)
|
||||
* Keep custom allocator in publisher and subscription options alive. (`#1647 <https://github.com/ros2/rclcpp/issues/1647>`_)
|
||||
* Fix get_publishers_subscriptions_info_by_topic test in test_node.cpp (`#1648 <https://github.com/ros2/rclcpp/issues/1648>`_)
|
||||
* Use OnShutdown callback handle instead of OnShutdown callback (`#1639 <https://github.com/ros2/rclcpp/issues/1639>`_)
|
||||
* use dynamic_pointer_cast to detect allocator mismatch in intra process manager (`#1643 <https://github.com/ros2/rclcpp/issues/1643>`_)
|
||||
* 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: Audrow Nash, 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>`_)
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
# Architecture of the rclcpp::WaitSet Type
|
||||
|
||||
The `rclcpp::WaitSet` type is actually a specific configuration of a the more general `rclcpp::WaitSetTemplate` class.
|
||||
|
||||
The `rclcpp::WaitSetTemplate` class is design to have interchangeable implementations for controlling storage of items in the wait set, as well as to control access to the wait set functionality, i.e. whether or not it has thread-safety.
|
||||
|
||||
In general the idea behind a wait set in rclcpp is that you gather a set of entities that can be waited on, e.g. subscriptions, timers, guard conditions, and then wait for one or more of them to be ready.
|
||||
These things are driven by asynchronous events, e.g. subscriptions become ready when new data arrives or timers become ready when their period has elapsed.
|
||||
|
||||
At the moment, things that can be waited on are limited by what can be put into an `rcl_wait_set_t`, which includes subscriptions, service clients, service servers, timers, guard conditions, and events.
|
||||
In this context events are QoS events, as defined in the `rcl` and `rmw` interfaces.
|
||||
|
||||
## Design Goals
|
||||
|
||||
There are some design goals for the `rclcpp::WaitSet` family of classes:
|
||||
|
||||
- minimize inheritance and avoid virtual functions
|
||||
- Overhead of the executor and wait set design have been a common complaint and are often blamed for performance issues.
|
||||
- Since the wait set is at the core of the wait-do loop of the system, aggressive optimization can actually pay off.
|
||||
- avoid unnecessary changes to the underlying `rcl_wait_set_t` instances or unnecessarily recreating it
|
||||
- This can be expensive, because under the hood that requires changes to the middleware's object, e.g. a DDS wait set or similar.
|
||||
- minimize memory allocations in the wait() function, avoid them entirely if the set of things to wait on has not changed
|
||||
- prevent accidentally using an entity with more than wait set at the same time
|
||||
|
||||
Several of these surround performance concerns, but others are concerned with safety and convenience for the user.
|
||||
|
||||
## Architecture
|
||||
|
||||
The `rclcpp::WaitSetTemplate` is the core fixture in the feature, which is using a policy-based design (see https://en.wikipedia.org/wiki/Modern_C%2B%2B_Design#Policy-based_design).
|
||||
|
||||
It delegates storage and synchronization to policy template arguments to the `rclcpp::WaitSetTemplate` via the `StoragePolicy` and `SynchronizationPolicy` template arguments respectively.
|
||||
|
||||
These policies can be mixed and matched to achieve different results.
|
||||
There are a few predefined combinations, `rclcpp::WaitSet` which is a non-thread-safe wait set with dynamic storage, `rclcpp::StaticWaitSet` which is a non-thread-safe wait set with fixed storage, and `rclcpp::ThreadSafeWaitSet` which is a thread-safe wait set with dynamic storage.
|
||||
They are all just aliases to `rclcpp::WaitSetTemplate` with difference combinations of policies.
|
||||
|
||||
Users can extend the behavior by implementing their own policies if desired.
|
||||
|
||||
This kind of design allows for specialization and code sharing without using standard polymorphism via virtual functions, and the benefit of that is that calls on the wait set class are always non-virtual, avoiding dispatching via the v-table.
|
||||
It also forces us to use templates, which means a head-only implementation, which will increase compile times, but will avoid some calls to shared libraries which on some systems has a small overhead too.
|
||||
|
||||
These are aggressive optimizations, but it can actually be very beneficial in the inner-loop of applications, and the hope is that this approach will offer the best performance we can achieve.
|
||||
|
||||
### StoragePolicy
|
||||
|
||||
The storage policy is responsible for storing the entities in the wait set and providing accessors and setters (if appropriate).
|
||||
|
||||
The storage policy is also responsible for maintaining ownership of the entities it is storing at the right times.
|
||||
For example, entities are always given to the wait set as `std::shared_ptr`'s and some policies might only maintain ownership for the lifetime of the wait set or until the entity is removed.
|
||||
Other policies might only hold ownership of the entities while waiting on them, i.e. while they are actively using them, but maintain only weak ownership otherwise.
|
||||
|
||||
There are two built-in storage policies available, the `rclcpp::wait_set_policies::DynamicStorage` and the `rclcpp::wait_set_policies::StaticStorage<...>` classes.
|
||||
|
||||
The `StaticStorage` policy requires that you fully specify the number of entities of each time that can be stored as template arguments and uses the `std:array` class as backing storage.
|
||||
Therefore, it also does not allow adding or removing entities after construction.
|
||||
Because entities cannot be removed and are therefore "always" in use by the wait set, it maintains shared ownership of the entities for the lifetime of the wait set.
|
||||
|
||||
The `DynamicStorage` policy provides access to the entities and allows add and removing entities at any time after construction.
|
||||
It also only maintains shared ownership of the entities while actively waiting on them, which allows the entities to go out of scope while the wait set is idle.
|
||||
Entities that go out of scope in this manner will be removed from the wait set when it notices their weak pointers no longer lock to the entity's shared pointer.
|
||||
|
||||
Both policies allow you to initialize the wait set with entities in the constructor.
|
||||
|
||||
### SynchronizationPolicy
|
||||
|
||||
The synchronization policy is responsible for synchronizing access to wait set operations that share access to the StoragePolicy.
|
||||
|
||||
There are two built-in synchronization policies available, the `rclcpp::wait_set_policies::SequentialSynchronization` and the `rclcpp::wait_set_policies::ThreadSafeSynchronization` policies.
|
||||
|
||||
The `rclcpp::wait_set_policies::SequentialSynchronization` policy essentially does nothing but pass through requests from the user-facing `rclcpp::WaitSetTemplate` interface to the `StoragePolicy` that is being used.
|
||||
|
||||
The `rclcpp::wait_set_policies::ThreadSafeSynchronization` policy sequences access to the `StoragePolicy` being used so that it is safe to call methods like `add_subscription()` on the wait set while it is doing something else, like waiting with the `wait()` method.
|
||||
This synchronization comes at the expense of using mutexes and extra logic to organize the access, but provides some thread-safety.
|
||||
|
||||
### Entity Intake and Management
|
||||
|
||||
Entities, i.e. `rclcpp::SubscriptionBase`, `rclcpp::Waitable`, `rclcpp::ClientBase`, `rclcpp::ServiceBase`, `rclcpp::TimerBase`, `rclcpp::GuardCondition`, etc., may be passed to the wait set during construction.
|
||||
If the wait set has policies that allow for dynamic storage and supports adding and removing entities after construction, then entities can also be added and removed using method on the wait set.
|
||||
|
||||
Either way, the entities are initially given to the wait set as a `std::shared_ptr` in order to maintain shared ownership, but depending on the storage policy it may be stored as a `std::weak_ptr` while the wait set is not actively using the entities.
|
||||
|
||||
Also, when taking on new entities the wait set is responsible for ensuring that entity is not being used by another wait set (at least another instance of `rclcpp::WaitSetTemplate`).
|
||||
|
||||
One more thing that plays into intake of entities is that a few entity types have some extra requirements, specifically subscriptions and waitables.
|
||||
|
||||
Subscriptions (specifically `rclcpp::SubscriptionBase`) are complex objects that contain not only a subscription that can be waited on, but also may have `rclcpp::Waitable`'s inside in order to implement intra-process communication and for QoS events that are also implemented as `rclcpp::Waitable` instances.
|
||||
Therefore, you need a way to say which parts of the subscription should be added to the wait set, because you don't need to add all the entities that make up a subscription to a single wait set.
|
||||
The `rclcpp::SubscriptionWaitSetMask` class provides this mapping, and when adding subscriptions to a wait set you need to provide the subscription shared pointer as well as a mask instance.
|
||||
|
||||
Waitables are complicated by the fact that they often are part of a larger piece of the API, as we saw with subscriptions, and therefore the waitable may need to keep additional things in scope while being used.
|
||||
So when adding a waitable to a wait set you may also provide an "associated entity" as a shared pointer to void, which is purely there to keep something in scope along with the waitable.
|
||||
|
||||
#### EntityEntry classes
|
||||
|
||||
In order to address the need to pair extra information with some entities (e.g. the subscription mask with the subscription entity) and to provide a convenient place to check if the entity is in use by another wait set and claim if not.
|
||||
|
||||
There are a series of classes that are a variation of the `EntityEntry` concept, which wrap the incoming entities and their associated data into a single class, and also provide some safety when converting between the shared ownership and weak ownership if needed.
|
||||
|
||||
They also provide RAII-style checking about whether or not an entity is already associated with a wait set.
|
||||
This is important because when ingesting multiple entities at the same time, e.g. via the constructor, because if you claim the first few entities to be associated with the wait set, but then find one that is already associated, then you need to abort and throw an exception.
|
||||
The RAII-style of these classes addresses this by "dissociating" the first few entities from the wait set when going out of scope due to the thrown exception.
|
||||
|
||||
The process from intake to cleanup of the entity entries follows something like this, using waitables as an example:
|
||||
|
||||
|
||||
|
||||
┌───────────────┐
|
||||
┌────────────────────────┐ │ WaitSet │
|
||||
│ ├──────►│ ├───────────────┐
|
||||
│ shared_ptr<Waitable> │ │ constructor │ │
|
||||
│ │ └───────────────┘ Implicit │
|
||||
│ and optional │ │
|
||||
│ │ ┌───────────────┐ Conversion │
|
||||
│ shared_ptr<void> │ │ add_waitable()│ │
|
||||
│ ├──────►│ ├───────────────┤
|
||||
└────────────────────────┘ │ method │ │
|
||||
└───────────────┘ │
|
||||
│
|
||||
│
|
||||
│
|
||||
┌──────────────────────┐ ┌─────────────────┐ │
|
||||
│ │ │ │ │
|
||||
┌─────┤ ManagedWaitableEntry │◄──┬────┤ WaitableEntry │◄──────┘
|
||||
│ │ │ │ │ │
|
||||
│ └─┬──────────────────┬─┘ │ └─┬─────────────┬─┘
|
||||
│ │ shared_ptr+RAII │ │ │ shared_ptr │
|
||||
│ └──────────────────┘ │ └─────────────┘
|
||||
│ │
|
||||
│ ┌───────┴───────────┐
|
||||
│ │Check that entity │
|
||||
│ Conversion to │is not in use, then│
|
||||
│ weak ownership │claim it for this │
|
||||
│ if needed. │wait set. │
|
||||
│ └───────────────────┘
|
||||
│
|
||||
│ ┌───────────────────────────┐
|
||||
│ │ │
|
||||
└────►│ WeakManagedWaitableEntry │
|
||||
│ │
|
||||
└─┬───────────────────────┬─┘
|
||||
│ weak_ptr + RAII │
|
||||
└───────────────────────┘
|
||||
|
||||
Using the diagram as a reference, you can see that the input from the user is converted into the entity entry class that, for now, just stores the entity and any associated data if it exists.
|
||||
At this point the entity comes in with shared ownership and stays as shared ownership in the basic entry class.
|
||||
Then this entry class is converted into a "managed" entry class, which will check that the entity is not associated with another wait set and associate it with the current wait set during construction.
|
||||
This managed entry class will also automatically disassociate the entity with the current wait set during destruction.
|
||||
The new managed entry class continues to keep shared ownership of the entity.
|
||||
|
||||
Optionally, if the storage policy requires it, the managed entry class can be converted into a "weak" version, where in the entity is stored as a weak pointer instead of a shared pointer.
|
||||
In this case the entity will remain stored as a "weak managed" entry until it is removed or the wait set is destroyed.
|
||||
In the meantime, if the wait set needs to take shared ownership again, it can do that be getting a copy of the weak pointer(s) in the entry and locking them to get shared pointers.
|
||||
But the weak managed entry remains responsible for the RAII-style dissociation from the current wait set when destroyed.
|
||||
Unlike the managed entry that maintains shared ownership, the weak version will need to attempt to lock the weak pointer for the entity before trying to dissociate it from the wait set, because this association is maintained within the entity itself, through methods like `rclcpp::Waitable::exchange_in_use_by_wait_set_state()`.
|
||||
If the entity cannot be accessed via the weak pointer, then it is not explicitly dissociated by the managed entry, but it doesn't matter because the object has gone out of scope and has been deleted anyway.
|
||||
So the cleanup for the weak managed entry is best effort, but that does not pose an issue.
|
||||
|
||||
#### The EntityEntryTemplate classes
|
||||
|
||||
There is a template class called `rclcpp::wait_set_policies::detail::EntityEntryTemplate<EntityT>` (and associated managed and weak-managed versions) which is the foundation for most of the entity types which don't require special handling, like `rclcpp::GuardCondition` and `rclcpp::TimerBase` for example.
|
||||
Other entities like `rclcpp::SubscriptionBase` and `rclcpp::Waitable` have custom specializations of these classes to handle extra storage, custom constructors, and other extra logic to help them work.
|
||||
@@ -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_
|
||||
|
||||
@@ -95,7 +95,7 @@ void set_allocator_for_deleter(AllocatorDeleter<T> * deleter, Alloc * alloc)
|
||||
template<typename Alloc, typename T>
|
||||
using Deleter = typename std::conditional<
|
||||
std::is_same<typename std::allocator_traits<Alloc>::template rebind_alloc<T>,
|
||||
std::allocator<T>>::value,
|
||||
typename std::allocator<void>::template rebind<T>::other>::value,
|
||||
std::default_delete<T>,
|
||||
AllocatorDeleter<Alloc>
|
||||
>::type;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <utility>
|
||||
#include <variant> // NOLINT[build/include_order]
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
#include "tracetools/utils.hpp"
|
||||
|
||||
@@ -30,9 +29,6 @@
|
||||
#include "rclcpp/detail/subscription_callback_type_helper.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/message_info.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
@@ -46,189 +42,53 @@ namespace detail
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct MessageDeleterHelper
|
||||
{
|
||||
using AllocTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using Alloc = typename AllocTraits::allocator_type;
|
||||
using Deleter = allocator::Deleter<Alloc, MessageT>;
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
|
||||
};
|
||||
|
||||
/// Struct which contains all possible callback signatures, with or without a TypeAdapter.s
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackPossibleTypes
|
||||
struct AnySubscriptionCallbackHelper
|
||||
{
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using SubscribedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
|
||||
|
||||
using SubscribedMessageDeleter =
|
||||
typename MessageDeleterHelper<SubscribedType, AllocatorT>::Deleter;
|
||||
using ROSMessageDeleter =
|
||||
typename MessageDeleterHelper<ROSMessageType, AllocatorT>::Deleter;
|
||||
using SerializedMessageDeleter =
|
||||
typename MessageDeleterHelper<rclcpp::SerializedMessage, AllocatorT>::Deleter;
|
||||
using MessageDeleter = typename MessageDeleterHelper<MessageT, AllocatorT>::MessageDeleter;
|
||||
|
||||
using ConstRefCallback =
|
||||
std::function<void (const SubscribedType &)>;
|
||||
using ConstRefROSMessageCallback =
|
||||
std::function<void (const ROSMessageType &)>;
|
||||
std::function<void (const MessageT &)>;
|
||||
using ConstRefWithInfoCallback =
|
||||
std::function<void (const SubscribedType &, const rclcpp::MessageInfo &)>;
|
||||
using ConstRefWithInfoROSMessageCallback =
|
||||
std::function<void (const ROSMessageType &, const rclcpp::MessageInfo &)>;
|
||||
using ConstRefSerializedMessageCallback =
|
||||
std::function<void (const rclcpp::SerializedMessage &)>;
|
||||
using ConstRefSerializedMessageWithInfoCallback =
|
||||
std::function<void (const rclcpp::SerializedMessage &, const rclcpp::MessageInfo &)>;
|
||||
std::function<void (const MessageT &, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using UniquePtrCallback =
|
||||
std::function<void (std::unique_ptr<SubscribedType, SubscribedMessageDeleter>)>;
|
||||
using UniquePtrROSMessageCallback =
|
||||
std::function<void (std::unique_ptr<ROSMessageType, ROSMessageDeleter>)>;
|
||||
std::function<void (std::unique_ptr<MessageT, MessageDeleter>)>;
|
||||
using UniquePtrWithInfoCallback =
|
||||
std::function<void (
|
||||
std::unique_ptr<SubscribedType, SubscribedMessageDeleter>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using UniquePtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
std::unique_ptr<ROSMessageType, ROSMessageDeleter>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using UniquePtrSerializedMessageCallback =
|
||||
std::function<void (std::unique_ptr<rclcpp::SerializedMessage, SerializedMessageDeleter>)>;
|
||||
using UniquePtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (
|
||||
std::unique_ptr<rclcpp::SerializedMessage, SerializedMessageDeleter>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
std::function<void (std::unique_ptr<MessageT, MessageDeleter>, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using SharedConstPtrCallback =
|
||||
std::function<void (std::shared_ptr<const SubscribedType>)>;
|
||||
using SharedConstPtrROSMessageCallback =
|
||||
std::function<void (std::shared_ptr<const ROSMessageType>)>;
|
||||
std::function<void (std::shared_ptr<const MessageT>)>;
|
||||
using SharedConstPtrWithInfoCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<const SubscribedType>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using SharedConstPtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<const ROSMessageType>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using SharedConstPtrSerializedMessageCallback =
|
||||
std::function<void (std::shared_ptr<const rclcpp::SerializedMessage>)>;
|
||||
using SharedConstPtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<const rclcpp::SerializedMessage>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
std::function<void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using ConstRefSharedConstPtrCallback =
|
||||
std::function<void (const std::shared_ptr<const SubscribedType> &)>;
|
||||
using ConstRefSharedConstPtrROSMessageCallback =
|
||||
std::function<void (const std::shared_ptr<const ROSMessageType> &)>;
|
||||
std::function<void (const std::shared_ptr<const MessageT> &)>;
|
||||
using ConstRefSharedConstPtrWithInfoCallback =
|
||||
std::function<void (
|
||||
const std::shared_ptr<const SubscribedType> &,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using ConstRefSharedConstPtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
const std::shared_ptr<const ROSMessageType> &,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using ConstRefSharedConstPtrSerializedMessageCallback =
|
||||
std::function<void (const std::shared_ptr<const rclcpp::SerializedMessage> &)>;
|
||||
using ConstRefSharedConstPtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (
|
||||
const std::shared_ptr<const rclcpp::SerializedMessage> &,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
std::function<void (const std::shared_ptr<const MessageT> &, const rclcpp::MessageInfo &)>;
|
||||
|
||||
// Deprecated signatures:
|
||||
using SharedPtrCallback =
|
||||
std::function<void (std::shared_ptr<SubscribedType>)>;
|
||||
using SharedPtrROSMessageCallback =
|
||||
std::function<void (std::shared_ptr<ROSMessageType>)>;
|
||||
std::function<void (std::shared_ptr<MessageT>)>;
|
||||
using SharedPtrWithInfoCallback =
|
||||
std::function<void (std::shared_ptr<SubscribedType>, const rclcpp::MessageInfo &)>;
|
||||
using SharedPtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<ROSMessageType>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using SharedPtrSerializedMessageCallback =
|
||||
std::function<void (std::shared_ptr<rclcpp::SerializedMessage>)>;
|
||||
using SharedPtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (std::shared_ptr<rclcpp::SerializedMessage>, const rclcpp::MessageInfo &)>;
|
||||
};
|
||||
|
||||
/// Template helper to select the variant type based on whether or not MessageT is a TypeAdapter.
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT,
|
||||
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value
|
||||
>
|
||||
struct AnySubscriptionCallbackHelper;
|
||||
|
||||
/// Specialization for when MessageT is not a TypeAdapter.
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
|
||||
{
|
||||
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
std::function<void (std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using variant_type = std::variant<
|
||||
typename CallbackTypes::ConstRefCallback,
|
||||
typename CallbackTypes::ConstRefWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrCallback,
|
||||
typename CallbackTypes::UniquePtrWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrCallback,
|
||||
typename CallbackTypes::SharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrCallback,
|
||||
typename CallbackTypes::SharedPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback
|
||||
>;
|
||||
};
|
||||
|
||||
/// Specialization for when MessageT is a TypeAdapter.
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
|
||||
{
|
||||
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
|
||||
using variant_type = std::variant<
|
||||
typename CallbackTypes::ConstRefCallback,
|
||||
typename CallbackTypes::ConstRefROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrCallback,
|
||||
typename CallbackTypes::UniquePtrROSMessageCallback,
|
||||
typename CallbackTypes::UniquePtrWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrCallback,
|
||||
typename CallbackTypes::SharedConstPtrROSMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrCallback,
|
||||
typename CallbackTypes::SharedPtrROSMessageCallback,
|
||||
typename CallbackTypes::SharedPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback
|
||||
ConstRefCallback,
|
||||
ConstRefWithInfoCallback,
|
||||
UniquePtrCallback,
|
||||
UniquePtrWithInfoCallback,
|
||||
SharedConstPtrCallback,
|
||||
SharedConstPtrWithInfoCallback,
|
||||
ConstRefSharedConstPtrCallback,
|
||||
ConstRefSharedConstPtrWithInfoCallback,
|
||||
SharedPtrCallback,
|
||||
SharedPtrWithInfoCallback
|
||||
>;
|
||||
};
|
||||
|
||||
@@ -241,124 +101,49 @@ template<
|
||||
class AnySubscriptionCallback
|
||||
{
|
||||
private:
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using SubscribedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
|
||||
|
||||
using HelperT = typename rclcpp::detail::AnySubscriptionCallbackHelper<MessageT, AllocatorT>;
|
||||
using MessageDeleterHelper = rclcpp::detail::MessageDeleterHelper<MessageT, AllocatorT>;
|
||||
|
||||
using SubscribedTypeDeleterHelper =
|
||||
rclcpp::detail::MessageDeleterHelper<SubscribedType, AllocatorT>;
|
||||
using SubscribedTypeAllocatorTraits = typename SubscribedTypeDeleterHelper::AllocTraits;
|
||||
using SubscribedTypeAllocator = typename SubscribedTypeDeleterHelper::Alloc;
|
||||
using SubscribedTypeDeleter = typename SubscribedTypeDeleterHelper::Deleter;
|
||||
using MessageAllocTraits = typename MessageDeleterHelper::MessageAllocTraits;
|
||||
using MessageAlloc = typename MessageDeleterHelper::MessageAlloc;
|
||||
using MessageDeleter = typename MessageDeleterHelper::MessageDeleter;
|
||||
|
||||
using ROSMessageTypeDeleterHelper =
|
||||
rclcpp::detail::MessageDeleterHelper<ROSMessageType, AllocatorT>;
|
||||
using ROSMessageTypeAllocatorTraits = typename ROSMessageTypeDeleterHelper::AllocTraits;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeDeleterHelper::Alloc;
|
||||
using ROSMessageTypeDeleter = typename ROSMessageTypeDeleterHelper::Deleter;
|
||||
// See AnySubscriptionCallbackHelper for the types of these.
|
||||
using ConstRefCallback = typename HelperT::ConstRefCallback;
|
||||
using ConstRefWithInfoCallback = typename HelperT::ConstRefWithInfoCallback;
|
||||
|
||||
using SerializedMessageDeleterHelper =
|
||||
rclcpp::detail::MessageDeleterHelper<rclcpp::SerializedMessage, AllocatorT>;
|
||||
using SerializedMessageAllocatorTraits = typename SerializedMessageDeleterHelper::AllocTraits;
|
||||
using SerializedMessageAllocator = typename SerializedMessageDeleterHelper::Alloc;
|
||||
using SerializedMessageDeleter = typename SerializedMessageDeleterHelper::Deleter;
|
||||
using UniquePtrCallback = typename HelperT::UniquePtrCallback;
|
||||
using UniquePtrWithInfoCallback = typename HelperT::UniquePtrWithInfoCallback;
|
||||
|
||||
// See AnySubscriptionCallbackPossibleTypes for the types of these.
|
||||
using CallbackTypes = detail::AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
using SharedConstPtrCallback = typename HelperT::SharedConstPtrCallback;
|
||||
using SharedConstPtrWithInfoCallback = typename HelperT::SharedConstPtrWithInfoCallback;
|
||||
|
||||
using ConstRefCallback =
|
||||
typename CallbackTypes::ConstRefCallback;
|
||||
using ConstRefROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefROSMessageCallback;
|
||||
using ConstRefWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefWithInfoCallback;
|
||||
using ConstRefWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefWithInfoROSMessageCallback;
|
||||
using ConstRefSerializedMessageCallback =
|
||||
typename CallbackTypes::ConstRefSerializedMessageCallback;
|
||||
using ConstRefSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback;
|
||||
using UniquePtrCallback =
|
||||
typename CallbackTypes::UniquePtrCallback;
|
||||
using UniquePtrROSMessageCallback =
|
||||
typename CallbackTypes::UniquePtrROSMessageCallback;
|
||||
using UniquePtrWithInfoCallback =
|
||||
typename CallbackTypes::UniquePtrWithInfoCallback;
|
||||
using UniquePtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::UniquePtrWithInfoROSMessageCallback;
|
||||
using UniquePtrSerializedMessageCallback =
|
||||
typename CallbackTypes::UniquePtrSerializedMessageCallback;
|
||||
using UniquePtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback;
|
||||
using SharedConstPtrCallback =
|
||||
typename CallbackTypes::SharedConstPtrCallback;
|
||||
using SharedConstPtrROSMessageCallback =
|
||||
typename CallbackTypes::SharedConstPtrROSMessageCallback;
|
||||
using SharedConstPtrWithInfoCallback =
|
||||
typename CallbackTypes::SharedConstPtrWithInfoCallback;
|
||||
using SharedConstPtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::SharedConstPtrWithInfoROSMessageCallback;
|
||||
using SharedConstPtrSerializedMessageCallback =
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageCallback;
|
||||
using SharedConstPtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback;
|
||||
using ConstRefSharedConstPtrCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrCallback;
|
||||
using ConstRefSharedConstPtrROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrROSMessageCallback;
|
||||
typename HelperT::ConstRefSharedConstPtrCallback;
|
||||
using ConstRefSharedConstPtrWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoCallback;
|
||||
using ConstRefSharedConstPtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoROSMessageCallback;
|
||||
using ConstRefSharedConstPtrSerializedMessageCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback;
|
||||
using ConstRefSharedConstPtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback;
|
||||
using SharedPtrCallback =
|
||||
typename CallbackTypes::SharedPtrCallback;
|
||||
using SharedPtrROSMessageCallback =
|
||||
typename CallbackTypes::SharedPtrROSMessageCallback;
|
||||
using SharedPtrWithInfoCallback =
|
||||
typename CallbackTypes::SharedPtrWithInfoCallback;
|
||||
using SharedPtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::SharedPtrWithInfoROSMessageCallback;
|
||||
using SharedPtrSerializedMessageCallback =
|
||||
typename CallbackTypes::SharedPtrSerializedMessageCallback;
|
||||
using SharedPtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback;
|
||||
typename HelperT::ConstRefSharedConstPtrWithInfoCallback;
|
||||
|
||||
template<typename T>
|
||||
struct NotNull
|
||||
{
|
||||
NotNull(const T * pointer_in, const char * msg)
|
||||
: pointer(pointer_in)
|
||||
{
|
||||
if (pointer == nullptr) {
|
||||
throw std::invalid_argument(msg);
|
||||
}
|
||||
}
|
||||
|
||||
const T * pointer;
|
||||
};
|
||||
using SharedPtrCallback = typename HelperT::SharedPtrCallback;
|
||||
using SharedPtrWithInfoCallback = typename HelperT::SharedPtrWithInfoCallback;
|
||||
|
||||
public:
|
||||
explicit
|
||||
AnySubscriptionCallback(const AllocatorT & allocator = AllocatorT()) // NOLINT[runtime/explicit]
|
||||
: subscribed_type_allocator_(allocator),
|
||||
ros_message_type_allocator_(allocator)
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&subscribed_type_deleter_, &subscribed_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
message_allocator_ = allocator;
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
|
||||
}
|
||||
|
||||
[[deprecated("use AnySubscriptionCallback(const AllocatorT & allocator) instead")]]
|
||||
explicit
|
||||
AnySubscriptionCallback(std::shared_ptr<AllocatorT> allocator) // NOLINT[runtime/explicit]
|
||||
: AnySubscriptionCallback(*NotNull<AllocatorT>(allocator.get(), "invalid allocator").pointer)
|
||||
{}
|
||||
{
|
||||
if (allocator == nullptr) {
|
||||
throw std::runtime_error("invalid allocator");
|
||||
}
|
||||
message_allocator_ = *allocator;
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
|
||||
}
|
||||
|
||||
AnySubscriptionCallback(const AnySubscriptionCallback &) = default;
|
||||
|
||||
@@ -405,79 +190,40 @@ public:
|
||||
}
|
||||
|
||||
/// Function for shared_ptr to non-const MessageT, which is deprecated.
|
||||
template<typename SetT>
|
||||
// TODO(wjwwood): enable this deprecation after Galactic
|
||||
// [[deprecated(
|
||||
// "use 'void (std::shared_ptr<const MessageT>)' instead"
|
||||
// )]]
|
||||
void
|
||||
set_deprecated(std::function<void(std::shared_ptr<SetT>)> callback)
|
||||
set_deprecated(std::function<void(std::shared_ptr<MessageT>)> callback)
|
||||
// set(CallbackT callback)
|
||||
{
|
||||
callback_variant_ = callback;
|
||||
}
|
||||
|
||||
/// Function for shared_ptr to non-const MessageT with MessageInfo, which is deprecated.
|
||||
template<typename SetT>
|
||||
// TODO(wjwwood): enable this deprecation after Galactic
|
||||
// [[deprecated(
|
||||
// "use 'void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)' instead"
|
||||
// )]]
|
||||
void
|
||||
set_deprecated(std::function<void(std::shared_ptr<SetT>, const rclcpp::MessageInfo &)> callback)
|
||||
set_deprecated(
|
||||
std::function<void(std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)> callback)
|
||||
{
|
||||
callback_variant_ = callback;
|
||||
}
|
||||
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
create_ros_unique_ptr_from_ros_shared_ptr_message(
|
||||
const std::shared_ptr<const ROSMessageType> & message)
|
||||
std::unique_ptr<MessageT, MessageDeleter>
|
||||
create_unique_ptr_from_shared_ptr_message(const std::shared_ptr<const MessageT> & message)
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr, *message);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
auto ptr = MessageAllocTraits::allocate(message_allocator_, 1);
|
||||
MessageAllocTraits::construct(message_allocator_, ptr, *message);
|
||||
return std::unique_ptr<MessageT, MessageDeleter>(ptr, message_deleter_);
|
||||
}
|
||||
|
||||
std::unique_ptr<rclcpp::SerializedMessage, SerializedMessageDeleter>
|
||||
create_serialized_message_unique_ptr_from_shared_ptr(
|
||||
const std::shared_ptr<const rclcpp::SerializedMessage> & serialized_message)
|
||||
{
|
||||
auto ptr = SerializedMessageAllocatorTraits::allocate(serialized_message_allocator_, 1);
|
||||
SerializedMessageAllocatorTraits::construct(
|
||||
serialized_message_allocator_, ptr, *serialized_message);
|
||||
return std::unique_ptr<
|
||||
rclcpp::SerializedMessage,
|
||||
SerializedMessageDeleter
|
||||
>(ptr, serialized_message_deleter_);
|
||||
}
|
||||
|
||||
std::unique_ptr<SubscribedType, SubscribedTypeDeleter>
|
||||
create_custom_unique_ptr_from_custom_shared_ptr_message(
|
||||
const std::shared_ptr<const SubscribedType> & message)
|
||||
{
|
||||
auto ptr = SubscribedTypeAllocatorTraits::allocate(subscribed_type_allocator_, 1);
|
||||
SubscribedTypeAllocatorTraits::construct(subscribed_type_allocator_, ptr, *message);
|
||||
return std::unique_ptr<SubscribedType, SubscribedTypeDeleter>(ptr, subscribed_type_deleter_);
|
||||
}
|
||||
|
||||
std::unique_ptr<SubscribedType, SubscribedTypeDeleter>
|
||||
convert_ros_message_to_custom_type_unique_ptr(const ROSMessageType & msg)
|
||||
{
|
||||
if constexpr (rclcpp::TypeAdapter<MessageT>::is_specialized::value) {
|
||||
auto ptr = SubscribedTypeAllocatorTraits::allocate(subscribed_type_allocator_, 1);
|
||||
SubscribedTypeAllocatorTraits::construct(subscribed_type_allocator_, ptr);
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_custom(msg, *ptr);
|
||||
return std::unique_ptr<SubscribedType, SubscribedTypeDeleter>(ptr, subscribed_type_deleter_);
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"convert_ros_message_to_custom_type_unique_ptr "
|
||||
"unexpectedly called without TypeAdapter");
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch when input is a ros message and the output could be anything.
|
||||
void
|
||||
dispatch(
|
||||
std::shared_ptr<ROSMessageType> message,
|
||||
std::shared_ptr<MessageT> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
@@ -492,268 +238,28 @@ public:
|
||||
std::visit(
|
||||
[&message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
static constexpr bool is_ta = rclcpp::TypeAdapter<MessageT>::is_specialized::value;
|
||||
|
||||
// conditions for output is custom message
|
||||
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
|
||||
// TODO(wjwwood): consider avoiding heap allocation for small messages
|
||||
// maybe something like:
|
||||
// if constexpr (rosidl_generator_traits::has_fixed_size<T> && sizeof(T) < N) {
|
||||
// ... on stack
|
||||
// }
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message, message_info);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, UniquePtrCallback>) {
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr (is_ta && std::is_same_v<T, UniquePtrWithInfoCallback>) {
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
}
|
||||
// conditions for output is ros message
|
||||
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
|
||||
if constexpr (std::is_same_v<T, ConstRefCallback>) {
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrROSMessageCallback>) {
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message));
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>) {
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message), message_info);
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrCallback>) {
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message));
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrWithInfoCallback>) {
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>)
|
||||
{
|
||||
callback(message);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
callback(message, message_info);
|
||||
}
|
||||
// condition to catch SerializedMessage types
|
||||
else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, ConstRefSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Cannot dispatch std::shared_ptr<ROSMessageType> message "
|
||||
"to rclcpp::SerializedMessage");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
}
|
||||
|
||||
// Dispatch when input is a serialized message and the output could be anything.
|
||||
void
|
||||
dispatch(
|
||||
std::shared_ptr<rclcpp::SerializedMessage> serialized_message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
if (std::get<0>(callback_variant_) == nullptr) {
|
||||
// This can happen if it is default initialized, or if it is assigned nullptr.
|
||||
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
|
||||
}
|
||||
}
|
||||
// Dispatch.
|
||||
std::visit(
|
||||
[&serialized_message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
|
||||
// condition to catch SerializedMessage types
|
||||
if constexpr (std::is_same_v<T, ConstRefSerializedMessageCallback>) {
|
||||
callback(*serialized_message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>) {
|
||||
callback(*serialized_message, message_info);
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrSerializedMessageCallback>) {
|
||||
callback(create_serialized_message_unique_ptr_from_shared_ptr(serialized_message));
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>) {
|
||||
callback(
|
||||
create_serialized_message_unique_ptr_from_shared_ptr(serialized_message),
|
||||
message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>)
|
||||
{
|
||||
callback(create_serialized_message_unique_ptr_from_shared_ptr(serialized_message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
callback(
|
||||
create_serialized_message_unique_ptr_from_shared_ptr(serialized_message),
|
||||
message_info);
|
||||
}
|
||||
// conditions for output anything else
|
||||
else if constexpr ( // NOLINT[whitespace/newline]
|
||||
std::is_same_v<T, ConstRefCallback>||
|
||||
std::is_same_v<T, ConstRefROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, UniquePtrROSMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"cannot dispatch rclcpp::SerializedMessage to "
|
||||
"non-rclcpp::SerializedMessage callbacks");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
}
|
||||
|
||||
void
|
||||
dispatch_intra_process(
|
||||
std::shared_ptr<const ROSMessageType> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
if (std::get<0>(callback_variant_) == nullptr) {
|
||||
// This can happen if it is default initialized, or if it is assigned nullptr.
|
||||
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
|
||||
}
|
||||
}
|
||||
// Dispatch.
|
||||
std::visit(
|
||||
[&message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
static constexpr bool is_ta = rclcpp::TypeAdapter<MessageT>::is_specialized::value;
|
||||
|
||||
// conditions for custom type
|
||||
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
}
|
||||
// conditions for ros message type
|
||||
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>)
|
||||
{
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>)
|
||||
std::is_same_v<T, SharedPtrCallback>)
|
||||
{
|
||||
callback(message);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>)
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>)
|
||||
{
|
||||
callback(message, message_info);
|
||||
}
|
||||
// condition to catch SerializedMessage types
|
||||
else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, ConstRefSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Cannot dispatch std::shared_ptr<const ROSMessageType> message "
|
||||
"to rclcpp::SerializedMessage");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
} else {
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
@@ -762,7 +268,7 @@ public:
|
||||
|
||||
void
|
||||
dispatch_intra_process(
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> message,
|
||||
std::shared_ptr<const MessageT> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
@@ -777,89 +283,75 @@ public:
|
||||
std::visit(
|
||||
[&message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
static constexpr bool is_ta = rclcpp::TypeAdapter<MessageT>::is_specialized::value;
|
||||
|
||||
// conditions for custom type
|
||||
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
}
|
||||
// conditions for ros message type
|
||||
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
|
||||
if constexpr (std::is_same_v<T, ConstRefCallback>) {
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>)
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>)
|
||||
{
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>)
|
||||
{
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>)
|
||||
{
|
||||
callback(message);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>)
|
||||
{
|
||||
callback(message, message_info);
|
||||
} else {
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
}
|
||||
|
||||
void
|
||||
dispatch_intra_process(
|
||||
std::unique_ptr<MessageT, MessageDeleter> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
if (std::get<0>(callback_variant_) == nullptr) {
|
||||
// This can happen if it is default initialized, or if it is assigned nullptr.
|
||||
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
|
||||
}
|
||||
}
|
||||
// Dispatch.
|
||||
std::visit(
|
||||
[&message, &message_info](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, ConstRefCallback>) {
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>)
|
||||
{
|
||||
callback(std::move(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>)
|
||||
{
|
||||
callback(std::move(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>)
|
||||
{
|
||||
callback(std::move(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
callback(std::move(message), message_info);
|
||||
}
|
||||
// condition to catch SerializedMessage types
|
||||
else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, ConstRefSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Cannot dispatch std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> message "
|
||||
"to rclcpp::SerializedMessage");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
} else {
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
@@ -877,18 +369,6 @@ public:
|
||||
std::holds_alternative<ConstRefSharedConstPtrWithInfoCallback>(callback_variant_);
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
is_serialized_message_callback() const
|
||||
{
|
||||
return
|
||||
std::holds_alternative<ConstRefSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<UniquePtrSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<SharedConstPtrSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<ConstRefSharedConstPtrSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<SharedPtrSerializedMessageCallback>(callback_variant_);
|
||||
}
|
||||
|
||||
void
|
||||
register_callback_for_tracing()
|
||||
{
|
||||
@@ -922,12 +402,8 @@ private:
|
||||
// For now, compose the variant into this class as a private attribute.
|
||||
typename HelperT::variant_type callback_variant_;
|
||||
|
||||
SubscribedTypeAllocator subscribed_type_allocator_;
|
||||
SubscribedTypeDeleter subscribed_type_deleter_;
|
||||
ROSMessageTypeAllocator ros_message_type_allocator_;
|
||||
ROSMessageTypeDeleter ros_message_type_deleter_;
|
||||
SerializedMessageAllocator serialized_message_allocator_;
|
||||
SerializedMessageDeleter serialized_message_deleter_;
|
||||
MessageAlloc message_allocator_;
|
||||
MessageDeleter message_deleter_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -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.
|
||||
@@ -92,7 +80,7 @@ public:
|
||||
*
|
||||
* Note that this function does not setup any signal handlers, so if you want
|
||||
* it to be shutdown by the signal handler, then you need to either install
|
||||
* them manually with rclcpp::install_signal_handlers() or use rclcpp::init().
|
||||
* them manually with rclcpp::install_signal_handers() or use rclcpp::init().
|
||||
* In addition to installing the signal handlers, the shutdown_on_sigint
|
||||
* of the InitOptions needs to be `true` for this context to be shutdown by
|
||||
* the signal handler, otherwise it will be passed over.
|
||||
@@ -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_;
|
||||
|
||||
@@ -47,11 +47,11 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT,
|
||||
typename NodeParametersT,
|
||||
typename NodeTopicsT,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType>
|
||||
typename NodeTopicsT>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
NodeParametersT & node_parameters,
|
||||
@@ -70,7 +70,7 @@ create_subscription(
|
||||
using rclcpp::node_interfaces::get_node_topics_interface;
|
||||
auto node_topics_interface = get_node_topics_interface(node_topics);
|
||||
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
|
||||
subscription_topic_stats = nullptr;
|
||||
|
||||
if (rclcpp::detail::resolve_enable_topic_statistics(
|
||||
@@ -92,11 +92,11 @@ create_subscription(
|
||||
qos);
|
||||
|
||||
subscription_topic_stats = std::make_shared<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
|
||||
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
|
||||
|
||||
std::weak_ptr<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
|
||||
> weak_subscription_topic_stats(subscription_topic_stats);
|
||||
auto sub_call_back = [weak_subscription_topic_stats]() {
|
||||
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
|
||||
@@ -153,6 +153,7 @@ create_subscription(
|
||||
* \tparam MessageT
|
||||
* \tparam CallbackT
|
||||
* \tparam AllocatorT
|
||||
* \tparam CallbackMessageT
|
||||
* \tparam SubscriptionT
|
||||
* \tparam MessageMemoryStrategyT
|
||||
* \tparam NodeT
|
||||
@@ -170,8 +171,13 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>,
|
||||
typename NodeT>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
@@ -188,7 +194,7 @@ create_subscription(
|
||||
)
|
||||
{
|
||||
return rclcpp::detail::create_subscription<
|
||||
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
node, node, topic_name, qos, std::forward<CallbackT>(callback), options, msg_mem_strat);
|
||||
}
|
||||
|
||||
@@ -200,8 +206,13 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType>
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & node_parameters,
|
||||
@@ -218,7 +229,7 @@ create_subscription(
|
||||
)
|
||||
{
|
||||
return rclcpp::detail::create_subscription<
|
||||
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
node_parameters, node_topics, topic_name, qos,
|
||||
std::forward<CallbackT>(callback), options, msg_mem_strat);
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
|
||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -38,13 +37,13 @@ template<
|
||||
typename rclcpp::experimental::buffers::IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr
|
||||
create_intra_process_buffer(
|
||||
IntraProcessBufferType buffer_type,
|
||||
const rclcpp::QoS & qos,
|
||||
rmw_qos_profile_t qos,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
using MessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
size_t buffer_size = qos.depth();
|
||||
size_t buffer_size = qos.depth;
|
||||
|
||||
using rclcpp::experimental::buffers::IntraProcessBuffer;
|
||||
typename IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr buffer;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
@@ -182,7 +181,7 @@ public:
|
||||
do_intra_process_publish(
|
||||
uint64_t intra_process_publisher_id,
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
|
||||
@@ -203,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)
|
||||
{
|
||||
@@ -227,9 +225,9 @@ public:
|
||||
{
|
||||
// Construct a new shared pointer from the message
|
||||
// for the buffers that do not require ownership
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
|
||||
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);
|
||||
@@ -244,7 +242,7 @@ public:
|
||||
do_intra_process_publish_and_return_shared(
|
||||
uint64_t intra_process_publisher_id,
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
|
||||
@@ -265,17 +263,17 @@ 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;
|
||||
} else {
|
||||
// Construct a new shared pointer from the message for the buffers that
|
||||
// do not require ownership and to return.
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
|
||||
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);
|
||||
}
|
||||
@@ -305,6 +303,25 @@ public:
|
||||
get_subscription_intra_process(uint64_t intra_process_subscription_id);
|
||||
|
||||
private:
|
||||
struct SubscriptionInfo
|
||||
{
|
||||
SubscriptionInfo() = default;
|
||||
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr subscription;
|
||||
rmw_qos_profile_t qos;
|
||||
const char * topic_name;
|
||||
bool use_take_shared_method;
|
||||
};
|
||||
|
||||
struct PublisherInfo
|
||||
{
|
||||
PublisherInfo() = default;
|
||||
|
||||
rclcpp::PublisherBase::WeakPtr publisher;
|
||||
rmw_qos_profile_t qos;
|
||||
const char * topic_name;
|
||||
};
|
||||
|
||||
struct SplittedSubscriptions
|
||||
{
|
||||
std::vector<uint64_t> take_shared_subscriptions;
|
||||
@@ -312,10 +329,10 @@ private:
|
||||
};
|
||||
|
||||
using SubscriptionMap =
|
||||
std::unordered_map<uint64_t, rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr>;
|
||||
std::unordered_map<uint64_t, SubscriptionInfo>;
|
||||
|
||||
using PublisherMap =
|
||||
std::unordered_map<uint64_t, rclcpp::PublisherBase::WeakPtr>;
|
||||
std::unordered_map<uint64_t, PublisherInfo>;
|
||||
|
||||
using PublisherToSubscriptionIdsMap =
|
||||
std::unordered_map<uint64_t, SplittedSubscriptions>;
|
||||
@@ -331,14 +348,9 @@ private:
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
can_communicate(
|
||||
rclcpp::PublisherBase::SharedPtr pub,
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr sub) const;
|
||||
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,
|
||||
@@ -349,18 +361,11 @@ private:
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
throw std::runtime_error("subscription has unexpectedly gone out of scope");
|
||||
}
|
||||
auto subscription_base = subscription_it->second.lock();
|
||||
auto subscription_base = subscription_it->second.subscription.lock();
|
||||
if (subscription_base) {
|
||||
auto subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcessBuffer<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 "
|
||||
"SubscriptionIntraProcessBuffer<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 {
|
||||
@@ -377,7 +382,7 @@ private:
|
||||
add_owned_msg_to_buffers(
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
std::vector<uint64_t> subscription_ids,
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
@@ -387,18 +392,11 @@ private:
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
throw std::runtime_error("subscription has unexpectedly gone out of scope");
|
||||
}
|
||||
auto subscription_base = subscription_it->second.lock();
|
||||
auto subscription_base = subscription_it->second.subscription.lock();
|
||||
if (subscription_base) {
|
||||
auto subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcessBuffer<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 "
|
||||
"SubscriptionIntraProcessBuffer<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
|
||||
@@ -407,8 +405,8 @@ private:
|
||||
// Copy the message since we have additional subscriptions to serve
|
||||
MessageUniquePtr copy_message;
|
||||
Deleter deleter = message.get_deleter();
|
||||
auto ptr = MessageAllocTraits::allocate(allocator, 1);
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
auto ptr = MessageAllocTraits::allocate(*allocator.get(), 1);
|
||||
MessageAllocTraits::construct(*allocator.get(), ptr, *message);
|
||||
copy_message = MessageUniquePtr(ptr, deleter);
|
||||
|
||||
subscription->provide_intra_process_message(std::move(copy_message));
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
@@ -46,43 +44,54 @@ template<
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>,
|
||||
typename CallbackMessageT = MessageT>
|
||||
class SubscriptionIntraProcess
|
||||
: public SubscriptionIntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>
|
||||
class SubscriptionIntraProcess : public SubscriptionIntraProcessBase
|
||||
{
|
||||
using SubscriptionIntraProcessBufferT = SubscriptionIntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
|
||||
|
||||
using MessageAllocTraits = typename SubscriptionIntraProcessBufferT::MessageAllocTraits;
|
||||
using MessageAlloc = typename SubscriptionIntraProcessBufferT::MessageAlloc;
|
||||
using ConstMessageSharedPtr = typename SubscriptionIntraProcessBufferT::ConstMessageSharedPtr;
|
||||
using MessageUniquePtr = typename SubscriptionIntraProcessBufferT::MessageUniquePtr;
|
||||
using BufferUniquePtr = typename SubscriptionIntraProcessBufferT::BufferUniquePtr;
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>::UniquePtr;
|
||||
|
||||
SubscriptionIntraProcess(
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> callback,
|
||||
std::shared_ptr<Alloc> allocator,
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile,
|
||||
rmw_qos_profile_t qos_profile,
|
||||
rclcpp::IntraProcessBufferType buffer_type)
|
||||
: SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>(
|
||||
allocator,
|
||||
context,
|
||||
topic_name,
|
||||
qos_profile,
|
||||
buffer_type),
|
||||
: SubscriptionIntraProcessBase(topic_name, qos_profile),
|
||||
any_callback_(callback)
|
||||
{
|
||||
if (!std::is_same<MessageT, CallbackMessageT>::value) {
|
||||
throw std::runtime_error("SubscriptionIntraProcess wrong callback type");
|
||||
}
|
||||
|
||||
// Create the intra-process buffer.
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<MessageT, Alloc, Deleter>(
|
||||
buffer_type,
|
||||
qos_profile,
|
||||
allocator);
|
||||
|
||||
// Create the guard condition.
|
||||
rcl_guard_condition_options_t guard_condition_options =
|
||||
rcl_guard_condition_get_default_options();
|
||||
|
||||
gc_ = rcl_get_zero_initialized_guard_condition();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(
|
||||
&gc_, context->get_rcl_context().get(), guard_condition_options);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error("SubscriptionIntraProcess init error initializing guard condition");
|
||||
}
|
||||
|
||||
TRACEPOINT(
|
||||
rclcpp_subscription_callback_added,
|
||||
static_cast<const void *>(this),
|
||||
@@ -95,7 +104,22 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~SubscriptionIntraProcess() = default;
|
||||
~SubscriptionIntraProcess()
|
||||
{
|
||||
if (rcl_guard_condition_fini(&gc_) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Failed to destroy guard condition: %s",
|
||||
rcutils_get_error_string().str);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set)
|
||||
{
|
||||
(void) wait_set;
|
||||
return buffer_->has_data();
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data()
|
||||
@@ -104,9 +128,9 @@ public:
|
||||
MessageUniquePtr unique_msg;
|
||||
|
||||
if (any_callback_.use_take_shared_method()) {
|
||||
shared_msg = this->buffer_->consume_shared();
|
||||
shared_msg = buffer_->consume_shared();
|
||||
} else {
|
||||
unique_msg = this->buffer_->consume_unique();
|
||||
unique_msg = buffer_->consume_unique();
|
||||
}
|
||||
return std::static_pointer_cast<void>(
|
||||
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
|
||||
@@ -117,10 +141,37 @@ public:
|
||||
|
||||
void execute(std::shared_ptr<void> & data)
|
||||
{
|
||||
execute_impl<MessageT>(data);
|
||||
execute_impl<CallbackMessageT>(data);
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(ConstMessageSharedPtr message)
|
||||
{
|
||||
buffer_->add_shared(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(MessageUniquePtr message)
|
||||
{
|
||||
buffer_->add_unique(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const
|
||||
{
|
||||
return buffer_->use_take_shared_method();
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
trigger_guard_condition()
|
||||
{
|
||||
rcl_ret_t ret = rcl_trigger_guard_condition(&gc_);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_same<T, rcl_serialized_message_t>::value, void>::type
|
||||
execute_impl(std::shared_ptr<void> & data)
|
||||
@@ -155,6 +206,7 @@ protected:
|
||||
}
|
||||
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
|
||||
BufferUniquePtr buffer_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
@@ -40,9 +39,7 @@ public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
SubscriptionIntraProcessBase(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile)
|
||||
SubscriptionIntraProcessBase(const std::string & topic_name, rmw_qos_profile_t qos_profile)
|
||||
: topic_name_(topic_name), qos_profile_(qos_profile)
|
||||
{}
|
||||
|
||||
@@ -74,7 +71,7 @@ public:
|
||||
get_topic_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
QoS
|
||||
rmw_qos_profile_t
|
||||
get_actual_qos() const;
|
||||
|
||||
protected:
|
||||
@@ -86,7 +83,7 @@ private:
|
||||
trigger_guard_condition() = 0;
|
||||
|
||||
std::string topic_name_;
|
||||
QoS qos_profile_;
|
||||
rmw_qos_profile_t qos_profile_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
@@ -1,143 +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__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>
|
||||
>
|
||||
class SubscriptionIntraProcessBuffer : public SubscriptionIntraProcessBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcessBuffer)
|
||||
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>::UniquePtr;
|
||||
|
||||
SubscriptionIntraProcessBuffer(
|
||||
std::shared_ptr<Alloc> allocator,
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile,
|
||||
rclcpp::IntraProcessBufferType buffer_type)
|
||||
: SubscriptionIntraProcessBase(topic_name, qos_profile)
|
||||
{
|
||||
// Create the intra-process buffer.
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<MessageT, Alloc, Deleter>(
|
||||
buffer_type,
|
||||
qos_profile,
|
||||
allocator);
|
||||
|
||||
// Create the guard condition.
|
||||
rcl_guard_condition_options_t guard_condition_options =
|
||||
rcl_guard_condition_get_default_options();
|
||||
|
||||
gc_ = rcl_get_zero_initialized_guard_condition();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(
|
||||
&gc_, context->get_rcl_context().get(), guard_condition_options);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error(
|
||||
"SubscriptionIntraProcessBuffer init error initializing guard condition");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~SubscriptionIntraProcessBuffer()
|
||||
{
|
||||
if (rcl_guard_condition_fini(&gc_) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Failed to destroy guard condition: %s",
|
||||
rcutils_get_error_string().str);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set)
|
||||
{
|
||||
(void) wait_set;
|
||||
return buffer_->has_data();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(ConstMessageSharedPtr message)
|
||||
{
|
||||
buffer_->add_shared(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(MessageUniquePtr message)
|
||||
{
|
||||
buffer_->add_unique(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const
|
||||
{
|
||||
return buffer_->use_take_shared_method();
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
trigger_guard_condition()
|
||||
{
|
||||
rcl_ret_t ret = rcl_trigger_guard_condition(&gc_);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
BufferUniquePtr buffer_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
@@ -136,13 +136,6 @@ public:
|
||||
void handle_message(
|
||||
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// Handle dispatching rclcpp::SerializedMessage to user callback.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// This function is currently not implemented.
|
||||
RCLCPP_PUBLIC
|
||||
void handle_loaned_message(
|
||||
|
||||
@@ -1,90 +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__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
#define RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
/// Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Specialization for when MessageT is an actual ROS message type.
|
||||
template<typename MessageT>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<MessageT>::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
auto handle = rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>();
|
||||
if (!handle) {
|
||||
throw std::runtime_error("Type support handle unexpectedly nullptr");
|
||||
}
|
||||
return *handle;
|
||||
}
|
||||
|
||||
/// Specialization for when MessageT is an adapted type using rclcpp::TypeAdapter.
|
||||
template<typename AdaptedType>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<AdaptedType>::value &&
|
||||
rclcpp::TypeAdapter<AdaptedType>::is_specialized::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
auto handle = rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
typename TypeAdapter<AdaptedType>::ros_message_type
|
||||
>();
|
||||
if (!handle) {
|
||||
throw std::runtime_error("Type support handle unexpectedly nullptr");
|
||||
}
|
||||
return *handle;
|
||||
}
|
||||
|
||||
/// Specialization for when MessageT is not a ROS message nor an adapted type.
|
||||
/**
|
||||
* This specialization is a pass through runtime check, which allows a better
|
||||
* static_assert to catch this issue further down the line.
|
||||
* This should never get to be called in practice, and is purely defensive.
|
||||
*/
|
||||
template<
|
||||
typename AdaptedType
|
||||
>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<AdaptedType>::value &&
|
||||
!TypeAdapter<AdaptedType>::is_specialized::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"this specialization of rclcpp::get_message_type_support_handle() "
|
||||
"should never be called");
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
@@ -1,35 +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__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
#define RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct is_ros_compatible_type
|
||||
{
|
||||
static constexpr bool value =
|
||||
rosidl_generator_traits::is_message<T>::value ||
|
||||
rclcpp::TypeAdapter<T>::is_specialized::value;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
@@ -103,9 +103,6 @@ public:
|
||||
* \param[in] allocator Allocator instance in case middleware can not allocate messages
|
||||
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
|
||||
*/
|
||||
[[
|
||||
deprecated("used the LoanedMessage constructor that does not use a shared_ptr to the allocator")
|
||||
]]
|
||||
LoanedMessage(
|
||||
const rclcpp::PublisherBase * pub,
|
||||
std::shared_ptr<std::allocator<MessageT>> allocator)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -206,8 +206,13 @@ public:
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>
|
||||
>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
|
||||
@@ -86,6 +86,7 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#ifndef RCLCPP__PUBLISHER_HPP_
|
||||
#define RCLCPP__PUBLISHER_HPP_
|
||||
|
||||
#include <rmw/error_handling.h>
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -24,21 +27,16 @@
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/publisher.h"
|
||||
#include "rmw/error_handling.h"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/detail/resolve_use_intra_process.hpp"
|
||||
#include "rclcpp/experimental/intra_process_manager.hpp"
|
||||
#include "rclcpp/get_message_type_support_handle.hpp"
|
||||
#include "rclcpp/is_ros_compatible_type.hpp"
|
||||
#include "rclcpp/loaned_message.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -51,62 +49,15 @@ template<typename MessageT, typename AllocatorT>
|
||||
class LoanedMessage;
|
||||
|
||||
/// A publisher publishes messages of any type to a topic.
|
||||
/**
|
||||
* MessageT must be a:
|
||||
*
|
||||
* - ROS message type with its own type support (e.g. std_msgs::msgs::String), or a
|
||||
* - rclcpp::TypeAdapter<CustomType, ROSMessageType>
|
||||
* (e.g. rclcpp::TypeAdapter<std::string, std_msgs::msg::String), or a
|
||||
* - custom type that has been setup as the implicit type for a ROS type using
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(custom_type, ros_message_type)
|
||||
*
|
||||
* In the case that MessageT is ROS message type (e.g. std_msgs::msg::String),
|
||||
* both PublishedType and ROSMessageType will be that type.
|
||||
* In the case that MessageT is a TypeAdapter<CustomType, ROSMessageType> type
|
||||
* (e.g. TypeAdapter<std::string, std_msgs::msg::String>), PublishedType will
|
||||
* be the custom type, and ROSMessageType will be the ros message type.
|
||||
*
|
||||
* This is achieved because of the "identity specialization" for TypeAdapter,
|
||||
* which returns itself if it is already a TypeAdapter, and the default
|
||||
* specialization which allows ROSMessageType to be void.
|
||||
* \sa rclcpp::TypeAdapter for more details.
|
||||
*/
|
||||
template<typename MessageT, typename AllocatorT = std::allocator<void>>
|
||||
class Publisher : public PublisherBase
|
||||
{
|
||||
public:
|
||||
static_assert(
|
||||
rclcpp::is_ros_compatible_type<MessageT>::value,
|
||||
"given message type is not compatible with ROS and cannot be used with a Publisher");
|
||||
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
|
||||
|
||||
using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, AllocatorT>;
|
||||
using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
|
||||
using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
|
||||
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using MessageAllocatorTraits
|
||||
[[deprecated("use PublishedTypeAllocatorTraits")]] =
|
||||
PublishedTypeAllocatorTraits;
|
||||
using MessageAllocator
|
||||
[[deprecated("use PublishedTypeAllocator")]] =
|
||||
PublishedTypeAllocator;
|
||||
using MessageDeleter
|
||||
[[deprecated("use PublishedTypeDeleter")]] =
|
||||
PublishedTypeDeleter;
|
||||
using MessageUniquePtr
|
||||
[[deprecated("use std::unique_ptr<PublishedType, PublishedTypeDeleter>")]] =
|
||||
std::unique_ptr<PublishedType, PublishedTypeDeleter>;
|
||||
using MessageSharedPtr
|
||||
[[deprecated("use std::shared_ptr<const PublishedType>")]] =
|
||||
std::shared_ptr<const PublishedType>;
|
||||
using MessageAllocatorTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAllocator, MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
|
||||
using MessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
|
||||
|
||||
@@ -129,14 +80,12 @@ public:
|
||||
: PublisherBase(
|
||||
node_base,
|
||||
topic,
|
||||
rclcpp::get_message_type_support_handle<MessageT>(),
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
options.template to_rcl_publisher_options<MessageT>(qos)),
|
||||
options_(options),
|
||||
published_type_allocator_(*options.get_allocator()),
|
||||
ros_message_type_allocator_(*options.get_allocator())
|
||||
message_allocator_(new MessageAllocator(*options.get_allocator().get()))
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
|
||||
|
||||
if (options_.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
@@ -186,15 +135,15 @@ public:
|
||||
// Get the intra process manager instance for this context.
|
||||
auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
|
||||
// Register the publisher with the intra process manager.
|
||||
if (qos.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
if (qos.get_rmw_qos_profile().history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with keep last history qos policy");
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
}
|
||||
if (qos.depth() == 0) {
|
||||
if (qos.get_rmw_qos_profile().depth == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
}
|
||||
if (qos.durability() != rclcpp::DurabilityPolicy::Volatile) {
|
||||
if (qos.get_rmw_qos_profile().durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with volatile durability");
|
||||
}
|
||||
@@ -221,33 +170,21 @@ public:
|
||||
* allocator.
|
||||
* \sa rclcpp::LoanedMessage for details of the LoanedMessage class.
|
||||
*
|
||||
* \return LoanedMessage containing memory for a ROS message of type ROSMessageType
|
||||
* \return LoanedMessage containing memory for a ROS message of type MessageT
|
||||
*/
|
||||
rclcpp::LoanedMessage<ROSMessageType, AllocatorT>
|
||||
rclcpp::LoanedMessage<MessageT, AllocatorT>
|
||||
borrow_loaned_message()
|
||||
{
|
||||
return rclcpp::LoanedMessage<ROSMessageType, AllocatorT>(
|
||||
*this,
|
||||
this->get_ros_message_type_allocator());
|
||||
return rclcpp::LoanedMessage<MessageT, AllocatorT>(this, this->get_allocator());
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/// Send a message to the topic for this publisher.
|
||||
/**
|
||||
* This signature is enabled if the element_type of the std::unique_ptr is
|
||||
* a ROS message type, as opposed to the custom_type of a TypeAdapter, and
|
||||
* that type matches the type given when creating the publisher.
|
||||
*
|
||||
* This signature allows the user to give ownership of the message to rclcpp,
|
||||
* allowing for more efficient intra-process communication optimizations.
|
||||
*
|
||||
* \param[in] msg A unique pointer to the message to send.
|
||||
* This function is templated on the input message type, MessageT.
|
||||
* \param[in] msg A shared pointer to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<T>::value &&
|
||||
std::is_same<T, ROSMessageType>::value
|
||||
>
|
||||
publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
|
||||
virtual void
|
||||
publish(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
{
|
||||
if (!intra_process_is_enabled_) {
|
||||
this->do_inter_process_publish(*msg);
|
||||
@@ -270,24 +207,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if the object being published is
|
||||
* a ROS message type, as opposed to the custom_type of a TypeAdapter, and
|
||||
* that type matches the type given when creating the publisher.
|
||||
*
|
||||
* This signature allows the user to give a reference to a message, which is
|
||||
* copied onto the heap without modification so that a copy can be owned by
|
||||
* rclcpp and ownership of the copy can be moved later if needed.
|
||||
*
|
||||
* \param[in] msg A const reference to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<T>::value &&
|
||||
std::is_same<T, ROSMessageType>::value
|
||||
>
|
||||
publish(const T & msg)
|
||||
virtual void
|
||||
publish(const MessageT & msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
if (!intra_process_is_enabled_) {
|
||||
@@ -297,77 +218,12 @@ public:
|
||||
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
|
||||
// As the message is not const, a copy should be made.
|
||||
// A shared_ptr<const MessageT> could also be constructed here.
|
||||
auto unique_msg = this->duplicate_ros_message_as_unique_ptr(msg);
|
||||
auto ptr = MessageAllocatorTraits::allocate(*message_allocator_.get(), 1);
|
||||
MessageAllocatorTraits::construct(*message_allocator_.get(), ptr, msg);
|
||||
MessageUniquePtr unique_msg(ptr, message_deleter_);
|
||||
this->publish(std::move(unique_msg));
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if this class was created with a TypeAdapter and
|
||||
* the element_type of the std::unique_ptr matches the custom_type for the
|
||||
* TypeAdapter used with this class.
|
||||
*
|
||||
* This signature allows the user to give ownership of the message to rclcpp,
|
||||
* allowing for more efficient intra-process communication optimizations.
|
||||
*
|
||||
* \param[in] msg A unique pointer to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rclcpp::TypeAdapter<MessageT>::is_specialized::value &&
|
||||
std::is_same<T, PublishedType>::value
|
||||
>
|
||||
publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
|
||||
{
|
||||
// TODO(wjwwood): later update this to give the unique_ptr to the intra
|
||||
// process manager and let it decide if it needs to be converted or not.
|
||||
// For now, convert it unconditionally and pass it the ROSMessageType
|
||||
// publish function specialization.
|
||||
auto unique_ros_msg = this->create_ros_message_unique_ptr();
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*msg, *unique_ros_msg);
|
||||
this->publish(std::move(unique_ros_msg));
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if this class was created with a TypeAdapter and
|
||||
* the given type matches the custom_type of the TypeAdapter.
|
||||
*
|
||||
* This signature allows the user to give a reference to a message, which is
|
||||
* copied onto the heap without modification so that a copy can be owned by
|
||||
* rclcpp and ownership of the copy can be moved later if needed.
|
||||
*
|
||||
* \param[in] msg A const reference to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rclcpp::TypeAdapter<MessageT>::is_specialized::value &&
|
||||
std::is_same<T, PublishedType>::value
|
||||
>
|
||||
publish(const T & msg)
|
||||
{
|
||||
// TODO(wjwwood): later update this to give the unique_ptr to the intra
|
||||
// process manager and let it decide if it needs to be converted or not.
|
||||
// For now, convert it unconditionally and pass it the ROSMessageType
|
||||
// publish function specialization.
|
||||
|
||||
// Avoid allocating when not using intra process.
|
||||
if (!intra_process_is_enabled_) {
|
||||
// Convert to the ROS message equivalent and publish it.
|
||||
ROSMessageType ros_msg;
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(msg, ros_msg);
|
||||
// In this case we're not using intra process.
|
||||
return this->do_inter_process_publish(ros_msg);
|
||||
}
|
||||
// Otherwise we have to allocate memory in a unique_ptr, convert it,
|
||||
// and pass it along.
|
||||
// As the message is not const, a copy should be made.
|
||||
// A shared_ptr<const MessageT> could also be constructed here.
|
||||
auto unique_ros_msg = this->create_ros_message_unique_ptr();
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(msg, *unique_ros_msg);
|
||||
this->publish(std::move(unique_ros_msg));
|
||||
}
|
||||
|
||||
void
|
||||
publish(const rcl_serialized_message_t & serialized_msg)
|
||||
{
|
||||
@@ -389,7 +245,7 @@ public:
|
||||
* \param loaned_msg The LoanedMessage instance to be published.
|
||||
*/
|
||||
void
|
||||
publish(rclcpp::LoanedMessage<ROSMessageType, AllocatorT> && loaned_msg)
|
||||
publish(rclcpp::LoanedMessage<MessageT, AllocatorT> && loaned_msg)
|
||||
{
|
||||
if (!loaned_msg.is_valid()) {
|
||||
throw std::runtime_error("loaned message is not valid");
|
||||
@@ -415,28 +271,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
[[deprecated("use get_published_type_allocator() or get_ros_message_type_allocator() instead")]]
|
||||
std::shared_ptr<PublishedTypeAllocator>
|
||||
std::shared_ptr<MessageAllocator>
|
||||
get_allocator() const
|
||||
{
|
||||
return std::make_shared<PublishedTypeAllocator>(published_type_allocator_);
|
||||
}
|
||||
|
||||
PublishedTypeAllocator
|
||||
get_published_type_allocator() const
|
||||
{
|
||||
return published_type_allocator_;
|
||||
}
|
||||
|
||||
ROSMessageTypeAllocator
|
||||
get_ros_message_type_allocator() const
|
||||
{
|
||||
return ros_message_type_allocator_;
|
||||
return message_allocator_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
do_inter_process_publish(const ROSMessageType & msg)
|
||||
do_inter_process_publish(const MessageT & msg)
|
||||
{
|
||||
TRACEPOINT(
|
||||
rclcpp_publish,
|
||||
@@ -473,8 +316,7 @@ protected:
|
||||
}
|
||||
|
||||
void
|
||||
do_loaned_message_publish(
|
||||
std::unique_ptr<ROSMessageType, std::function<void(ROSMessageType *)>> msg)
|
||||
do_loaned_message_publish(std::unique_ptr<MessageT, std::function<void(MessageT *)>> msg)
|
||||
{
|
||||
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
|
||||
|
||||
@@ -494,7 +336,7 @@ protected:
|
||||
}
|
||||
|
||||
void
|
||||
do_intra_process_publish(std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
|
||||
do_intra_process_publish(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
{
|
||||
auto ipm = weak_ipm_.lock();
|
||||
if (!ipm) {
|
||||
@@ -505,15 +347,14 @@ protected:
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
ipm->template do_intra_process_publish<ROSMessageType, AllocatorT>(
|
||||
ipm->template do_intra_process_publish<MessageT, AllocatorT>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
ros_message_type_allocator_);
|
||||
message_allocator_);
|
||||
}
|
||||
|
||||
std::shared_ptr<const ROSMessageType>
|
||||
do_intra_process_publish_and_return_shared(
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
|
||||
std::shared_ptr<const MessageT>
|
||||
do_intra_process_publish_and_return_shared(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
{
|
||||
auto ipm = weak_ipm_.lock();
|
||||
if (!ipm) {
|
||||
@@ -524,29 +365,10 @@ protected:
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
return ipm->template do_intra_process_publish_and_return_shared<ROSMessageType,
|
||||
AllocatorT>(
|
||||
return ipm->template do_intra_process_publish_and_return_shared<MessageT, AllocatorT>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
ros_message_type_allocator_);
|
||||
}
|
||||
|
||||
/// Return a new unique_ptr using the ROSMessageType of the publisher.
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
create_ros_message_unique_ptr()
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
}
|
||||
|
||||
/// Duplicate a given ros message as a unique_ptr.
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
duplicate_ros_message_as_unique_ptr(const ROSMessageType & msg)
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr, msg);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
message_allocator_);
|
||||
}
|
||||
|
||||
/// Copy of original options passed during construction.
|
||||
@@ -556,10 +378,9 @@ protected:
|
||||
*/
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> options_;
|
||||
|
||||
PublishedTypeAllocator published_type_allocator_;
|
||||
PublishedTypeDeleter published_type_deleter_;
|
||||
ROSMessageTypeAllocator ros_message_type_allocator_;
|
||||
ROSMessageTypeDeleter ros_message_type_deleter_;
|
||||
std::shared_ptr<MessageAllocator> message_allocator_;
|
||||
|
||||
MessageDeleter message_deleter_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
@@ -65,10 +64,6 @@ struct PublisherOptionsBase
|
||||
template<typename Allocator>
|
||||
struct PublisherOptionsWithAllocator : public PublisherOptionsBase
|
||||
{
|
||||
static_assert(
|
||||
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
|
||||
"Publisher allocator value type must be void");
|
||||
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = nullptr;
|
||||
|
||||
@@ -85,7 +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();
|
||||
result.allocator = this->get_rcl_allocator();
|
||||
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;
|
||||
@@ -104,35 +99,10 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
|
||||
get_allocator() const
|
||||
{
|
||||
if (!this->allocator) {
|
||||
if (!allocator_storage_) {
|
||||
allocator_storage_ = std::make_shared<Allocator>();
|
||||
}
|
||||
return allocator_storage_;
|
||||
return std::make_shared<Allocator>();
|
||||
}
|
||||
return this->allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
using PlainAllocator =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
|
||||
|
||||
rcl_allocator_t
|
||||
get_rcl_allocator() const
|
||||
{
|
||||
if (!plain_allocator_storage_) {
|
||||
plain_allocator_storage_ =
|
||||
std::make_shared<PlainAllocator>(*this->get_allocator());
|
||||
}
|
||||
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
|
||||
}
|
||||
|
||||
// This is a temporal workaround, to make sure that get_allocator()
|
||||
// always returns a copy of the same allocator.
|
||||
mutable std::shared_ptr<Allocator> allocator_storage_;
|
||||
|
||||
// This is a temporal workaround, to keep the plain allocator that backs
|
||||
// up the rcl allocator returned in rcl_publisher_options_t alive.
|
||||
mutable std::shared_ptr<PlainAllocator> plain_allocator_storage_;
|
||||
};
|
||||
|
||||
using PublisherOptions = PublisherOptionsWithAllocator<std::allocator<void>>;
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
* \param[in] initial_capacity The amount of memory to be allocated.
|
||||
* \param[in] allocator The allocator to be used for the initialization.
|
||||
*/
|
||||
explicit SerializedMessage(
|
||||
SerializedMessage(
|
||||
size_t initial_capacity,
|
||||
const rcl_allocator_t & allocator = rcl_get_default_allocator());
|
||||
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -60,16 +60,10 @@ class NodeTopicsInterface;
|
||||
|
||||
/// Subscription implementation, templated on the type of message this subscription receives.
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackMessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter,
|
||||
/// otherwise just MessageT.
|
||||
typename SubscribedT = typename rclcpp::TypeAdapter<MessageT>::custom_type,
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter,
|
||||
/// otherwise just MessageT.
|
||||
typename ROSMessageT = typename rclcpp::TypeAdapter<MessageT>::ros_message_type,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
ROSMessageT,
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
class Subscription : public SubscriptionBase
|
||||
@@ -77,36 +71,14 @@ class Subscription : public SubscriptionBase
|
||||
friend class rclcpp::node_interfaces::NodeTopicsInterface;
|
||||
|
||||
public:
|
||||
// Redeclare these here to use outside of the class.
|
||||
using SubscribedType = SubscribedT;
|
||||
using ROSMessageType = ROSMessageT;
|
||||
using MessageMemoryStrategyType = MessageMemoryStrategyT;
|
||||
|
||||
using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, AllocatorT>;
|
||||
using SubscribedTypeAllocator = typename SubscribedTypeAllocatorTraits::allocator_type;
|
||||
using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
|
||||
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using MessageAllocatorTraits [[deprecated("use ROSMessageTypeAllocatorTraits")]] =
|
||||
ROSMessageTypeAllocatorTraits;
|
||||
using MessageAllocator [[deprecated("use ROSMessageTypeAllocator")]] =
|
||||
ROSMessageTypeAllocator;
|
||||
using MessageDeleter [[deprecated("use ROSMessageTypeDeleter")]] =
|
||||
ROSMessageTypeDeleter;
|
||||
|
||||
using ConstMessageSharedPtr [[deprecated]] = std::shared_ptr<const ROSMessageType>;
|
||||
using MessageUniquePtr
|
||||
[[deprecated("use std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> instead")]] =
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
|
||||
|
||||
private:
|
||||
using MessageAllocatorTraits = allocator::AllocRebind<CallbackMessageT, AllocatorT>;
|
||||
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAllocator, CallbackMessageT>;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const CallbackMessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<CallbackMessageT, MessageDeleter>;
|
||||
using SubscriptionTopicStatisticsSharedPtr =
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>;
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
|
||||
|
||||
/// Default constructor.
|
||||
@@ -132,7 +104,7 @@ public:
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos,
|
||||
AnySubscriptionCallback<MessageT, AllocatorT> callback,
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename MessageMemoryStrategyT::SharedPtr message_memory_strategy,
|
||||
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics = nullptr)
|
||||
@@ -140,8 +112,8 @@ public:
|
||||
node_base,
|
||||
type_support_handle,
|
||||
topic_name,
|
||||
options.template to_rcl_subscription_options<ROSMessageType>(qos),
|
||||
callback.is_serialized_message_callback()),
|
||||
options.template to_rcl_subscription_options<CallbackMessageT>(qos),
|
||||
rclcpp::subscription_traits::is_serialized_subscription_argument<CallbackMessageT>::value),
|
||||
any_callback_(callback),
|
||||
options_(options),
|
||||
message_memory_strategy_(message_memory_strategy)
|
||||
@@ -183,16 +155,16 @@ public:
|
||||
using rclcpp::detail::resolve_intra_process_buffer_type;
|
||||
|
||||
// Check if the QoS is compatible with intra-process.
|
||||
auto qos_profile = get_actual_qos();
|
||||
if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
rmw_qos_profile_t qos_profile = get_actual_qos().get_rmw_qos_profile();
|
||||
if (qos_profile.history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with keep last history qos policy");
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
}
|
||||
if (qos_profile.depth() == 0) {
|
||||
if (qos_profile.depth == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with 0 depth qos policy");
|
||||
}
|
||||
if (qos_profile.durability() != rclcpp::DurabilityPolicy::Volatile) {
|
||||
if (qos_profile.durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with volatile durability");
|
||||
}
|
||||
@@ -269,34 +241,11 @@ public:
|
||||
* \throws any rcl errors from rcl_take, \sa rclcpp::exceptions::throw_from_rcl_error()
|
||||
*/
|
||||
bool
|
||||
take(ROSMessageType & message_out, rclcpp::MessageInfo & message_info_out)
|
||||
take(CallbackMessageT & message_out, rclcpp::MessageInfo & message_info_out)
|
||||
{
|
||||
return this->take_type_erased(static_cast<void *>(&message_out), message_info_out);
|
||||
}
|
||||
|
||||
/// Take the next message from the inter-process subscription.
|
||||
/**
|
||||
* This verison takes a SubscribedType which is different frmo the
|
||||
* ROSMessageType when a rclcpp::TypeAdapter is in used.
|
||||
*
|
||||
* \sa take(ROSMessageType &, rclcpp::MessageInfo &)
|
||||
*/
|
||||
template<typename TakeT>
|
||||
std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<TakeT>::value &&
|
||||
std::is_same_v<TakeT, SubscribedType>,
|
||||
bool
|
||||
>
|
||||
take(TakeT & message_out, rclcpp::MessageInfo & message_info_out)
|
||||
{
|
||||
ROSMessageType local_message;
|
||||
bool taken = this->take_type_erased(static_cast<void *>(&local_message), message_info_out);
|
||||
if (taken) {
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_custom(local_message, message_out);
|
||||
}
|
||||
return taken;
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
create_message() override
|
||||
{
|
||||
@@ -323,7 +272,7 @@ public:
|
||||
// we should ignore this copy of the message.
|
||||
return;
|
||||
}
|
||||
auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
|
||||
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> now;
|
||||
if (subscription_topic_statistics_) {
|
||||
@@ -341,24 +290,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override
|
||||
{
|
||||
// TODO(wjwwood): enable topic statistics for serialized messages
|
||||
any_callback_.dispatch(serialized_message, message_info);
|
||||
}
|
||||
|
||||
void
|
||||
handle_loaned_message(
|
||||
void * loaned_message,
|
||||
const rclcpp::MessageInfo & message_info) override
|
||||
{
|
||||
auto typed_message = static_cast<ROSMessageType *>(loaned_message);
|
||||
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<ROSMessageType>(
|
||||
typed_message, [](ROSMessageType * msg) {(void) msg;});
|
||||
auto sptr = std::shared_ptr<CallbackMessageT>(
|
||||
typed_message, [](CallbackMessageT * msg) {(void) msg;});
|
||||
any_callback_.dispatch(sptr, message_info);
|
||||
}
|
||||
|
||||
@@ -369,7 +309,7 @@ public:
|
||||
void
|
||||
return_message(std::shared_ptr<void> & message) override
|
||||
{
|
||||
auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
|
||||
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
|
||||
message_memory_strategy_->return_message(typed_message);
|
||||
}
|
||||
|
||||
@@ -392,24 +332,21 @@ public:
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Subscription)
|
||||
|
||||
AnySubscriptionCallback<MessageT, AllocatorT> any_callback_;
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_callback_;
|
||||
/// Copy of original options passed during construction.
|
||||
/**
|
||||
* It is important to save a copy of this so that the rmw payload which it
|
||||
* may contain is kept alive for the duration of the subscription.
|
||||
*/
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> options_;
|
||||
typename message_memory_strategy::MessageMemoryStrategy<ROSMessageType, AllocatorT>::SharedPtr
|
||||
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, AllocatorT>::SharedPtr
|
||||
message_memory_strategy_;
|
||||
|
||||
/// Component which computes and publishes topic statistics for this subscriber
|
||||
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics_{nullptr};
|
||||
|
||||
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
|
||||
ROSMessageType,
|
||||
CallbackMessageT,
|
||||
AllocatorT,
|
||||
ROSMessageTypeDeleter,
|
||||
MessageT>;
|
||||
typename MessageUniquePtr::deleter_type>;
|
||||
std::shared_ptr<SubscriptionIntraProcessT> subscription_intra_process_;
|
||||
};
|
||||
|
||||
|
||||
@@ -183,13 +183,6 @@ public:
|
||||
void
|
||||
handle_message(std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "rclcpp/get_message_type_support_handle.hpp"
|
||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
@@ -75,23 +74,26 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType
|
||||
>
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
SubscriptionFactory
|
||||
create_subscription_factory(
|
||||
CallbackT && callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat,
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
|
||||
subscription_topic_stats = nullptr
|
||||
)
|
||||
{
|
||||
auto allocator = options.get_allocator();
|
||||
|
||||
using rclcpp::AnySubscriptionCallback;
|
||||
AnySubscriptionCallback<MessageT, AllocatorT> any_subscription_callback(*allocator);
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_subscription_callback(*allocator);
|
||||
any_subscription_callback.set(std::forward<CallbackT>(callback));
|
||||
|
||||
SubscriptionFactory factory {
|
||||
@@ -105,9 +107,9 @@ create_subscription_factory(
|
||||
using rclcpp::Subscription;
|
||||
using rclcpp::SubscriptionBase;
|
||||
|
||||
auto sub = Subscription<MessageT, AllocatorT>::make_shared(
|
||||
auto sub = Subscription<CallbackMessageT, AllocatorT>::make_shared(
|
||||
node_base,
|
||||
rclcpp::get_message_type_support_handle<MessageT>(),
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
topic_name,
|
||||
qos,
|
||||
any_subscription_callback,
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
@@ -87,10 +86,6 @@ struct SubscriptionOptionsBase
|
||||
template<typename Allocator>
|
||||
struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
{
|
||||
static_assert(
|
||||
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
|
||||
"Subscription allocator value type must be void");
|
||||
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = nullptr;
|
||||
|
||||
@@ -112,7 +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();
|
||||
result.allocator = this->get_rcl_allocator();
|
||||
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 =
|
||||
@@ -126,39 +121,15 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Get the allocator, creating one if needed.
|
||||
std::shared_ptr<Allocator>
|
||||
get_allocator() const
|
||||
{
|
||||
if (!this->allocator) {
|
||||
if (!allocator_storage_) {
|
||||
allocator_storage_ = std::make_shared<Allocator>();
|
||||
}
|
||||
return allocator_storage_;
|
||||
return std::make_shared<Allocator>();
|
||||
}
|
||||
return this->allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
using PlainAllocator =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
|
||||
|
||||
rcl_allocator_t
|
||||
get_rcl_allocator() const
|
||||
{
|
||||
if (!plain_allocator_storage_) {
|
||||
plain_allocator_storage_ =
|
||||
std::make_shared<PlainAllocator>(*this->get_allocator());
|
||||
}
|
||||
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
|
||||
}
|
||||
|
||||
// This is a temporal workaround, to make sure that get_allocator()
|
||||
// always returns a copy of the same allocator.
|
||||
mutable std::shared_ptr<Allocator> allocator_storage_;
|
||||
|
||||
// This is a temporal workaround, to keep the plain allocator that backs
|
||||
// up the rcl allocator returned in rcl_subscription_options_t alive.
|
||||
mutable std::shared_ptr<PlainAllocator> plain_allocator_storage_;
|
||||
};
|
||||
|
||||
using SubscriptionOptions = SubscriptionOptionsWithAllocator<std::allocator<void>>;
|
||||
|
||||
@@ -74,14 +74,14 @@ public:
|
||||
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
|
||||
bool use_clock_thread = true);
|
||||
|
||||
/// Attach node to the time source.
|
||||
/// Attack node to the time source.
|
||||
/**
|
||||
* \param node std::shared pointer to a initialized node
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void attachNode(rclcpp::Node::SharedPtr node);
|
||||
|
||||
/// Attach node to the time source.
|
||||
/// Attack node to the time source.
|
||||
/**
|
||||
* If the parameter `use_sim_time` is `true` then the source time is the simulation time,
|
||||
* otherwise the source time is defined by the system.
|
||||
|
||||
@@ -1,201 +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__TYPE_ADAPTER_HPP_
|
||||
#define RCLCPP__TYPE_ADAPTER_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Template structure used to adapt custom, user-defined types to ROS types.
|
||||
/**
|
||||
* Adapting a custom, user-defined type to a ROS type allows that custom type
|
||||
* to be used when publishing and subscribing in ROS.
|
||||
*
|
||||
* In order to adapt a custom type to a ROS type, the user must create a
|
||||
* template specialization of this structure for the custom type.
|
||||
* In that specialization they must:
|
||||
*
|
||||
* - change `is_specialized` to `std::true_type`,
|
||||
* - specify the custom type with `using custom_type = ...`,
|
||||
* - specify the ROS type with `using ros_message_type = ...`,
|
||||
* - provide static convert functions with the signatures:
|
||||
* - static void convert_to_ros(const custom_type &, ros_message_type &)
|
||||
* - static void convert_to_custom(const ros_message_type &, custom_type &)
|
||||
*
|
||||
* The convert functions must convert from one type to the other.
|
||||
*
|
||||
* For example, here is a theoretical example for adapting `std::string` to the
|
||||
* `std_msgs::msg::String` ROS message type:
|
||||
*
|
||||
* template<>
|
||||
* struct rclcpp::TypeAdapter<std::string, std_msgs::msg::String>
|
||||
* {
|
||||
* using is_specialized = std::true_type;
|
||||
* using custom_type = std::string;
|
||||
* using ros_message_type = std_msgs::msg::String;
|
||||
*
|
||||
* static
|
||||
* void
|
||||
* convert_to_ros_message(
|
||||
* const custom_type & source,
|
||||
* ros_message_type & destination)
|
||||
* {
|
||||
* destination.data = source;
|
||||
* }
|
||||
*
|
||||
* static
|
||||
* void
|
||||
* convert_to_custom(
|
||||
* const ros_message_type & source,
|
||||
* custom_type & destination)
|
||||
* {
|
||||
* destination = source.data;
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* The adapter can then be used when creating a publisher or subscription,
|
||||
* e.g.:
|
||||
*
|
||||
* using MyAdaptedType = TypeAdapter<std::string, std_msgs::msg::String>;
|
||||
* auto pub = node->create_publisher<MyAdaptedType>("topic", 10);
|
||||
* auto sub = node->create_subscription<MyAdaptedType>(
|
||||
* "topic",
|
||||
* 10,
|
||||
* [](const std::string & msg) {...});
|
||||
*
|
||||
* You can also be more declarative by using the adapt_type::as metafunctions,
|
||||
* which are a bit less ambiguous to read:
|
||||
*
|
||||
* using AdaptedType = rclcpp::adapt_type<std::string>::as<std_msgs::msg::String>;
|
||||
* auto pub = node->create_publisher<AdaptedType>(...);
|
||||
*
|
||||
* If you wish, you may associate a custom type with a single ROS message type,
|
||||
* allowing you to be a bit more brief when creating entities, e.g.:
|
||||
*
|
||||
* // First you must declare the association, this is similar to how you
|
||||
* // would avoid using the namespace in C++ by doing `using std::vector;`.
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
|
||||
*
|
||||
* // Then you can create things with just the custom type, and the ROS
|
||||
* // message type is implied based on the previous statement.
|
||||
* auto pub = node->create_publisher<std::string>(...);
|
||||
*/
|
||||
template<typename CustomType, typename ROSMessageType = void, class Enable = void>
|
||||
struct TypeAdapter
|
||||
{
|
||||
using is_specialized = std::false_type;
|
||||
using custom_type = CustomType;
|
||||
// In this case, the CustomType is the only thing given, or there is no specialization.
|
||||
// Assign ros_message_type to CustomType for the former case.
|
||||
using ros_message_type = CustomType;
|
||||
};
|
||||
|
||||
/// Helper template to determine if a type is a TypeAdapter, false specialization.
|
||||
template<typename T>
|
||||
struct is_type_adapter : std::false_type {};
|
||||
|
||||
/// Helper template to determine if a type is a TypeAdapter, true specialization.
|
||||
template<typename ... Ts>
|
||||
struct is_type_adapter<TypeAdapter<Ts...>>: std::true_type {};
|
||||
|
||||
/// Identity specialization for TypeAdapter.
|
||||
template<typename T>
|
||||
struct TypeAdapter<T, void, std::enable_if_t<is_type_adapter<T>::value>>: T {};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename CustomType, typename ROSMessageType>
|
||||
struct assert_type_pair_is_specialized_type_adapter
|
||||
{
|
||||
using type_adapter = TypeAdapter<CustomType, ROSMessageType>;
|
||||
static_assert(
|
||||
type_adapter::is_specialized::value,
|
||||
"No type adapter for this custom type/ros message type pair");
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Template metafunction that can make the type being adapted explicit.
|
||||
template<typename CustomType>
|
||||
struct adapt_type
|
||||
{
|
||||
template<typename ROSMessageType>
|
||||
using as = typename ::rclcpp::detail::assert_type_pair_is_specialized_type_adapter<
|
||||
CustomType,
|
||||
ROSMessageType
|
||||
>::type_adapter;
|
||||
};
|
||||
|
||||
/// Implicit type adapter used as a short hand way to create something with just the custom type.
|
||||
/**
|
||||
* This is used when creating a publisher or subscription using just the custom
|
||||
* type in conjunction with RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE().
|
||||
* For example:
|
||||
*
|
||||
* #include "type_adapter_for_std_string_to_std_msgs_String.hpp"
|
||||
*
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
|
||||
*
|
||||
* int main(...) {
|
||||
* // ...
|
||||
* auto pub = node->create_publisher<std::string>(...);
|
||||
* }
|
||||
*
|
||||
* \sa TypeAdapter for more examples.
|
||||
*/
|
||||
template<typename CustomType>
|
||||
struct ImplicitTypeAdapter
|
||||
{
|
||||
using is_specialized = std::false_type;
|
||||
};
|
||||
|
||||
/// Specialization of TypeAdapter for ImplicitTypeAdapter.
|
||||
/**
|
||||
* This allows for things like this:
|
||||
*
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
|
||||
* auto pub = node->create_publisher<std::string>("topic", 10);
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
struct TypeAdapter<T, void, std::enable_if_t<ImplicitTypeAdapter<T>::is_specialized::value>>
|
||||
: ImplicitTypeAdapter<T>
|
||||
{};
|
||||
|
||||
/// Assigns the custom type implicitly to the given custom type/ros message type pair.
|
||||
/**
|
||||
* Note: this macro needs to be used in the root namespace.
|
||||
* We cannot use ::rclcpp to protect against this, due to how GCC interprets the
|
||||
* syntax, see: https://stackoverflow.com/a/2781537
|
||||
*
|
||||
* \sa TypeAdapter
|
||||
* \sa ImplicitTypeAdapter
|
||||
*/
|
||||
#define RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(CustomType, ROSMessageType) \
|
||||
template<> \
|
||||
struct rclcpp::ImplicitTypeAdapter<CustomType> \
|
||||
: public rclcpp::TypeAdapter<CustomType, ROSMessageType> \
|
||||
{ \
|
||||
static_assert( \
|
||||
is_specialized::value, \
|
||||
"Cannot use custom type as ros type when there is no TypeAdapter for that pair"); \
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__TYPE_ADAPTER_HPP_
|
||||
@@ -1,43 +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_SET_POLICIES__ALREADY_ASSOCIATED_WITH_WAIT_SET_EXCEPTION_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__ALREADY_ASSOCIATED_WITH_WAIT_SET_EXCEPTION_HPP_
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
|
||||
class AlreadyAssociatedWithWaitSetException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
template<typename EntityT>
|
||||
explicit
|
||||
AlreadyAssociatedWithWaitSetException(const EntityT & entity_instance)
|
||||
: std::runtime_error(
|
||||
"cannot associate " +
|
||||
rmw::impl::cpp::demangle(entity_instance) +
|
||||
" with wait set because it is already in use by a wait set")
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__ALREADY_ASSOCIATED_WITH_WAIT_SET_EXCEPTION_HPP_
|
||||
@@ -1,41 +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_SET_POLICIES__DETAIL__CLIENT_ENTRY_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__CLIENT_ENTRY_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/entity_entry.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
using ClientEntry =
|
||||
// EntityEntryTemplate<rclcpp::ClientBase, std::shared_ptr<rclcpp::ClientBase>>;
|
||||
EntityEntryTemplate<rclcpp::ClientBase>;
|
||||
using WeakClientEntry =
|
||||
// EntityEntryTemplate<rclcpp::ClientBase, std::weak_ptr<rclcpp::ClientBase>>;
|
||||
EntityEntryTemplate<rclcpp::ClientBase>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__CLIENT_ENTRY_HPP_
|
||||
@@ -1,183 +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_SET_POLICIES__DETAIL__ENTITY_ENTRY_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__ENTITY_ENTRY_HPP_
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/wait_set_policies/already_associated_with_wait_set_exception.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// Forward declaration for use in friend statement.
|
||||
template<typename EntityT>
|
||||
class ManagedEntityEntryTemplate;
|
||||
|
||||
/// Encapsulating class for wait set entities, and gateway to the ManagedEntityEntryTemplate.
|
||||
/**
|
||||
* The entity is stored as a std::shared_ptr.
|
||||
*
|
||||
* This is class can be converted to a "managed" version which ensures the
|
||||
* entity is not associated with another wait set already, then associates it
|
||||
* with the current wait set, and then dissociates it on destruction.
|
||||
*/
|
||||
template<typename EntityT>
|
||||
class EntityEntryTemplate
|
||||
{
|
||||
public:
|
||||
EntityEntryTemplate(std::shared_ptr<EntityT> entity_in = nullptr)
|
||||
: entity_(entity_in)
|
||||
{}
|
||||
private:
|
||||
std::shared_ptr<EntityT> entity_;
|
||||
|
||||
friend ManagedEntityEntryTemplate<EntityT>;
|
||||
};
|
||||
|
||||
/// Managing class for wait set entities, with RAII-style (dis)association with the wait set.
|
||||
/**
|
||||
* The entity is stored as a std::shared_ptr, but ths class can be converted
|
||||
* (one way) into a weak version that stores it as a std::weak_ptr.
|
||||
*
|
||||
* This class will assert that the entity is not already associated with a
|
||||
* wait set, while atomically indicating it is associated with this wait set
|
||||
* to prevent other wait sets from using it, and then on destruction this class
|
||||
* will disassociate it.
|
||||
*
|
||||
* \throws rclcpp::wait_set_policies::AlreadyAssociatedWithWaitSetException if entity
|
||||
* is already associated with a wait set.
|
||||
*/
|
||||
template<typename EntityT>
|
||||
class ManagedEntityEntryTemplate
|
||||
{
|
||||
public:
|
||||
/// The only valid way to construct this is with an unmanaged entity entry.
|
||||
explicit ManagedEntityEntryTemplate(const EntityEntryTemplate<EntityT> & unmanaged_entity_entry)
|
||||
: entity_(unmanaged_entity_entry.entity_)
|
||||
{
|
||||
if (nullptr == entity_) {
|
||||
throw std::invalid_argument("entity cannot be nullptr for a managed entry");
|
||||
}
|
||||
bool already_in_use = entity_->exchange_in_use_by_wait_set_state(true);
|
||||
if (already_in_use) {
|
||||
throw rclcpp::wait_set_policies::AlreadyAssociatedWithWaitSetException(*entity_);
|
||||
}
|
||||
}
|
||||
|
||||
// ManagedEntityEntryTemplate(const ManagedEntityEntryTemplate<EntityT> & other)
|
||||
// {
|
||||
// if (other.should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_) {
|
||||
// throw std::runtime_error("")
|
||||
// }
|
||||
// }
|
||||
|
||||
~ManagedEntityEntryTemplate()
|
||||
{
|
||||
if ((nullptr != entity_)) {
|
||||
bool was_in_use = entity_->exchange_in_use_by_wait_set_state(false);
|
||||
assert(was_in_use);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the interal entity shared pointer.
|
||||
std::shared_ptr<EntityT>
|
||||
get_entity() const
|
||||
{
|
||||
return entity_;
|
||||
}
|
||||
|
||||
/// Reset the entity.
|
||||
/**
|
||||
* Specializations of this class may reset more than one item.
|
||||
* Having this method in all instantiations of this class provides uniform access.
|
||||
*/
|
||||
// void
|
||||
// reset() noexcept
|
||||
// {
|
||||
// entity_.reset();
|
||||
// }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<EntityT> entity_;
|
||||
|
||||
};
|
||||
|
||||
/// Version of ManagedEntityEntryTemplate with weak ownership and best effort disassociation.
|
||||
/**
|
||||
* The entity is stored as a std::weak_ptr, but on destruction, the entity is
|
||||
* locked, and if not nullptr, then it will be marked as not in use by a wait set.
|
||||
*/
|
||||
template<typename EntityT>
|
||||
class WeakManagedEntityEntryTemplate
|
||||
{
|
||||
public:
|
||||
/// Can only be constructed from a moved ManagedEntityEntryTemplate.
|
||||
explicit WeakManagedEntityEntryTemplate(ManagedEntityEntryTemplate<EntityT> && moved_entity_entry)
|
||||
: weak_entity_(moved_entity_entry.get_entity())
|
||||
{}
|
||||
|
||||
~WeakManagedEntityEntryTemplate()
|
||||
{
|
||||
auto entity = weak_entity_.lock();
|
||||
if (nullptr != entity) {
|
||||
bool was_in_use = entity->exchange_in_use_by_wait_set_state(false);
|
||||
assert(was_in_use);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the interal entity weak pointer.
|
||||
std::weak_ptr<EntityT>
|
||||
get_weak_entity() const
|
||||
{
|
||||
return weak_entity_;
|
||||
}
|
||||
|
||||
// /// Lock the entity.
|
||||
// /**
|
||||
// * Specializations of this class may select from more than one item to lock.
|
||||
// * Having this method in all instantiations of this class provides uniform access.
|
||||
// */
|
||||
// std::shared_ptr<EntityT>
|
||||
// lock() const
|
||||
// {
|
||||
// return weak_entity_.lock();
|
||||
// }
|
||||
|
||||
// /// Return true if the entity has expired, otherwise false.
|
||||
// /**
|
||||
// * Specializations of this class may select from more than one item to check.
|
||||
// * Having this method in all instantiations of this class provides uniform access.
|
||||
// */
|
||||
// bool
|
||||
// expired() const noexcept
|
||||
// {
|
||||
// return weak_entity_.expired();
|
||||
// }
|
||||
private:
|
||||
std::weak_ptr<EntityT> weak_entity_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__ENTITY_ENTRY_HPP_
|
||||
@@ -1,41 +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_SET_POLICIES__DETAIL__GUARD_CONDITION_ENTRY_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__GUARD_CONDITION_ENTRY_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/entity_entry.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
using GuardConditionEntry =
|
||||
// EntityEntryTemplate<rclcpp::GuardCondition, std::shared_ptr<rclcpp::GuardCondition>>;
|
||||
EntityEntryTemplate<rclcpp::GuardCondition>;
|
||||
using WeakGuardConditionEntry =
|
||||
// EntityEntryTemplate<rclcpp::GuardCondition, std::weak_ptr<rclcpp::GuardCondition>>;
|
||||
EntityEntryTemplate<rclcpp::GuardCondition>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__GUARD_CONDITION_ENTRY_HPP_
|
||||
@@ -1,41 +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_SET_POLICIES__DETAIL__SERVICE_ENTRY_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__SERVICE_ENTRY_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/entity_entry.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
using ServiceEntry =
|
||||
// EntityEntryTemplate<rclcpp::ServiceBase, std::shared_ptr<rclcpp::ServiceBase>>;
|
||||
EntityEntryTemplate<rclcpp::ServiceBase>;
|
||||
using WeakServiceEntry =
|
||||
// EntityEntryTemplate<rclcpp::ServiceBase, std::weak_ptr<rclcpp::ServiceBase>>;
|
||||
EntityEntryTemplate<rclcpp::ServiceBase>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__SERVICE_ENTRY_HPP_
|
||||
@@ -1,403 +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_SET_POLICIES__DETAIL__SUBSCRIPTION_ENTRY_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__SUBSCRIPTION_ENTRY_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/subscription_wait_set_mask.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/entity_entry.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/waitable_entry.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// See rclcpp::wait_set_policies::detail::EntityEntryTemplate.
|
||||
template<>
|
||||
class EntityEntryTemplate<rclcpp::SubscriptionBase>
|
||||
{
|
||||
using EntityT = rclcpp::SubscriptionBase;
|
||||
|
||||
public:
|
||||
EntityEntryTemplate(
|
||||
std::shared_ptr<EntityT> entity_in = nullptr,
|
||||
const rclcpp::SubscriptionWaitSetMask & mask_in = {})
|
||||
: entity_(entity_in),
|
||||
mask_(mask_in)
|
||||
{}
|
||||
|
||||
/// Create ManagedEntityEntryTemplate instances for the subscription and waitables if needed.
|
||||
/**
|
||||
* This method uses the SubscriptionWaitSetMask to determine how to decompose
|
||||
* the various entities within the subscription into managed entries.
|
||||
*
|
||||
* It optionally returns a managed entry for the subscription, if the mask
|
||||
* indicates it should, and then optionally any waitables for the
|
||||
* intra-process communication and QoS events.
|
||||
*/
|
||||
std::pair<
|
||||
std::optional<ManagedEntityEntryTemplate<rclcpp::SubscriptionBase>>,
|
||||
std::vector<ManagedEntityEntryTemplate<rclcpp::Waitable>>
|
||||
>
|
||||
manage();
|
||||
// defined below ManagedEntityEntryTemplate<rclcpp::SubscriptionBase>.
|
||||
|
||||
private:
|
||||
std::shared_ptr<EntityT> entity_;
|
||||
rclcpp::SubscriptionWaitSetMask mask_;
|
||||
};
|
||||
|
||||
/// See rclcpp::wait_set_policies::detail::ManagedEntityEntryTemplate.
|
||||
template<>
|
||||
class ManagedEntityEntryTemplate<rclcpp::SubscriptionBase>
|
||||
{
|
||||
using EntityT = rclcpp::SubscriptionBase;
|
||||
|
||||
/// Only constructed by EntityEntryTemplate<rclcpp::SubscriptionBase>::manage().
|
||||
explicit ManagedEntityEntryTemplate(std::shared_ptr<EntityT> subscription)
|
||||
: entity_(subscription)
|
||||
{
|
||||
if (nullptr == entity_) {
|
||||
throw std::invalid_argument("entity cannot be nullptr for a managed entry");
|
||||
}
|
||||
bool already_in_use = entity_->exchange_in_use_by_wait_set_state(entity_.get(), true);
|
||||
if (already_in_use) {
|
||||
throw rclcpp::wait_set_policies::AlreadyAssociatedWithWaitSetException(*entity_);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// ManagedEntityEntryTemplate(const ManagedEntityEntryTemplate<EntityT> & other)
|
||||
// {
|
||||
// if (other.should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_) {
|
||||
// throw std::runtime_error("")
|
||||
// }
|
||||
// }
|
||||
|
||||
~ManagedEntityEntryTemplate()
|
||||
{
|
||||
if ((nullptr != entity_)) {
|
||||
bool was_in_use = entity_->exchange_in_use_by_wait_set_state(entity_.get(), false);
|
||||
assert(was_in_use);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the interal entity shared pointer.
|
||||
std::shared_ptr<EntityT>
|
||||
get_entity() const
|
||||
{
|
||||
return entity_;
|
||||
}
|
||||
|
||||
/// Reset the entity.
|
||||
/**
|
||||
* Specializations of this class may reset more than one item.
|
||||
* Having this method in all instantiations of this class provides uniform access.
|
||||
*/
|
||||
// void
|
||||
// reset() noexcept
|
||||
// {
|
||||
// entity_.reset();
|
||||
// }
|
||||
|
||||
private:
|
||||
std::shared_ptr<EntityT> entity_;
|
||||
|
||||
friend EntityEntryTemplate<EntityT>;
|
||||
|
||||
};
|
||||
|
||||
std::pair<
|
||||
std::optional<ManagedEntityEntryTemplate<rclcpp::SubscriptionBase>>,
|
||||
std::vector<ManagedEntityEntryTemplate<rclcpp::Waitable>>
|
||||
>
|
||||
EntityEntryTemplate<rclcpp::SubscriptionBase>::manage()
|
||||
{
|
||||
std::optional<ManagedEntityEntryTemplate<rclcpp::SubscriptionBase>> managed_subscription_entry;
|
||||
std::vector<ManagedEntityEntryTemplate<rclcpp::Waitable>> waitables;
|
||||
|
||||
if (mask_.include_subscription) {
|
||||
managed_subscription_entry = ManagedEntityEntryTemplate<rclcpp::SubscriptionBase>(entity_);
|
||||
}
|
||||
if (mask_.include_events) {
|
||||
for (const auto & event_waitable : entity_->get_event_handlers()) {
|
||||
waitables.emplace_back(EntityEntryTemplate<rclcpp::Waitable>(event_waitable, entity_));
|
||||
}
|
||||
}
|
||||
if (mask_.include_intra_process_waitable) {
|
||||
waitables.emplace_back(
|
||||
EntityEntryTemplate<rclcpp::Waitable>(entity_->get_intra_process_waitable(), entity_)
|
||||
);
|
||||
}
|
||||
|
||||
return {managed_subscription_entry, waitables};
|
||||
}
|
||||
|
||||
/// See rclcpp::wait_set_policies::detail::WeakManagedEntityEntryTemplate.
|
||||
template<>
|
||||
class WeakManagedEntityEntryTemplate<rclcpp::SubscriptionBase>
|
||||
{
|
||||
using EntityT = rclcpp::SubscriptionBase;
|
||||
|
||||
public:
|
||||
/// Can only be constructed from a moved ManagedEntityEntryTemplate.
|
||||
explicit WeakManagedEntityEntryTemplate(ManagedEntityEntryTemplate<EntityT> && moved_entity_entry)
|
||||
: weak_entity_(moved_entity_entry.get_entity())
|
||||
{}
|
||||
|
||||
~WeakManagedEntityEntryTemplate()
|
||||
{
|
||||
auto entity = weak_entity_.lock();
|
||||
if (nullptr != entity) {
|
||||
bool was_in_use = entity->exchange_in_use_by_wait_set_state(entity.get(), false);
|
||||
assert(was_in_use);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the interal entity weak pointer.
|
||||
std::weak_ptr<EntityT>
|
||||
get_weak_entity() const
|
||||
{
|
||||
return weak_entity_;
|
||||
}
|
||||
|
||||
// /// Lock the entity.
|
||||
// /**
|
||||
// * Specializations of this class may select from more than one item to lock.
|
||||
// * Having this method in all instantiations of this class provides uniform access.
|
||||
// */
|
||||
// std::shared_ptr<EntityT>
|
||||
// lock() const
|
||||
// {
|
||||
// return weak_entity_.lock();
|
||||
// }
|
||||
|
||||
// /// Return true if the entity has expired, otherwise false.
|
||||
// /**
|
||||
// * Specializations of this class may select from more than one item to check.
|
||||
// * Having this method in all instantiations of this class provides uniform access.
|
||||
// */
|
||||
// bool
|
||||
// expired() const noexcept
|
||||
// {
|
||||
// return weak_entity_.expired();
|
||||
// }
|
||||
private:
|
||||
std::weak_ptr<EntityT> weak_entity_;
|
||||
std::weak_ptr<void> weak_associated_entity_;
|
||||
|
||||
};
|
||||
|
||||
using SubscriptionEntry = EntityEntryTemplate<rclcpp::SubscriptionBase>;
|
||||
using ManagedSubscriptionEntry = ManagedEntityEntryTemplate<rclcpp::SubscriptionBase>;
|
||||
using WeakManagedSubscriptionEntry = WeakManagedEntityEntryTemplate<rclcpp::SubscriptionBase>;
|
||||
|
||||
// /// Specialization for Subscriptions.
|
||||
// template<>
|
||||
// class EntityEntryTemplate<rclcpp::SubscriptionBase>
|
||||
// {
|
||||
// using EntityT = rclcpp::SubscriptionBase;
|
||||
// std::shared_ptr<EntityT> entity_;
|
||||
// rclcpp::SubscriptionWaitSetMask mask_;
|
||||
|
||||
// public:
|
||||
// EntityEntryTemplate(
|
||||
// std::shared_ptr<EntityT> entity_in = nullptr,
|
||||
// const rclcpp::SubscriptionWaitSetMask & mask_in = {})
|
||||
// : entity_(entity_in),
|
||||
// mask_(mask_in)
|
||||
// {}
|
||||
|
||||
// ~EntityEntryTemplate()
|
||||
// {
|
||||
// if (should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_) {
|
||||
// EntityEntryTemplate<rclcpp::SubscriptionBase>::cleanup(entity_, mask_);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// See EntityEntryTemplate::get_entity().
|
||||
// std::shared_ptr<EntityT>
|
||||
// get_entity() const
|
||||
// {
|
||||
// return entity_;
|
||||
// }
|
||||
|
||||
// /// Return a const reference to the subscrption mask.
|
||||
// const rclcpp::SubscriptionWaitSetMask &
|
||||
// get_mask() const
|
||||
// {
|
||||
// return mask_;
|
||||
// }
|
||||
|
||||
// /// See EntityEntryTemplate::manage().
|
||||
// std::vector<WaitableEntry>
|
||||
// manage()
|
||||
// {
|
||||
// if (nullptr == entity_) {
|
||||
// throw std::runtime_error("manage() called on EntityEntry with null entity");
|
||||
// }
|
||||
// auto associate = [this](void * entity_part) {
|
||||
// bool already_in_use = entity_->exchange_in_use_by_wait_set_state(entity_part, true);
|
||||
// if (already_in_use) {
|
||||
// throw rclcpp::wait_set_policies::AlreadyAssociatedWithWaitSetException(*entity_);
|
||||
// }
|
||||
// };
|
||||
|
||||
// if (mask_.include_subscription) {
|
||||
// associate(entity_.get());
|
||||
// }
|
||||
|
||||
// std::vector<WaitableEntry> decomposed_waitables;
|
||||
|
||||
// if (mask_.include_events) {
|
||||
// for (auto event : entity_->get_event_handlers()) {
|
||||
// // TODO(wjwwood): do we need to use the unmanage_function argument
|
||||
// // to utilize the exchange_in_use_by_wait_set_state of SubscriptionBase?
|
||||
// decomposed_waitables.emplace_back(event, entity_);
|
||||
// decomposed_waitables.back().manage();
|
||||
// }
|
||||
// // mask_.include_events = false;
|
||||
// }
|
||||
// if (mask_.include_intra_process_waitable) {
|
||||
// auto waitable = entity_->get_intra_process_waitable();
|
||||
// if (nullptr != waitable) {
|
||||
// // TODO(wjwwood): do we need to use the unmanage_function argument
|
||||
// // to utilize the exchange_in_use_by_wait_set_state of SubscriptionBase?
|
||||
// decomposed_waitables.emplace_back(waitable, entity_);
|
||||
// decomposed_waitables.back().manage();
|
||||
// // mask_.include_intra_process_waitable = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_ = true;
|
||||
|
||||
// return decomposed_waitables;
|
||||
// }
|
||||
|
||||
// /// See EntityEntryTemplate::reset().
|
||||
// void
|
||||
// reset() noexcept
|
||||
// {
|
||||
// entity_.reset();
|
||||
// }
|
||||
|
||||
// protected:
|
||||
// bool should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_{false};
|
||||
|
||||
// static
|
||||
// void
|
||||
// cleanup(std::shared_ptr<EntityT> subscription, rclcpp::SubscriptionWaitSetMask mask)
|
||||
// {
|
||||
// if (subscription != nullptr) {
|
||||
// auto dissociate = [&subscription](void * entity_part) {
|
||||
// bool was_in_use = subscription->exchange_in_use_by_wait_set_state(entity_part, false);
|
||||
// assert(was_in_use);
|
||||
// };
|
||||
// if (mask.include_subscription) {
|
||||
// dissociate(subscription.get());
|
||||
// }
|
||||
// if (mask.include_events) {
|
||||
// for (auto event : subscription->get_event_handlers()) {
|
||||
// dissociate(event.get());
|
||||
// }
|
||||
// }
|
||||
// if (mask.include_intra_process_waitable) {
|
||||
// auto waitable = subscription->get_intra_process_waitable();
|
||||
// if (nullptr != waitable) {
|
||||
// dissociate(waitable.get());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// friend WeakEntityEntryTemplate<EntityT>;
|
||||
|
||||
// };
|
||||
|
||||
// /// Specialization for Subscriptions.
|
||||
// template<>
|
||||
// class WeakEntityEntryTemplate<rclcpp::SubscriptionBase>
|
||||
// {
|
||||
// using EntityT = rclcpp::SubscriptionBase;
|
||||
// std::weak_ptr<EntityT> weak_entity_;
|
||||
// rclcpp::SubscriptionWaitSetMask mask_;
|
||||
|
||||
// public:
|
||||
// explicit WeakEntityEntryTemplate(EntityEntryTemplate<EntityT> && moved_entity_entry)
|
||||
// : weak_entity_(moved_entity_entry.get_entity()),
|
||||
// mask_(moved_entity_entry.mask_),
|
||||
// should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_(
|
||||
// moved_entity_entry.should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_
|
||||
// )
|
||||
// {
|
||||
// moved_entity_entry.should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_ = false;
|
||||
// }
|
||||
|
||||
// ~WeakEntityEntryTemplate()
|
||||
// {
|
||||
// auto entity = weak_entity_.lock();
|
||||
// if (should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_) {
|
||||
// EntityEntryTemplate<rclcpp::SubscriptionBase>::cleanup(entity, mask_);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// See WeakEntityEntryTemplate::get_weak_entity().
|
||||
// std::weak_ptr<EntityT>
|
||||
// get_weak_entity() const
|
||||
// {
|
||||
// return weak_entity_;
|
||||
// }
|
||||
|
||||
// /// Return a const reference to the subscrption mask.
|
||||
// const rclcpp::SubscriptionWaitSetMask &
|
||||
// get_mask() const
|
||||
// {
|
||||
// return mask_;
|
||||
// }
|
||||
|
||||
// /// See WeakEntityEntryTemplate::lock().
|
||||
// std::shared_ptr<EntityT>
|
||||
// lock() const
|
||||
// {
|
||||
// return weak_entity_.lock();
|
||||
// }
|
||||
|
||||
// /// See WeakEntityEntryTemplate::expired().
|
||||
// bool
|
||||
// expired() const noexcept
|
||||
// {
|
||||
// return weak_entity_.expired();
|
||||
// }
|
||||
|
||||
// protected:
|
||||
// bool should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_{false};
|
||||
|
||||
// };
|
||||
|
||||
// using SubscriptionEntry = EntityEntryTemplate<rclcpp::SubscriptionBase>;
|
||||
// using WeakSubscriptionEntry = WeakEntityEntryTemplate<rclcpp::SubscriptionBase>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__SUBSCRIPTION_ENTRY_HPP_
|
||||
@@ -1,41 +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_SET_POLICIES__DETAIL__TIMER_ENTRY_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__TIMER_ENTRY_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/entity_entry.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
using TimerEntry =
|
||||
// EntityEntryTemplate<rclcpp::TimerBase, std::shared_ptr<rclcpp::TimerBase>>;
|
||||
EntityEntryTemplate<rclcpp::TimerBase>;
|
||||
using WeakTimerEntry =
|
||||
// EntityEntryTemplate<rclcpp::TimerBase, std::weak_ptr<rclcpp::TimerBase>>;
|
||||
EntityEntryTemplate<rclcpp::TimerBase>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__TIMER_ENTRY_HPP_
|
||||
@@ -1,183 +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_SET_POLICIES__DETAIL__WAITABLE_ENTRY_HPP_
|
||||
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__WAITABLE_ENTRY_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/waitable.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/entity_entry.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace wait_set_policies
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// See rclcpp::wait_set_policies::detail::EntityEntryTemplate.
|
||||
template<>
|
||||
class EntityEntryTemplate<rclcpp::Waitable>
|
||||
{
|
||||
using EntityT = rclcpp::Waitable;
|
||||
|
||||
public:
|
||||
EntityEntryTemplate(
|
||||
std::shared_ptr<EntityT> entity_in = nullptr,
|
||||
std::shared_ptr<void> associated_entity_in = nullptr)
|
||||
: entity_(entity_in),
|
||||
associated_entity_(associated_entity_in)
|
||||
{}
|
||||
private:
|
||||
std::shared_ptr<EntityT> entity_;
|
||||
std::shared_ptr<void> associated_entity_;
|
||||
|
||||
friend ManagedEntityEntryTemplate<EntityT>;
|
||||
};
|
||||
|
||||
/// See rclcpp::wait_set_policies::detail::ManagedEntityEntryTemplate.
|
||||
template<>
|
||||
class ManagedEntityEntryTemplate<rclcpp::Waitable>
|
||||
{
|
||||
using EntityT = rclcpp::Waitable;
|
||||
|
||||
public:
|
||||
/// The only valid way to construct this is with an unmanaged entity entry.
|
||||
explicit ManagedEntityEntryTemplate(const EntityEntryTemplate<EntityT> & unmanaged_entity_entry)
|
||||
: entity_(unmanaged_entity_entry.entity_),
|
||||
associated_entity_(unmanaged_entity_entry.associated_entity_)
|
||||
{
|
||||
if (nullptr == entity_) {
|
||||
throw std::invalid_argument("entity cannot be nullptr for a managed entry");
|
||||
}
|
||||
bool already_in_use = entity_->exchange_in_use_by_wait_set_state(true);
|
||||
if (already_in_use) {
|
||||
throw rclcpp::wait_set_policies::AlreadyAssociatedWithWaitSetException(*entity_);
|
||||
}
|
||||
}
|
||||
|
||||
// ManagedEntityEntryTemplate(const ManagedEntityEntryTemplate<EntityT> & other)
|
||||
// {
|
||||
// if (other.should_set_in_use_by_wait_set_of_entity_to_false_on_destruction_) {
|
||||
// throw std::runtime_error("")
|
||||
// }
|
||||
// }
|
||||
|
||||
~ManagedEntityEntryTemplate()
|
||||
{
|
||||
if ((nullptr != entity_)) {
|
||||
bool was_in_use = entity_->exchange_in_use_by_wait_set_state(false);
|
||||
assert(was_in_use);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the interal entity shared pointer.
|
||||
std::shared_ptr<EntityT>
|
||||
get_entity() const
|
||||
{
|
||||
return entity_;
|
||||
}
|
||||
|
||||
/// Return the interal associated entity shared pointer.
|
||||
std::shared_ptr<void>
|
||||
get_associated_entity() const
|
||||
{
|
||||
return associated_entity_;
|
||||
}
|
||||
|
||||
/// Reset the entity.
|
||||
/**
|
||||
* Specializations of this class may reset more than one item.
|
||||
* Having this method in all instantiations of this class provides uniform access.
|
||||
*/
|
||||
// void
|
||||
// reset() noexcept
|
||||
// {
|
||||
// entity_.reset();
|
||||
// }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<EntityT> entity_;
|
||||
std::shared_ptr<void> associated_entity_;
|
||||
|
||||
};
|
||||
|
||||
/// See rclcpp::wait_set_policies::detail::WeakManagedEntityEntryTemplate.
|
||||
template<>
|
||||
class WeakManagedEntityEntryTemplate<rclcpp::Waitable>
|
||||
{
|
||||
using EntityT = rclcpp::Waitable;
|
||||
|
||||
public:
|
||||
/// Can only be constructed from a moved ManagedEntityEntryTemplate.
|
||||
explicit WeakManagedEntityEntryTemplate(ManagedEntityEntryTemplate<EntityT> && moved_entity_entry)
|
||||
: weak_entity_(moved_entity_entry.get_entity()),
|
||||
weak_associated_entity_(moved_entity_entry.get_associated_entity())
|
||||
{}
|
||||
|
||||
~WeakManagedEntityEntryTemplate()
|
||||
{
|
||||
auto entity = weak_entity_.lock();
|
||||
if (nullptr != entity) {
|
||||
bool was_in_use = entity->exchange_in_use_by_wait_set_state(false);
|
||||
assert(was_in_use);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the interal entity weak pointer.
|
||||
std::weak_ptr<EntityT>
|
||||
get_weak_entity() const
|
||||
{
|
||||
return weak_entity_;
|
||||
}
|
||||
|
||||
// /// Lock the entity.
|
||||
// /**
|
||||
// * Specializations of this class may select from more than one item to lock.
|
||||
// * Having this method in all instantiations of this class provides uniform access.
|
||||
// */
|
||||
// std::shared_ptr<EntityT>
|
||||
// lock() const
|
||||
// {
|
||||
// return weak_entity_.lock();
|
||||
// }
|
||||
|
||||
// /// Return true if the entity has expired, otherwise false.
|
||||
// /**
|
||||
// * Specializations of this class may select from more than one item to check.
|
||||
// * Having this method in all instantiations of this class provides uniform access.
|
||||
// */
|
||||
// bool
|
||||
// expired() const noexcept
|
||||
// {
|
||||
// return weak_entity_.expired();
|
||||
// }
|
||||
private:
|
||||
std::weak_ptr<EntityT> weak_entity_;
|
||||
std::weak_ptr<void> weak_associated_entity_;
|
||||
|
||||
};
|
||||
|
||||
using WaitableEntry = EntityEntryTemplate<rclcpp::Waitable>;
|
||||
using ManagedWaitableEntry = ManagedEntityEntryTemplate<rclcpp::Waitable>;
|
||||
using WeakManagedWaitableEntry = WeakManagedEntityEntryTemplate<rclcpp::Waitable>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace wait_set_policies
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__WAITABLE_ENTRY_HPP_
|
||||
@@ -28,13 +28,7 @@
|
||||
#include "rclcpp/subscription_wait_set_mask.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/client_entry.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/guard_condition_entry.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/service_entry.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/storage_policy_common.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/subscription_entry.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/timer_entry.hpp"
|
||||
#include "rclcpp/wait_set_policies/detail/waitable_entry.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -48,27 +42,124 @@ class DynamicStorage : public rclcpp::wait_set_policies::detail::StoragePolicyCo
|
||||
protected:
|
||||
using is_mutable = std::true_type;
|
||||
|
||||
using WeakManagedSubscriptionEntry = detail::WeakManagedSubscriptionEntry;
|
||||
using SubscriptionEntry = detail::SubscriptionEntry;
|
||||
class SubscriptionEntry
|
||||
{
|
||||
// (wjwwood): indent of 'public:' is weird, I know. uncrustify is dumb.
|
||||
|
||||
using SequenceOfWeakSubscriptions = std::vector<WeakManagedSubscriptionEntry>;
|
||||
public:
|
||||
std::shared_ptr<rclcpp::SubscriptionBase> subscription;
|
||||
rclcpp::SubscriptionWaitSetMask mask;
|
||||
|
||||
/// Conversion constructor, which is intentionally not marked explicit.
|
||||
SubscriptionEntry(
|
||||
std::shared_ptr<rclcpp::SubscriptionBase> subscription_in = nullptr,
|
||||
const rclcpp::SubscriptionWaitSetMask & mask_in = {})
|
||||
: subscription(std::move(subscription_in)),
|
||||
mask(mask_in)
|
||||
{}
|
||||
|
||||
void
|
||||
reset() noexcept
|
||||
{
|
||||
subscription.reset();
|
||||
}
|
||||
};
|
||||
class WeakSubscriptionEntry
|
||||
{
|
||||
public:
|
||||
std::weak_ptr<rclcpp::SubscriptionBase> subscription;
|
||||
rclcpp::SubscriptionWaitSetMask mask;
|
||||
|
||||
explicit WeakSubscriptionEntry(
|
||||
const std::shared_ptr<rclcpp::SubscriptionBase> & subscription_in,
|
||||
const rclcpp::SubscriptionWaitSetMask & mask_in) noexcept
|
||||
: subscription(subscription_in),
|
||||
mask(mask_in)
|
||||
{}
|
||||
|
||||
explicit WeakSubscriptionEntry(const SubscriptionEntry & other)
|
||||
: subscription(other.subscription),
|
||||
mask(other.mask)
|
||||
{}
|
||||
|
||||
std::shared_ptr<rclcpp::SubscriptionBase>
|
||||
lock() const
|
||||
{
|
||||
return subscription.lock();
|
||||
}
|
||||
|
||||
bool
|
||||
expired() const noexcept
|
||||
{
|
||||
return subscription.expired();
|
||||
}
|
||||
};
|
||||
using SequenceOfWeakSubscriptions = std::vector<WeakSubscriptionEntry>;
|
||||
using SubscriptionsIterable = std::vector<SubscriptionEntry>;
|
||||
|
||||
using SequenceOfWeakGuardConditions = std::vector<detail::WeakGuardConditionEntry>;
|
||||
using GuardConditionsIterable = std::vector<detail::GuardConditionEntry>;
|
||||
using SequenceOfWeakGuardConditions = std::vector<std::weak_ptr<rclcpp::GuardCondition>>;
|
||||
using GuardConditionsIterable = std::vector<std::shared_ptr<rclcpp::GuardCondition>>;
|
||||
|
||||
using SequenceOfWeakTimers = std::vector<detail::WeakTimerEntry>;
|
||||
using TimersIterable = std::vector<detail::TimerEntry>;
|
||||
using SequenceOfWeakTimers = std::vector<std::weak_ptr<rclcpp::TimerBase>>;
|
||||
using TimersIterable = std::vector<std::shared_ptr<rclcpp::TimerBase>>;
|
||||
|
||||
using SequenceOfWeakClients = std::vector<detail::WeakClientEntry>;
|
||||
using ClientsIterable = std::vector<detail::ClientEntry>;
|
||||
using SequenceOfWeakClients = std::vector<std::weak_ptr<rclcpp::ClientBase>>;
|
||||
using ClientsIterable = std::vector<std::shared_ptr<rclcpp::ClientBase>>;
|
||||
|
||||
using SequenceOfWeakServices = std::vector<detail::WeakServiceEntry>;
|
||||
using ServicesIterable = std::vector<detail::ServiceEntry>;
|
||||
using SequenceOfWeakServices = std::vector<std::weak_ptr<rclcpp::ServiceBase>>;
|
||||
using ServicesIterable = std::vector<std::shared_ptr<rclcpp::ServiceBase>>;
|
||||
|
||||
using WeakWaitableEntry = detail::WeakWaitableEntry;
|
||||
using WaitableEntry = detail::WaitableEntry;
|
||||
class WaitableEntry
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<rclcpp::Waitable> waitable;
|
||||
std::shared_ptr<void> associated_entity;
|
||||
|
||||
/// Conversion constructor, which is intentionally not marked explicit.
|
||||
WaitableEntry(
|
||||
std::shared_ptr<rclcpp::Waitable> waitable_in = nullptr,
|
||||
std::shared_ptr<void> associated_entity_in = nullptr) noexcept
|
||||
: waitable(std::move(waitable_in)),
|
||||
associated_entity(std::move(associated_entity_in))
|
||||
{}
|
||||
|
||||
void
|
||||
reset() noexcept
|
||||
{
|
||||
waitable.reset();
|
||||
associated_entity.reset();
|
||||
}
|
||||
};
|
||||
class WeakWaitableEntry
|
||||
{
|
||||
public:
|
||||
std::weak_ptr<rclcpp::Waitable> waitable;
|
||||
std::weak_ptr<void> associated_entity;
|
||||
|
||||
explicit WeakWaitableEntry(
|
||||
const std::shared_ptr<rclcpp::Waitable> & waitable_in,
|
||||
const std::shared_ptr<void> & associated_entity_in) noexcept
|
||||
: waitable(waitable_in),
|
||||
associated_entity(associated_entity_in)
|
||||
{}
|
||||
|
||||
explicit WeakWaitableEntry(const WaitableEntry & other)
|
||||
: waitable(other.waitable),
|
||||
associated_entity(other.associated_entity)
|
||||
{}
|
||||
|
||||
std::shared_ptr<rclcpp::Waitable>
|
||||
lock() const
|
||||
{
|
||||
return waitable.lock();
|
||||
}
|
||||
|
||||
bool
|
||||
expired() const noexcept
|
||||
{
|
||||
return waitable.expired();
|
||||
}
|
||||
};
|
||||
using SequenceOfWeakWaitables = std::vector<WeakWaitableEntry>;
|
||||
using WaitablesIterable = std::vector<WaitableEntry>;
|
||||
|
||||
@@ -93,9 +184,8 @@ protected:
|
||||
services,
|
||||
waitables,
|
||||
context),
|
||||
// subscriptions_ is populated in the constructor dynamically, in order
|
||||
// to respect the mask.
|
||||
// shared_subscriptions_ is resized based on the result of subscriptions_.
|
||||
subscriptions_(subscriptions.cbegin(), subscriptions.cend()),
|
||||
shared_subscriptions_(subscriptions_.size()),
|
||||
guard_conditions_(guard_conditions.cbegin(), guard_conditions.cend()),
|
||||
shared_guard_conditions_(guard_conditions_.size()),
|
||||
timers_(timers.cbegin(), timers.cend()),
|
||||
@@ -104,39 +194,9 @@ protected:
|
||||
shared_clients_(clients_.size()),
|
||||
services_(services.cbegin(), services.cend()),
|
||||
shared_services_(services_.size()),
|
||||
waitables_(waitables.cbegin(), waitables.cend())
|
||||
// shared_waitables_ is resized based on the result of waitables_ after
|
||||
// waitables from subscriptions are added, if any.
|
||||
{
|
||||
// Ensure subscriptions are not being used by other wait sets and extract
|
||||
// their waitables, if they have them.
|
||||
std::vector<WaitableEntry> waitables_from_subscriptions;
|
||||
for (auto & subscription_entry : subscriptions) {
|
||||
std::vector<WaitableEntry> local_waitables_from_subscriptions = subscription_entry.manage();
|
||||
if (subscription_entry.get_mask().include_subscription) {
|
||||
subscriptions_.push_back(subscription_entry);
|
||||
}
|
||||
}
|
||||
// Add subscription entries from subscriptions, if the subscription mask indicates.
|
||||
std::copy_if(
|
||||
subscriptions.cbegin(),
|
||||
subscriptions.cend(),
|
||||
std::back_inserter(subscriptions_),
|
||||
[](const auto & subscription_entry) {
|
||||
return subscription_entry.mask.include_subscription;
|
||||
}
|
||||
);
|
||||
shared_subscriptions_.resize(subscriptions_.size());
|
||||
// Add waitables from subscriptions, if the subscription mask indicates.
|
||||
for (const auto & subscription_entry : subscriptions) {
|
||||
if (subscription_entry.mask.include_events) {
|
||||
for (const auto & event : subscription_entry.subscription->get_event_handlers()) {
|
||||
waitables_.push_back({event, subscription_entry.subscription});
|
||||
}
|
||||
}
|
||||
}
|
||||
shared_waitables_.resize(waitables_.size());
|
||||
}
|
||||
waitables_(waitables.cbegin(), waitables.cend()),
|
||||
shared_waitables_(waitables_.size())
|
||||
{}
|
||||
|
||||
~DynamicStorage() = default;
|
||||
|
||||
@@ -183,7 +243,7 @@ protected:
|
||||
if (this->storage_has_entity(*subscription, subscriptions_)) {
|
||||
throw std::runtime_error("subscription already in wait set");
|
||||
}
|
||||
WeakManagedSubscriptionEntry weak_entry{std::move(subscription), {}};
|
||||
WeakSubscriptionEntry weak_entry{std::move(subscription), {}};
|
||||
subscriptions_.push_back(std::move(weak_entry));
|
||||
this->storage_flag_for_resize();
|
||||
}
|
||||
|
||||
@@ -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>11.0.0</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>
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "rcutils/error_handling.h"
|
||||
#include "rcutils/macros.h"
|
||||
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
|
||||
#include "./logging_mutex.hpp"
|
||||
|
||||
using rclcpp::Context;
|
||||
@@ -313,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
|
||||
@@ -346,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>
|
||||
|
||||
@@ -56,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) {
|
||||
@@ -138,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>
|
||||
@@ -268,9 +260,7 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
|
||||
// If the node already has an executor
|
||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||
if (has_executor.exchange(true)) {
|
||||
throw std::runtime_error(
|
||||
std::string("Node '") + node_ptr->get_fully_qualified_name() +
|
||||
"' has already been added to an executor.");
|
||||
throw std::runtime_error("Node has already been added to an executor.");
|
||||
}
|
||||
std::lock_guard<std::mutex> guard{mutex_};
|
||||
for (auto & weak_group : node_ptr->get_callback_groups()) {
|
||||
@@ -591,7 +581,8 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
|
||||
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
|
||||
[&]()
|
||||
{
|
||||
subscription->handle_serialized_message(serialized_msg, message_info);
|
||||
auto void_serialized_msg = std::static_pointer_cast<void>(serialized_msg);
|
||||
subscription->handle_message(void_serialized_msg, message_info);
|
||||
});
|
||||
subscription->return_serialized_message(serialized_msg);
|
||||
} else if (subscription->can_loan_messages()) {
|
||||
|
||||
@@ -36,19 +36,11 @@ std::shared_ptr<rclcpp::SerializedMessage> GenericSubscription::create_serialize
|
||||
}
|
||||
|
||||
void GenericSubscription::handle_message(
|
||||
std::shared_ptr<void> &,
|
||||
const rclcpp::MessageInfo &)
|
||||
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"handle_message is not implemented for GenericSubscription");
|
||||
}
|
||||
|
||||
void
|
||||
GenericSubscription::handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & message,
|
||||
const rclcpp::MessageInfo &)
|
||||
{
|
||||
callback_(message);
|
||||
(void) message_info;
|
||||
auto typed_message = std::static_pointer_cast<rclcpp::SerializedMessage>(message);
|
||||
callback_(typed_message);
|
||||
}
|
||||
|
||||
void GenericSubscription::handle_loaned_message(
|
||||
|
||||
@@ -36,26 +36,23 @@ IntraProcessManager::add_publisher(rclcpp::PublisherBase::SharedPtr publisher)
|
||||
{
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
uint64_t pub_id = IntraProcessManager::get_next_unique_id();
|
||||
auto id = IntraProcessManager::get_next_unique_id();
|
||||
|
||||
publishers_[pub_id] = publisher;
|
||||
publishers_[id].publisher = publisher;
|
||||
publishers_[id].topic_name = publisher->get_topic_name();
|
||||
publishers_[id].qos = publisher->get_actual_qos().get_rmw_qos_profile();
|
||||
|
||||
// Initialize the subscriptions storage for this publisher.
|
||||
pub_to_subs_[pub_id] = SplittedSubscriptions();
|
||||
pub_to_subs_[id] = SplittedSubscriptions();
|
||||
|
||||
// create an entry for the publisher id and populate with already existing subscriptions
|
||||
for (auto & pair : subscriptions_) {
|
||||
auto subscription = pair.second.lock();
|
||||
if (!subscription) {
|
||||
continue;
|
||||
}
|
||||
if (can_communicate(publisher, subscription)) {
|
||||
uint64_t sub_id = pair.first;
|
||||
insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
|
||||
if (can_communicate(publishers_[id], pair.second)) {
|
||||
insert_sub_id_for_pub(pair.first, id, pair.second.use_take_shared_method);
|
||||
}
|
||||
}
|
||||
|
||||
return pub_id;
|
||||
return id;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@@ -63,23 +60,21 @@ IntraProcessManager::add_subscription(SubscriptionIntraProcessBase::SharedPtr su
|
||||
{
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
uint64_t sub_id = IntraProcessManager::get_next_unique_id();
|
||||
auto id = IntraProcessManager::get_next_unique_id();
|
||||
|
||||
subscriptions_[sub_id] = subscription;
|
||||
subscriptions_[id].subscription = subscription;
|
||||
subscriptions_[id].topic_name = subscription->get_topic_name();
|
||||
subscriptions_[id].qos = subscription->get_actual_qos();
|
||||
subscriptions_[id].use_take_shared_method = subscription->use_take_shared_method();
|
||||
|
||||
// adds the subscription id to all the matchable publishers
|
||||
for (auto & pair : publishers_) {
|
||||
auto publisher = pair.second.lock();
|
||||
if (!publisher) {
|
||||
continue;
|
||||
}
|
||||
if (can_communicate(publisher, subscription)) {
|
||||
uint64_t pub_id = pair.first;
|
||||
insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
|
||||
if (can_communicate(pair.second, subscriptions_[id])) {
|
||||
insert_sub_id_for_pub(id, pair.first, subscriptions_[id].use_take_shared_method);
|
||||
}
|
||||
}
|
||||
|
||||
return sub_id;
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -121,7 +116,7 @@ IntraProcessManager::matches_any_publishers(const rmw_gid_t * id) const
|
||||
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
for (auto & publisher_pair : publishers_) {
|
||||
auto publisher = publisher_pair.second.lock();
|
||||
auto publisher = publisher_pair.second.publisher.lock();
|
||||
if (!publisher) {
|
||||
continue;
|
||||
}
|
||||
@@ -162,7 +157,7 @@ IntraProcessManager::get_subscription_intra_process(uint64_t intra_process_subsc
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
auto subscription = subscription_it->second.lock();
|
||||
auto subscription = subscription_it->second.subscription.lock();
|
||||
if (subscription) {
|
||||
return subscription;
|
||||
} else {
|
||||
@@ -209,16 +204,25 @@ IntraProcessManager::insert_sub_id_for_pub(
|
||||
|
||||
bool
|
||||
IntraProcessManager::can_communicate(
|
||||
rclcpp::PublisherBase::SharedPtr pub,
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr sub) const
|
||||
PublisherInfo pub_info,
|
||||
SubscriptionInfo sub_info) const
|
||||
{
|
||||
// publisher and subscription must be on the same topic
|
||||
if (strcmp(pub->get_topic_name(), sub->get_topic_name()) != 0) {
|
||||
if (strcmp(pub_info.topic_name, sub_info.topic_name) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto check_result = rclcpp::qos_check_compatible(pub->get_actual_qos(), sub->get_actual_qos());
|
||||
if (check_result.compatibility == rclcpp::QoSCompatibility::Error) {
|
||||
// TODO(alsora): the following checks for qos compatibility should be provided by the RMW
|
||||
// a reliable subscription can't be connected with a best effort publisher
|
||||
if (
|
||||
sub_info.qos.reliability == RMW_QOS_POLICY_RELIABILITY_RELIABLE &&
|
||||
pub_info.qos.reliability == RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// a publisher and a subscription with different durability can't communicate
|
||||
if (sub_info.qos.durability != pub_info.qos.durability) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "rcutils/logging_macros.h"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
|
||||
@@ -31,7 +31,7 @@ SubscriptionIntraProcessBase::get_topic_name() const
|
||||
return topic_name_.c_str();
|
||||
}
|
||||
|
||||
rclcpp::QoS
|
||||
rmw_qos_profile_t
|
||||
SubscriptionIntraProcessBase::get_actual_qos() const
|
||||
{
|
||||
return qos_profile_;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
string data
|
||||
@@ -7,7 +7,6 @@ add_definitions(-DTEST_RESOURCES_DIRECTORY="${TEST_RESOURCES_DIRECTORY}")
|
||||
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
|
||||
../msg/Header.msg
|
||||
../msg/MessageWithHeader.msg
|
||||
../msg/String.msg
|
||||
DEPENDENCIES builtin_interfaces
|
||||
LIBRARY_NAME ${PROJECT_NAME}
|
||||
SKIP_INSTALL
|
||||
@@ -144,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
|
||||
@@ -356,44 +348,6 @@ if(TARGET test_publisher)
|
||||
)
|
||||
target_link_libraries(test_publisher ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
if(WIN32)
|
||||
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_publisher_with_type_adapter test_publisher_with_type_adapter.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
)
|
||||
if(TARGET test_publisher_with_type_adapter)
|
||||
ament_target_dependencies(test_publisher_with_type_adapter
|
||||
"rcutils"
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
rosidl_target_interfaces(test_publisher_with_type_adapter ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
|
||||
target_link_libraries(test_publisher_with_type_adapter ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_subscription_with_type_adapter test_subscription_with_type_adapter.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
)
|
||||
if(TARGET test_subscription_with_type_adapter)
|
||||
ament_target_dependencies(test_subscription_with_type_adapter
|
||||
"rcutils"
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
rosidl_target_interfaces(test_subscription_with_type_adapter ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
|
||||
target_link_libraries(test_subscription_with_type_adapter ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_publisher_subscription_count_api test_publisher_subscription_count_api.cpp)
|
||||
if(TARGET test_publisher_subscription_count_api)
|
||||
ament_target_dependencies(test_publisher_subscription_count_api
|
||||
@@ -546,6 +500,11 @@ if(TARGET test_find_weak_nodes)
|
||||
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
if(WIN32)
|
||||
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_externally_defined_services test_externally_defined_services.cpp)
|
||||
ament_target_dependencies(test_externally_defined_services
|
||||
"rcl"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -71,8 +71,6 @@ public:
|
||||
|
||||
void handle_message(std::shared_ptr<void> &, const rclcpp::MessageInfo &) override {}
|
||||
void handle_loaned_message(void *, const rclcpp::MessageInfo &) override {}
|
||||
void handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> &, const rclcpp::MessageInfo &) override {}
|
||||
void return_message(std::shared_ptr<void> &) override {}
|
||||
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> &) override {}
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ void construct_with_null_allocator()
|
||||
TEST(AnySubscriptionCallback, null_allocator) {
|
||||
EXPECT_THROW(
|
||||
construct_with_null_allocator(),
|
||||
std::invalid_argument);
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_F(TestAnySubscriptionCallback, construct_destruct) {
|
||||
@@ -95,69 +95,44 @@ TEST_F(TestAnySubscriptionCallback, unset_dispatch_throw) {
|
||||
// Parameterized test to test across all callback types and dispatch types.
|
||||
//
|
||||
|
||||
// Type adapter to be used in tests.
|
||||
struct MyEmpty {};
|
||||
|
||||
template<>
|
||||
struct rclcpp::TypeAdapter<MyEmpty, test_msgs::msg::Empty>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = MyEmpty;
|
||||
using ros_message_type = test_msgs::msg::Empty;
|
||||
|
||||
static
|
||||
void
|
||||
convert_to_ros_message(const custom_type &, ros_message_type &)
|
||||
{}
|
||||
|
||||
static
|
||||
void
|
||||
convert_to_custom(const ros_message_type &, custom_type &)
|
||||
{}
|
||||
};
|
||||
|
||||
using MyTA = rclcpp::TypeAdapter<MyEmpty, test_msgs::msg::Empty>;
|
||||
|
||||
template<typename MessageT>
|
||||
class InstanceContextImpl
|
||||
{
|
||||
public:
|
||||
InstanceContextImpl() = default;
|
||||
virtual ~InstanceContextImpl() = default;
|
||||
|
||||
explicit InstanceContextImpl(rclcpp::AnySubscriptionCallback<MessageT> asc)
|
||||
explicit InstanceContextImpl(rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc)
|
||||
: any_subscription_callback_(asc)
|
||||
{}
|
||||
|
||||
virtual
|
||||
rclcpp::AnySubscriptionCallback<MessageT>
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>
|
||||
get_any_subscription_callback_to_test() const
|
||||
{
|
||||
return any_subscription_callback_;
|
||||
}
|
||||
|
||||
protected:
|
||||
rclcpp::AnySubscriptionCallback<MessageT> any_subscription_callback_;
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> any_subscription_callback_;
|
||||
};
|
||||
|
||||
template<typename MessageT>
|
||||
class InstanceContext
|
||||
{
|
||||
public:
|
||||
InstanceContext(const std::string & name, std::shared_ptr<InstanceContextImpl<MessageT>> impl)
|
||||
InstanceContext(const std::string & name, std::shared_ptr<InstanceContextImpl> impl)
|
||||
: name(name), impl_(impl)
|
||||
{}
|
||||
|
||||
InstanceContext(
|
||||
const std::string & name,
|
||||
rclcpp::AnySubscriptionCallback<MessageT> asc)
|
||||
: name(name), impl_(std::make_shared<InstanceContextImpl<MessageT>>(asc))
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc)
|
||||
: name(name), impl_(std::make_shared<InstanceContextImpl>(asc))
|
||||
{}
|
||||
|
||||
InstanceContext(const InstanceContext & other)
|
||||
: InstanceContext(other.name, other.impl_) {}
|
||||
|
||||
rclcpp::AnySubscriptionCallback<MessageT>
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>
|
||||
get_any_subscription_callback_to_test() const
|
||||
{
|
||||
return impl_->get_any_subscription_callback_to_test();
|
||||
@@ -166,17 +141,12 @@ public:
|
||||
std::string name;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<InstanceContextImpl<MessageT>> impl_;
|
||||
std::shared_ptr<InstanceContextImpl> impl_;
|
||||
};
|
||||
|
||||
class DispatchTests
|
||||
: public TestAnySubscriptionCallback,
|
||||
public ::testing::WithParamInterface<InstanceContext<test_msgs::msg::Empty>>
|
||||
{};
|
||||
|
||||
class DispatchTestsWithTA
|
||||
: public TestAnySubscriptionCallback,
|
||||
public ::testing::WithParamInterface<InstanceContext<MyTA>>
|
||||
public ::testing::WithParamInterface<InstanceContext>
|
||||
{};
|
||||
|
||||
auto
|
||||
@@ -185,67 +155,57 @@ format_parameter(const ::testing::TestParamInfo<DispatchTests::ParamType> & info
|
||||
return info.param.name;
|
||||
}
|
||||
|
||||
auto
|
||||
format_parameter_with_ta(const ::testing::TestParamInfo<DispatchTestsWithTA::ParamType> & info)
|
||||
{
|
||||
return info.param.name;
|
||||
// Testing dispatch with shared_ptr<MessageT> as input
|
||||
TEST_P(DispatchTests, test_inter_shared_dispatch) {
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test();
|
||||
any_subscription_callback_to_test.dispatch(msg_shared_ptr_, message_info_);
|
||||
}
|
||||
|
||||
#define PARAMETERIZED_TESTS(DispatchTests_name) \
|
||||
/* Testing dispatch with shared_ptr<MessageT> as input */ \
|
||||
TEST_P(DispatchTests_name, test_inter_shared_dispatch) { \
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test(); \
|
||||
any_subscription_callback_to_test.dispatch(msg_shared_ptr_, message_info_); \
|
||||
} \
|
||||
\
|
||||
/* Testing dispatch with shared_ptr<const MessageT> as input */ \
|
||||
TEST_P(DispatchTests_name, test_intra_shared_dispatch) { \
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test(); \
|
||||
any_subscription_callback_to_test.dispatch_intra_process(msg_shared_ptr_, message_info_); \
|
||||
} \
|
||||
\
|
||||
/* Testing dispatch with unique_ptr<MessageT> as input */ \
|
||||
TEST_P(DispatchTests_name, test_intra_unique_dispatch) { \
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test(); \
|
||||
any_subscription_callback_to_test.dispatch_intra_process(get_unique_ptr_msg(), message_info_); \
|
||||
}
|
||||
// Testing dispatch with shared_ptr<const MessageT> as input
|
||||
TEST_P(DispatchTests, test_intra_shared_dispatch) {
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test();
|
||||
any_subscription_callback_to_test.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
}
|
||||
|
||||
PARAMETERIZED_TESTS(DispatchTests)
|
||||
PARAMETERIZED_TESTS(DispatchTestsWithTA)
|
||||
// Testing dispatch with unique_ptr<MessageT> as input
|
||||
TEST_P(DispatchTests, test_intra_unique_dispatch) {
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test();
|
||||
any_subscription_callback_to_test.dispatch_intra_process(get_unique_ptr_msg(), message_info_);
|
||||
}
|
||||
|
||||
// Generic classes for testing callbacks using std::bind to class methods.
|
||||
template<typename MessageT, typename ... CallbackArgs>
|
||||
class BindContextImpl : public InstanceContextImpl<MessageT>
|
||||
template<typename ... CallbackArgs>
|
||||
class BindContextImpl : public InstanceContextImpl
|
||||
{
|
||||
static constexpr size_t number_of_callback_args{sizeof...(CallbackArgs)};
|
||||
|
||||
public:
|
||||
using InstanceContextImpl<MessageT>::InstanceContextImpl;
|
||||
using InstanceContextImpl::InstanceContextImpl;
|
||||
virtual ~BindContextImpl() = default;
|
||||
|
||||
void on_message(CallbackArgs ...) const {}
|
||||
|
||||
rclcpp::AnySubscriptionCallback<MessageT>
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>
|
||||
get_any_subscription_callback_to_test() const override
|
||||
{
|
||||
if constexpr (number_of_callback_args == 1) {
|
||||
return rclcpp::AnySubscriptionCallback<MessageT>().set(
|
||||
return rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
std::bind(&BindContextImpl::on_message, this, std::placeholders::_1)
|
||||
);
|
||||
} else {
|
||||
return rclcpp::AnySubscriptionCallback<MessageT>().set(
|
||||
return rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
std::bind(&BindContextImpl::on_message, this, std::placeholders::_1, std::placeholders::_2)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MessageT, typename ... CallbackArgs>
|
||||
class BindContext : public InstanceContext<MessageT>
|
||||
template<typename ... CallbackArgs>
|
||||
class BindContext : public InstanceContext
|
||||
{
|
||||
public:
|
||||
explicit BindContext(const std::string & name)
|
||||
: InstanceContext<MessageT>(name, std::make_shared<BindContextImpl<MessageT, CallbackArgs ...>>())
|
||||
: InstanceContext(name, std::make_shared<BindContextImpl<CallbackArgs ...>>())
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -272,53 +232,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
const_ref_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, const test_msgs::msg::Empty &>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, const test_msgs::msg::Empty &, const rclcpp::MessageInfo &>(
|
||||
BindContext<const test_msgs::msg::Empty &>("bind_method"),
|
||||
BindContext<const test_msgs::msg::Empty &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void const_ref_ta_free_func(const MyEmpty &) {}
|
||||
void const_ref_ta_w_info_free_func(const MyEmpty &, const rclcpp::MessageInfo &) {}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ConstRefTACallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const MyEmpty &) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const MyEmpty &, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const test_msgs::msg::Empty &) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const test_msgs::msg::Empty &, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, const MyEmpty &>("bind_method_ta"),
|
||||
BindContext<MyTA, const MyEmpty &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, const test_msgs::msg::Empty &>("bind_method"),
|
||||
BindContext<MyTA, const test_msgs::msg::Empty &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
//
|
||||
// Versions of `std::unique_ptr<MessageT, MessageDeleter>`
|
||||
//
|
||||
@@ -344,54 +264,11 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
unique_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, std::unique_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<
|
||||
test_msgs::msg::Empty,
|
||||
std::unique_ptr<test_msgs::msg::Empty>,
|
||||
const rclcpp::MessageInfo &
|
||||
>("bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void unique_ptr_ta_free_func(std::unique_ptr<MyEmpty>) {}
|
||||
void unique_ptr_ta_w_info_free_func(std::unique_ptr<MyEmpty>, const rclcpp::MessageInfo &) {}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
UniquePtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<MyEmpty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<MyEmpty>, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<test_msgs::msg::Empty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>>("bind_method_ta"),
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
BindContext<std::unique_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
format_parameter
|
||||
);
|
||||
|
||||
//
|
||||
@@ -419,56 +296,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<const test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<const test_msgs::msg::Empty>,
|
||||
const rclcpp::MessageInfo &>(
|
||||
BindContext<std::shared_ptr<const test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void shared_const_ptr_ta_free_func(std::shared_ptr<const MyEmpty>) {}
|
||||
void shared_const_ptr_ta_w_info_free_func(
|
||||
std::shared_ptr<const MyEmpty>, const rclcpp::MessageInfo &)
|
||||
{}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SharedConstPtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const MyEmpty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const MyEmpty>, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const test_msgs::msg::Empty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, std::shared_ptr<const MyEmpty>>("bind_method_ta"),
|
||||
BindContext<MyTA, std::shared_ptr<const MyEmpty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, std::shared_ptr<const test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<MyTA, std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
//
|
||||
// Versions of `const std::shared_ptr<const MessageT> &`
|
||||
//
|
||||
@@ -494,58 +328,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
const_ref_shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty,
|
||||
const std::shared_ptr<const test_msgs::msg::Empty> &>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, const std::shared_ptr<const test_msgs::msg::Empty> &,
|
||||
const rclcpp::MessageInfo &>(
|
||||
BindContext<const std::shared_ptr<const test_msgs::msg::Empty> &>("bind_method"),
|
||||
BindContext<const std::shared_ptr<const test_msgs::msg::Empty> &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void const_ref_shared_const_ptr_ta_free_func(const std::shared_ptr<const MyEmpty> &) {}
|
||||
void const_ref_shared_const_ptr_ta_w_info_free_func(
|
||||
const std::shared_ptr<const MyEmpty> &, const rclcpp::MessageInfo &)
|
||||
{}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ConstRefSharedConstPtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const MyEmpty> &) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const MyEmpty> &, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const test_msgs::msg::Empty> &) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const test_msgs::msg::Empty> &, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, const std::shared_ptr<const MyEmpty> &>("bind_method_ta"),
|
||||
BindContext<MyTA, const std::shared_ptr<const MyEmpty> &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, const std::shared_ptr<const test_msgs::msg::Empty> &>("bind_method"),
|
||||
BindContext<MyTA, const std::shared_ptr<const test_msgs::msg::Empty> &,
|
||||
const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
//
|
||||
// Versions of `std::shared_ptr<MessageT>`
|
||||
//
|
||||
@@ -571,52 +360,9 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
shared_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<test_msgs::msg::Empty>,
|
||||
const rclcpp::MessageInfo &>(
|
||||
BindContext<std::shared_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void shared_ptr_ta_free_func(std::shared_ptr<MyEmpty>) {}
|
||||
void shared_ptr_ta_w_info_free_func(
|
||||
std::shared_ptr<MyEmpty>, const rclcpp::MessageInfo &)
|
||||
{}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SharedPtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<MyEmpty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<MyEmpty>, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<test_msgs::msg::Empty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, std::shared_ptr<MyEmpty>>("bind_method_ta"),
|
||||
BindContext<MyTA, std::shared_ptr<MyEmpty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, std::shared_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<MyTA, std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
@@ -52,8 +52,8 @@ class PublisherBase
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase)
|
||||
|
||||
explicit PublisherBase(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: qos_profile(qos),
|
||||
PublisherBase()
|
||||
: qos(rclcpp::QoS(10)),
|
||||
topic_name("topic")
|
||||
{}
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
rclcpp::QoS
|
||||
get_actual_qos() const
|
||||
{
|
||||
return qos_profile;
|
||||
return qos;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp::QoS qos_profile;
|
||||
rclcpp::QoS qos;
|
||||
std::string topic_name;
|
||||
uint64_t intra_process_publisher_id_;
|
||||
IntraProcessManagerWeakPtr weak_ipm_;
|
||||
@@ -111,9 +111,9 @@ public:
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<T, Alloc>)
|
||||
|
||||
explicit Publisher(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: PublisherBase(qos)
|
||||
Publisher()
|
||||
{
|
||||
qos = rclcpp::QoS(10);
|
||||
auto allocator = std::make_shared<Alloc>();
|
||||
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
|
||||
}
|
||||
@@ -136,10 +136,7 @@ namespace buffers
|
||||
{
|
||||
namespace mock
|
||||
{
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename MessageDeleter = std::default_delete<MessageT>>
|
||||
template<typename MessageT>
|
||||
class IntraProcessBuffer
|
||||
{
|
||||
public:
|
||||
@@ -194,8 +191,8 @@ class SubscriptionIntraProcessBase
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
|
||||
|
||||
explicit SubscriptionIntraProcessBase(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: qos_profile(qos), topic_name("topic")
|
||||
SubscriptionIntraProcessBase()
|
||||
: qos_profile(rmw_qos_profile_default), topic_name("topic")
|
||||
{}
|
||||
|
||||
virtual ~SubscriptionIntraProcessBase() {}
|
||||
@@ -203,7 +200,7 @@ public:
|
||||
virtual bool
|
||||
use_take_shared_method() const = 0;
|
||||
|
||||
QoS
|
||||
rmw_qos_profile_t
|
||||
get_actual_qos()
|
||||
{
|
||||
return qos_profile;
|
||||
@@ -215,21 +212,18 @@ public:
|
||||
return topic_name;
|
||||
}
|
||||
|
||||
rclcpp::QoS qos_profile;
|
||||
rmw_qos_profile_t qos_profile;
|
||||
const char * topic_name;
|
||||
};
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
class SubscriptionIntraProcessBuffer : public SubscriptionIntraProcessBase
|
||||
template<typename MessageT>
|
||||
class SubscriptionIntraProcess : public SubscriptionIntraProcessBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcessBuffer)
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
|
||||
|
||||
explicit SubscriptionIntraProcessBuffer(rclcpp::QoS qos)
|
||||
: SubscriptionIntraProcessBase(qos), take_shared_method(false)
|
||||
SubscriptionIntraProcess()
|
||||
: take_shared_method(false)
|
||||
{
|
||||
buffer = std::make_unique<rclcpp::experimental::buffers::mock::IntraProcessBuffer<MessageT>>();
|
||||
}
|
||||
@@ -265,25 +259,6 @@ public:
|
||||
typename rclcpp::experimental::buffers::mock::IntraProcessBuffer<MessageT>::UniquePtr buffer;
|
||||
};
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
class SubscriptionIntraProcess : public SubscriptionIntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
|
||||
|
||||
explicit SubscriptionIntraProcess(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>(qos)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mock
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
@@ -292,14 +267,12 @@ public:
|
||||
#define RCLCPP__PUBLISHER_HPP_
|
||||
#define RCLCPP__PUBLISHER_BASE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
|
||||
// Force ipm to use our mock publisher class.
|
||||
#define Publisher mock::Publisher
|
||||
#define PublisherBase mock::PublisherBase
|
||||
#define IntraProcessBuffer mock::IntraProcessBuffer
|
||||
#define SubscriptionIntraProcessBase mock::SubscriptionIntraProcessBase
|
||||
#define SubscriptionIntraProcessBuffer mock::SubscriptionIntraProcessBuffer
|
||||
#define SubscriptionIntraProcess mock::SubscriptionIntraProcess
|
||||
#include "../src/rclcpp/intra_process_manager.cpp"
|
||||
#undef Publisher
|
||||
@@ -331,7 +304,7 @@ void Publisher<T, Alloc>::publish(MessageUniquePtr msg)
|
||||
ipm->template do_intra_process_publish<T, Alloc>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
*message_allocator_);
|
||||
message_allocator_);
|
||||
}
|
||||
|
||||
} // namespace mock
|
||||
@@ -359,12 +332,15 @@ TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
|
||||
auto ipm = std::make_shared<IntraProcessManagerT>();
|
||||
|
||||
auto p1 = std::make_shared<PublisherT>(rclcpp::QoS(10).best_effort());
|
||||
auto p1 = std::make_shared<PublisherT>();
|
||||
p1->qos.get_rmw_qos_profile().reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
|
||||
|
||||
auto p2 = std::make_shared<PublisherT>(rclcpp::QoS(10).best_effort());
|
||||
auto p2 = std::make_shared<PublisherT>();
|
||||
p2->qos.get_rmw_qos_profile().reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
|
||||
p2->topic_name = "different_topic_name";
|
||||
|
||||
auto s1 = std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(10).best_effort());
|
||||
auto s1 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s1->qos_profile.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
|
||||
|
||||
auto p1_id = ipm->add_publisher(p1);
|
||||
auto p2_id = ipm->add_publisher(p2);
|
||||
@@ -380,9 +356,11 @@ TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
ASSERT_EQ(0u, p2_subs);
|
||||
ASSERT_EQ(0u, non_existing_pub_subs);
|
||||
|
||||
auto p3 = std::make_shared<PublisherT>(rclcpp::QoS(10).reliable());
|
||||
auto p3 = std::make_shared<PublisherT>();
|
||||
p3->qos.get_rmw_qos_profile().reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(10).reliable());
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s2->qos_profile.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
|
||||
auto s2_id = ipm->add_subscription(s2);
|
||||
auto p3_id = ipm->add_publisher(p3);
|
||||
|
||||
@@ -1,303 +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 <type_traits>
|
||||
#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>
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
// Explicit specialization for void
|
||||
template<>
|
||||
struct MyAllocator<void>
|
||||
{
|
||||
public:
|
||||
using value_type = void;
|
||||
using pointer = void *;
|
||||
using const_pointer = const void *;
|
||||
|
||||
MyAllocator() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
~MyAllocator() noexcept {}
|
||||
|
||||
template<typename U>
|
||||
MyAllocator(const MyAllocator<U> &) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
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,
|
||||
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);
|
||||
}
|
||||
@@ -43,42 +43,7 @@ TEST_F(TestLoanedMessage, initialize) {
|
||||
auto node = std::make_shared<rclcpp::Node>("loaned_message_test_node");
|
||||
auto pub = node->create_publisher<MessageT>("loaned_message_test_topic", 1);
|
||||
|
||||
// suppress deprecated function warning
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
auto pub_allocator = pub->get_allocator();
|
||||
|
||||
// remove warning suppression
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// suppress deprecated function warning
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
auto loaned_msg = rclcpp::LoanedMessage<MessageT>(pub.get(), pub_allocator);
|
||||
|
||||
// remove warning suppression
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
auto loaned_msg = rclcpp::LoanedMessage<MessageT>(pub.get(), pub->get_allocator());
|
||||
ASSERT_TRUE(loaned_msg.is_valid());
|
||||
loaned_msg.get().float32_value = 42.0f;
|
||||
ASSERT_EQ(42.0f, loaned_msg.get().float32_value);
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -335,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
|
||||
@@ -2532,34 +2525,6 @@ void expect_qos_profile_eq(
|
||||
EXPECT_EQ(qos1.liveliness_lease_duration.nsec, qos2.liveliness_lease_duration.nsec);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr std::chrono::nanoseconds DEFAULT_EVENT_TIMEOUT = std::chrono::seconds(3);
|
||||
|
||||
constexpr std::chrono::nanoseconds DEFAULT_EVENT_SLEEP_PERIOD = std::chrono::milliseconds(100);
|
||||
|
||||
bool wait_for_event(
|
||||
std::shared_ptr<rclcpp::Node> node,
|
||||
std::function<bool()> predicate,
|
||||
std::chrono::nanoseconds timeout = DEFAULT_EVENT_TIMEOUT,
|
||||
std::chrono::nanoseconds sleep_period = DEFAULT_EVENT_SLEEP_PERIOD)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds time_slept(0);
|
||||
|
||||
bool predicate_result;
|
||||
while (!(predicate_result = predicate()) && time_slept < timeout) {
|
||||
rclcpp::Event::SharedPtr graph_event = node->get_graph_event();
|
||||
node->wait_for_graph_change(graph_event, sleep_period);
|
||||
time_slept = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now() - start);
|
||||
}
|
||||
return predicate_result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// test that calling get_publishers_info_by_topic and get_subscriptions_info_by_topic
|
||||
TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
@@ -2591,10 +2556,6 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
};
|
||||
rclcpp::QoS qos = rclcpp::QoS(qos_initialization, rmw_qos_profile_default);
|
||||
auto publisher = node->create_publisher<test_msgs::msg::BasicTypes>(topic_name, qos);
|
||||
// Wait for the underlying RMW implementation to catch up with graph changes
|
||||
auto topic_is_published =
|
||||
[&]() {return node->get_publishers_info_by_topic(fq_topic_name).size() > 0u;};
|
||||
ASSERT_TRUE(wait_for_event(node, topic_is_published));
|
||||
// List should have one item
|
||||
auto publisher_list = node->get_publishers_info_by_topic(fq_topic_name);
|
||||
ASSERT_EQ(publisher_list.size(), (size_t)1);
|
||||
@@ -2635,10 +2596,7 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
};
|
||||
auto subscriber =
|
||||
node->create_subscription<test_msgs::msg::BasicTypes>(topic_name, qos2, callback);
|
||||
// Wait for the underlying RMW implementation to catch up with graph changes
|
||||
auto topic_is_subscribed =
|
||||
[&]() {return node->get_subscriptions_info_by_topic(fq_topic_name).size() > 0u;};
|
||||
ASSERT_TRUE(wait_for_event(node, topic_is_subscribed));
|
||||
|
||||
// Both lists should have one item
|
||||
publisher_list = node->get_publishers_info_by_topic(fq_topic_name);
|
||||
auto subscription_list = node->get_subscriptions_info_by_topic(fq_topic_name);
|
||||
@@ -2803,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(
|
||||
|
||||
@@ -1,335 +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 <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/loaned_message.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "../mocking_utils/patch.hpp"
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "rclcpp/msg/string.hpp"
|
||||
|
||||
|
||||
#ifdef RMW_IMPLEMENTATION
|
||||
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
|
||||
#else
|
||||
# define CLASSNAME(NAME, SUFFIX) NAME
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static const int g_max_loops = 200;
|
||||
static const std::chrono::milliseconds g_sleep_per_loop(10);
|
||||
|
||||
|
||||
class TestPublisher : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
if (!rclcpp::ok()) {
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void initialize(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("my_node", "/ns", node_options);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
class CLASSNAME (test_intra_process_within_one_node, RMW_IMPLEMENTATION) : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<>
|
||||
struct TypeAdapter<std::string, rclcpp::msg::String>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = std::string;
|
||||
using ros_message_type = rclcpp::msg::String;
|
||||
|
||||
static void
|
||||
convert_to_ros_message(
|
||||
const custom_type & source,
|
||||
ros_message_type & destination)
|
||||
{
|
||||
destination.data = source;
|
||||
}
|
||||
|
||||
static void
|
||||
convert_to_custom(
|
||||
const ros_message_type & source,
|
||||
custom_type & destination)
|
||||
{
|
||||
destination = source.data;
|
||||
}
|
||||
};
|
||||
|
||||
// Throws in conversion
|
||||
template<>
|
||||
struct TypeAdapter<int, rclcpp::msg::String>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = int;
|
||||
using ros_message_type = rclcpp::msg::String;
|
||||
|
||||
static void
|
||||
convert_to_ros_message(
|
||||
const custom_type & source,
|
||||
ros_message_type & destination)
|
||||
{
|
||||
(void) source;
|
||||
(void) destination;
|
||||
throw std::runtime_error("This should happen");
|
||||
}
|
||||
|
||||
static void
|
||||
convert_to_custom(
|
||||
const ros_message_type & source,
|
||||
custom_type & destination)
|
||||
{
|
||||
(void) source;
|
||||
(void) destination;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
/*
|
||||
* Testing publisher creation signatures with a type adapter.
|
||||
*/
|
||||
TEST_F(TestPublisher, various_creation_signatures) {
|
||||
for (auto is_intra_process : {true, false}) {
|
||||
rclcpp::NodeOptions options;
|
||||
options.use_intra_process_comms(is_intra_process);
|
||||
initialize(options);
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
auto publisher = node->create_publisher<StringTypeAdapter>("topic", 42);
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::adapt_type<std::string>::as<rclcpp::msg::String>;
|
||||
auto publisher = node->create_publisher<StringTypeAdapter>("topic", 42);
|
||||
(void)publisher;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that conversion errors are passed up.
|
||||
*/
|
||||
TEST_F(TestPublisher, conversion_exception_is_passed_up) {
|
||||
using BadStringTypeAdapter = rclcpp::TypeAdapter<int, rclcpp::msg::String>;
|
||||
for (auto is_intra_process : {true, false}) {
|
||||
rclcpp::NodeOptions options;
|
||||
options.use_intra_process_comms(is_intra_process);
|
||||
initialize(options);
|
||||
auto pub = node->create_publisher<BadStringTypeAdapter>("topic_name", 1);
|
||||
EXPECT_THROW(pub->publish(1), std::runtime_error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that publisher sends type adapted types and ROS message types with intra proccess communications.
|
||||
*/
|
||||
TEST_F(
|
||||
CLASSNAME(test_intra_process_within_one_node, RMW_IMPLEMENTATION),
|
||||
check_type_adapted_message_is_sent_and_received_intra_process) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
bool is_received;
|
||||
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String::SharedPtr msg,
|
||||
const rclcpp::MessageInfo & message_info
|
||||
) -> void
|
||||
{
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_intra_process",
|
||||
rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
auto pub = node->create_publisher<StringTypeAdapter>(topic_name, 10);
|
||||
auto sub = node->create_subscription<rclcpp::msg::String>(topic_name, 1, callback);
|
||||
|
||||
auto wait_for_message_to_be_received = [&is_received, &node]() {
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
int i = 0;
|
||||
executor.add_node(node);
|
||||
executor.spin_once(std::chrono::milliseconds(0));
|
||||
while (!is_received && i < g_max_loops) {
|
||||
printf("spin_node_once() - callback (1) expected - try %d/%d\n", ++i, g_max_loops);
|
||||
executor.spin_once(g_sleep_per_loop);
|
||||
}
|
||||
};
|
||||
{
|
||||
{ // std::string passed by reference
|
||||
is_received = false;
|
||||
pub->publish(message_data);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // unique pointer to std::string
|
||||
is_received = false;
|
||||
auto pu_message = std::make_unique<std::string>(message_data);
|
||||
pub->publish(std::move(pu_message));
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // ROS message passed by reference
|
||||
is_received = false;
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // unique ptr to ROS message
|
||||
is_received = false;
|
||||
auto pu_msg = std::make_unique<rclcpp::msg::String>();
|
||||
pu_msg->data = message_data;
|
||||
pub->publish(std::move(pu_msg));
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
/* TODO(audrow) Enable once loaned messages are supported for intra process communication
|
||||
{ // loaned ROS message
|
||||
// is_received = false;
|
||||
// std::allocator<void> allocator;
|
||||
// rclcpp::LoanedMessage<rclcpp::msg::String> loaned_msg(*pub, allocator);
|
||||
// loaned_msg.get().data = message_data;
|
||||
// pub->publish(std::move(loaned_msg));
|
||||
// ASSERT_FALSE(is_received);
|
||||
// wait_for_message_to_be_received();
|
||||
// ASSERT_TRUE(is_received);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that publisher sends type adapted types and ROS message types with inter proccess communications.
|
||||
*/
|
||||
TEST_F(TestPublisher, check_type_adapted_message_is_sent_and_received) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
|
||||
initialize();
|
||||
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const rclcpp::msg::String>) {FAIL();};
|
||||
auto pub = node->create_publisher<StringTypeAdapter>(topic_name, 1);
|
||||
auto sub = node->create_subscription<rclcpp::msg::String>(topic_name, 1, do_nothing);
|
||||
|
||||
auto assert_no_message_was_received_yet = [sub]() {
|
||||
rclcpp::msg::String msg;
|
||||
rclcpp::MessageInfo msg_info;
|
||||
EXPECT_FALSE(sub->take(msg, msg_info));
|
||||
};
|
||||
auto assert_message_was_received = [sub, message_data]() {
|
||||
rclcpp::msg::String msg;
|
||||
rclcpp::MessageInfo msg_info;
|
||||
bool message_received = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
do {
|
||||
message_received = sub->take(msg, msg_info);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
|
||||
EXPECT_TRUE(message_received);
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
};
|
||||
|
||||
{ // std::string passed by reference
|
||||
assert_no_message_was_received_yet();
|
||||
pub->publish(message_data);
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // unique pointer to std::string
|
||||
assert_no_message_was_received_yet();
|
||||
auto pu_message = std::make_unique<std::string>(message_data);
|
||||
pub->publish(std::move(pu_message));
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // ROS message passed by reference
|
||||
assert_no_message_was_received_yet();
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
pub->publish(msg);
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // unique ptr to ROS message
|
||||
assert_no_message_was_received_yet();
|
||||
auto pu_msg = std::make_unique<rclcpp::msg::String>();
|
||||
pu_msg->data = message_data;
|
||||
pub->publish(std::move(pu_msg));
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // loaned ROS message
|
||||
assert_no_message_was_received_yet();
|
||||
std::allocator<void> allocator;
|
||||
rclcpp::LoanedMessage<rclcpp::msg::String> loaned_msg(*pub, allocator);
|
||||
loaned_msg.get().data = message_data;
|
||||
pub->publish(std::move(loaned_msg));
|
||||
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> options;
|
||||
assert_message_was_received();
|
||||
}
|
||||
}
|
||||
@@ -510,7 +510,7 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
TEST_F(TestSubscription, get_network_flow_endpoints_errors) {
|
||||
initialize();
|
||||
const rclcpp::QoS subscription_qos(1);
|
||||
auto subscription_callback = [](test_msgs::msg::Empty::SharedPtr msg) {
|
||||
auto subscription_callback = [](const test_msgs::msg::Empty::SharedPtr msg) {
|
||||
(void)msg;
|
||||
};
|
||||
auto subscription = node->create_subscription<test_msgs::msg::Empty>(
|
||||
|
||||
@@ -1,563 +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 <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/loaned_message.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "../mocking_utils/patch.hpp"
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "rclcpp/msg/string.hpp"
|
||||
|
||||
|
||||
#ifdef RMW_IMPLEMENTATION
|
||||
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
|
||||
#else
|
||||
# define CLASSNAME(NAME, SUFFIX) NAME
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static const int g_max_loops = 200;
|
||||
static const std::chrono::milliseconds g_sleep_per_loop(10);
|
||||
|
||||
|
||||
class TestSubscription : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
if (!rclcpp::ok()) {
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void initialize(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("my_node", "/ns", node_options);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
class CLASSNAME (test_intra_process_within_one_node, RMW_IMPLEMENTATION) : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<>
|
||||
struct TypeAdapter<std::string, rclcpp::msg::String>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = std::string;
|
||||
using ros_message_type = rclcpp::msg::String;
|
||||
|
||||
static void
|
||||
convert_to_ros_message(
|
||||
const custom_type & source,
|
||||
ros_message_type & destination)
|
||||
{
|
||||
destination.data = source;
|
||||
}
|
||||
|
||||
static void
|
||||
convert_to_custom(
|
||||
const ros_message_type & source,
|
||||
custom_type & destination)
|
||||
{
|
||||
destination = source.data;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
void wait_for_message_to_be_received(
|
||||
bool & is_received,
|
||||
const std::shared_ptr<rclcpp::Node> & node)
|
||||
{
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
executor.spin_once(std::chrono::milliseconds(0));
|
||||
int i = 0;
|
||||
while (!is_received && i < g_max_loops) {
|
||||
printf("spin_node_once() - callback (1) expected - try %d/%d\n", ++i, g_max_loops);
|
||||
executor.spin_once(g_sleep_per_loop);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Testing publisher creation signatures with a type adapter.
|
||||
*/
|
||||
TEST_F(TestSubscription, various_creation_signatures) {
|
||||
initialize();
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
auto sub =
|
||||
node->create_subscription<StringTypeAdapter>("topic", 42, [](const std::string &) {});
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::adapt_type<std::string>::as<rclcpp::msg::String>;
|
||||
auto sub =
|
||||
node->create_subscription<StringTypeAdapter>("topic", 42, [](const std::string &) {});
|
||||
(void)sub;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that subscriber receives type adapted types and ROS message types with intra proccess communications.
|
||||
*/
|
||||
TEST_F(
|
||||
CLASSNAME(test_intra_process_within_one_node, RMW_IMPLEMENTATION),
|
||||
check_type_adapted_messages_are_received_by_intra_process_subscription) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_intra_process",
|
||||
rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
auto pub = node->create_publisher<rclcpp::msg::String>(topic_name, 1);
|
||||
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
|
||||
{
|
||||
{ // const std::string &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const std::string & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // const std::string & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const std::string & msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::shared_ptr<const std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // const rclcpp::msg::String &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // const rclcpp::msg::String & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::shared_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that subscriber receives type adapted types and ROS message types with inter proccess communications.
|
||||
*/
|
||||
TEST_F(
|
||||
CLASSNAME(test_intra_process_within_one_node, RMW_IMPLEMENTATION),
|
||||
check_type_adapted_messages_are_received_by_inter_process_subscription) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_intra_process",
|
||||
rclcpp::NodeOptions().use_intra_process_comms(false));
|
||||
auto pub = node->create_publisher<rclcpp::msg::String>(topic_name, 1);
|
||||
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
|
||||
{
|
||||
{ // const std::string &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](const std::string & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // const std::string & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const std::string & msg, const rclcpp::MessageInfo & message_info) -> void
|
||||
{
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<const std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // const rclcpp::msg::String &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // const rclcpp::msg::String & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::shared_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -343,9 +342,6 @@ TEST_F(TestWaitSet, get_result_from_wait_result) {
|
||||
EXPECT_EQ(&wait_set, &const_result.get_wait_set());
|
||||
}
|
||||
|
||||
/*
|
||||
* Fail to get wait_set from result when timeout (not ready).
|
||||
*/
|
||||
TEST_F(TestWaitSet, get_result_from_wait_result_not_ready_error) {
|
||||
rclcpp::WaitSet wait_set;
|
||||
auto guard_condition = std::make_shared<rclcpp::GuardCondition>();
|
||||
@@ -363,97 +359,3 @@ TEST_F(TestWaitSet, get_result_from_wait_result_not_ready_error) {
|
||||
const_result.get_wait_set(),
|
||||
std::runtime_error("cannot access wait set when the result was not ready"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fail to add item to wait set, which was added in the constructor of another wait set.
|
||||
*
|
||||
* Also ensure items in destroyed wait sets can be added to new wait sets afterwards.
|
||||
*/
|
||||
TEST_F(TestWaitSet, add_entity_in_constructor_and_dynamically_fails) {
|
||||
auto node = std::make_shared<rclcpp::Node>("add_entity_in_constructor_and_dynamically_fails");
|
||||
|
||||
rclcpp::SubscriptionOptions subscription_options;
|
||||
subscription_options.event_callbacks.deadline_callback = [](auto) {};
|
||||
subscription_options.event_callbacks.liveliness_callback = [](auto) {};
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::BasicTypes>) {};
|
||||
auto sub = node->create_subscription<test_msgs::msg::BasicTypes>(
|
||||
"~/test",
|
||||
1,
|
||||
do_nothing,
|
||||
subscription_options);
|
||||
|
||||
auto guard_condition = std::make_shared<rclcpp::GuardCondition>();
|
||||
|
||||
auto timer = node->create_wall_timer(std::chrono::seconds(1), []() {});
|
||||
|
||||
auto client = node->create_client<rcl_interfaces::srv::ListParameters>("~/empty");
|
||||
|
||||
auto srv_callback =
|
||||
[](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::ListParameters::Request>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::ListParameters::Response>
|
||||
) {};
|
||||
auto service =
|
||||
node->create_service<rcl_interfaces::srv::ListParameters>("~/test", srv_callback);
|
||||
|
||||
{
|
||||
// Add all entities via constructor.
|
||||
rclcpp::WaitSet wait_set(
|
||||
{{sub}},
|
||||
{guard_condition},
|
||||
{timer},
|
||||
{client},
|
||||
{service}
|
||||
);
|
||||
|
||||
// Expect all cannot be added to another wait set.
|
||||
rclcpp::WaitSet other_wait_set;
|
||||
EXPECT_THROW({
|
||||
other_wait_set.add_subscription(sub);
|
||||
}, std::runtime_error);
|
||||
EXPECT_THROW({
|
||||
other_wait_set.add_guard_condition(guard_condition);
|
||||
}, std::runtime_error);
|
||||
EXPECT_THROW({
|
||||
other_wait_set.add_timer(timer);
|
||||
}, std::runtime_error);
|
||||
EXPECT_THROW({
|
||||
other_wait_set.add_client(client);
|
||||
}, std::runtime_error);
|
||||
EXPECT_THROW({
|
||||
other_wait_set.add_service(service);
|
||||
}, std::runtime_error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure removing a subscription added via construction is removable with all mask items.
|
||||
*
|
||||
* This covers a case that had a bug in which the adding of items via construction was naive and
|
||||
* did not behave as-if items were being added via `add_*` type methods, specifically for
|
||||
* subscriptions, which had the mask logic.
|
||||
*/
|
||||
TEST_F(TestWaitSet, remove_subscription_which_was_added_via_construction) {
|
||||
auto node =
|
||||
std::make_shared<rclcpp::Node>("remove_subscription_which_was_added_via_construction");
|
||||
|
||||
rclcpp::SubscriptionOptions subscription_options;
|
||||
subscription_options.event_callbacks.deadline_callback = [](auto) {};
|
||||
subscription_options.event_callbacks.liveliness_callback = [](auto) {};
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::BasicTypes>) {};
|
||||
auto sub = node->create_subscription<test_msgs::msg::BasicTypes>(
|
||||
"~/test",
|
||||
1,
|
||||
do_nothing,
|
||||
subscription_options);
|
||||
|
||||
rclcpp::WaitSet wait_set({{sub}});
|
||||
|
||||
wait_set.remove_subscription(sub);
|
||||
}
|
||||
|
||||
/*
|
||||
More test ideas:
|
||||
- add to dynamic wait set, let go out of scope, destroy wait set (weak ptr to objects prevent exchange_in_use_by_wait_set_state(false), should be ok though)
|
||||
*/
|
||||
|
||||
@@ -3,17 +3,6 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
* Bump the benchmark timeout for benchmark_action_client (`#1671 <https://github.com/ros2/rclcpp/issues/1671>`_)
|
||||
* Contributors: Scott K Logan
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
* Returns CancelResponse::REJECT while goal handle failed to transit to CANCELING state (`#1641 <https://github.com/ros2/rclcpp/issues/1641>`_)
|
||||
* Fix action server deadlock issue that caused by other mutexes locked in CancelCallback (`#1635 <https://github.com/ros2/rclcpp/issues/1635>`_)
|
||||
* Contributors: Kaven Yau
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>11.0.0</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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -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>11.0.0</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>
|
||||
|
||||
@@ -3,16 +3,6 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
* Fix destruction order in lifecycle benchmark (`#1675 <https://github.com/ros2/rclcpp/issues/1675>`_)
|
||||
* Contributors: Scott K Logan
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
* [rclcpp] Type Adaptation feature (`#1557 <https://github.com/ros2/rclcpp/issues/1557>`_)
|
||||
* Contributors: Audrow Nash, William Woodall
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -230,8 +230,13 @@ public:
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType>
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
|
||||
@@ -61,6 +61,7 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
|
||||
@@ -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>11.0.0</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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user