ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
intra_process_manager.hpp
1 // Copyright 2019 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__EXPERIMENTAL__INTRA_PROCESS_MANAGER_HPP_
16 #define RCLCPP__EXPERIMENTAL__INTRA_PROCESS_MANAGER_HPP_
17 
18 #include <rmw/types.h>
19 
20 #include <shared_mutex>
21 
22 #include <algorithm>
23 #include <iterator>
24 #include <memory>
25 #include <stdexcept>
26 #include <unordered_map>
27 #include <utility>
28 #include <vector>
29 #include <typeinfo>
30 
31 #include "rclcpp/allocator/allocator_deleter.hpp"
32 #include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
33 #include "rclcpp/experimental/ros_message_intra_process_buffer.hpp"
34 #include "rclcpp/experimental/subscription_intra_process_base.hpp"
35 #include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
36 #include "rclcpp/logger.hpp"
37 #include "rclcpp/logging.hpp"
38 #include "rclcpp/macros.hpp"
39 #include "rclcpp/publisher_base.hpp"
40 #include "rclcpp/type_adapter.hpp"
41 #include "rclcpp/visibility_control.hpp"
42 
43 namespace rclcpp
44 {
45 
46 namespace experimental
47 {
48 
50 
93 {
94 private:
95  RCLCPP_DISABLE_COPY(IntraProcessManager)
96 
97 public:
98  RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessManager)
99 
100  RCLCPP_PUBLIC
102 
103  RCLCPP_PUBLIC
104  virtual ~IntraProcessManager();
105 
107 
116  template<
117  typename ROSMessageType,
118  typename Alloc = std::allocator<ROSMessageType>
119  >
120  uint64_t
122  const rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr & subscription)
123  {
124  std::unique_lock<std::shared_timed_mutex> lock(mutex_);
125 
126  uint64_t sub_id = IntraProcessManager::get_next_unique_id();
127 
128  subscriptions_[sub_id] = subscription;
129 
130  // adds the subscription id to all the matchable publishers
131  for (auto & pair : publishers_) {
132  auto publisher = pair.second.lock();
133  if (!publisher) {
134  continue;
135  }
136  if (can_communicate(publisher, subscription)) {
137  uint64_t pub_id = pair.first;
138  insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
139  if (publisher->is_durability_transient_local() &&
140  subscription->is_durability_transient_local())
141  {
142  do_transient_local_publish<ROSMessageType, Alloc>(
143  pub_id, sub_id,
144  subscription->use_take_shared_method());
145  }
146  }
147  }
148 
149  return sub_id;
150  }
151 
153 
158  RCLCPP_PUBLIC
159  void
160  remove_subscription(uint64_t intra_process_subscription_id);
161 
163 
176  RCLCPP_PUBLIC
177  uint64_t
179  const rclcpp::PublisherBase::SharedPtr & publisher,
180  const rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr & buffer =
181  rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr());
182 
184 
189  RCLCPP_PUBLIC
190  void
191  remove_publisher(uint64_t intra_process_publisher_id);
192 
194 
217  template<
218  typename MessageT,
219  typename ROSMessageType,
220  typename Alloc,
221  typename Deleter = std::default_delete<MessageT>
222  >
223  void
225  uint64_t intra_process_publisher_id,
226  std::unique_ptr<MessageT, Deleter> message,
227  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
228  {
229  using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
230  using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
231 
232  std::shared_lock<std::shared_timed_mutex> lock(mutex_);
233 
234  auto publisher_it = pub_to_subs_.find(intra_process_publisher_id);
235  if (publisher_it == pub_to_subs_.end()) {
236  // Publisher is either invalid or no longer exists.
237  RCLCPP_WARN(
238  rclcpp::get_logger("rclcpp"),
239  "Calling do_intra_process_publish for invalid or no longer existing publisher id");
240  return;
241  }
242  const auto & sub_ids = publisher_it->second;
243 
244  if (sub_ids.take_ownership_subscriptions.empty()) {
245  // None of the buffers require ownership, so we promote the pointer
246  std::shared_ptr<MessageT> msg = std::move(message);
247 
248  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
249  msg, sub_ids.take_shared_subscriptions);
250  } else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
251  sub_ids.take_shared_subscriptions.size() <= 1)
252  {
253  // There is at maximum 1 buffer that does not require ownership.
254  // So this case is equivalent to all the buffers requiring ownership
255 
256  // Merge the two vector of ids into a unique one
257  std::vector<uint64_t> concatenated_vector(
258  sub_ids.take_shared_subscriptions.begin(), sub_ids.take_shared_subscriptions.end());
259  concatenated_vector.insert(
260  concatenated_vector.end(),
261  sub_ids.take_ownership_subscriptions.begin(),
262  sub_ids.take_ownership_subscriptions.end());
263  this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
264  std::move(message),
265  concatenated_vector,
266  allocator);
267  } else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
268  sub_ids.take_shared_subscriptions.size() > 1)
269  {
270  // Construct a new shared pointer from the message
271  // for the buffers that do not require ownership
272  auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
273 
274  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
275  shared_msg, sub_ids.take_shared_subscriptions);
276  this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
277  std::move(message), sub_ids.take_ownership_subscriptions, allocator);
278  }
279  }
280 
281  template<
282  typename MessageT,
283  typename ROSMessageType,
284  typename Alloc,
285  typename Deleter = std::default_delete<MessageT>
286  >
287  std::shared_ptr<const MessageT>
288  do_intra_process_publish_and_return_shared(
289  uint64_t intra_process_publisher_id,
290  std::unique_ptr<MessageT, Deleter> message,
291  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
292  {
293  using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
294  using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
295 
296  std::shared_lock<std::shared_timed_mutex> lock(mutex_);
297 
298  auto publisher_it = pub_to_subs_.find(intra_process_publisher_id);
299  if (publisher_it == pub_to_subs_.end()) {
300  // Publisher is either invalid or no longer exists.
301  RCLCPP_WARN(
302  rclcpp::get_logger("rclcpp"),
303  "Calling do_intra_process_publish for invalid or no longer existing publisher id");
304  return nullptr;
305  }
306  const auto & sub_ids = publisher_it->second;
307 
308  if (sub_ids.take_ownership_subscriptions.empty()) {
309  // If there are no owning, just convert to shared.
310  std::shared_ptr<MessageT> shared_msg = std::move(message);
311  if (!sub_ids.take_shared_subscriptions.empty()) {
312  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
313  shared_msg, sub_ids.take_shared_subscriptions);
314  }
315  return shared_msg;
316  } else {
317  // Construct a new shared pointer from the message for the buffers that
318  // do not require ownership and to return.
319  auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
320 
321  if (!sub_ids.take_shared_subscriptions.empty()) {
322  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
323  shared_msg,
324  sub_ids.take_shared_subscriptions);
325  }
326  if (!sub_ids.take_ownership_subscriptions.empty()) {
327  this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
328  std::move(message),
329  sub_ids.take_ownership_subscriptions,
330  allocator);
331  }
332  return shared_msg;
333  }
334  }
335 
336  template<
337  typename MessageT,
338  typename Alloc,
339  typename Deleter,
340  typename ROSMessageType>
341  void
342  add_shared_msg_to_buffer(
343  std::shared_ptr<const MessageT> message,
344  uint64_t subscription_id)
345  {
346  add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(message, {subscription_id});
347  }
348 
349  template<
350  typename MessageT,
351  typename Alloc,
352  typename Deleter,
353  typename ROSMessageType>
354  void
355  add_owned_msg_to_buffer(
356  std::unique_ptr<MessageT, Deleter> message,
357  uint64_t subscription_id,
358  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
359  {
360  add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
361  std::move(message), {subscription_id}, allocator);
362  }
363 
365  RCLCPP_PUBLIC
366  bool
367  matches_any_publishers(const rmw_gid_t * id) const;
368 
370  RCLCPP_PUBLIC
371  size_t
372  get_subscription_count(uint64_t intra_process_publisher_id) const;
373 
374  RCLCPP_PUBLIC
375  rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr
376  get_subscription_intra_process(uint64_t intra_process_subscription_id);
377 
379  RCLCPP_PUBLIC
380  size_t
381  lowest_available_capacity(const uint64_t intra_process_publisher_id) const;
382 
383 private:
384  struct SplittedSubscriptions
385  {
386  std::vector<uint64_t> take_shared_subscriptions;
387  std::vector<uint64_t> take_ownership_subscriptions;
388  };
389 
391  struct rmw_gid_hash
392  {
393  std::size_t operator()(const rmw_gid_t & gid) const noexcept
394  {
395  // Using the FNV-1a hash algorithm on the gid data
396  constexpr std::size_t FNV_prime = 1099511628211u;
397  std::size_t result = 14695981039346656037u;
398 
399  for (std::size_t i = 0; i < RMW_GID_STORAGE_SIZE; ++i) {
400  result ^= gid.data[i];
401  result *= FNV_prime;
402  }
403  return result;
404  }
405  };
406 
408  struct rmw_gid_equal
409  {
410  bool operator()(const rmw_gid_t & lhs, const rmw_gid_t & rhs) const noexcept
411  {
412  // Compare the data bytes only.
413  // implementation_identifier pointer comparison is not used here because
414  // intra-process communication is always within the same process and RMW,
415  // and pointer comparison is fragile across dynamically loaded components.
416  return std::equal(
417  std::begin(lhs.data),
418  std::end(lhs.data),
419  std::begin(rhs.data));
420  }
421  };
422 
423  using SubscriptionMap =
424  std::unordered_map<uint64_t, rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr>;
425 
426  using PublisherMap =
427  std::unordered_map<uint64_t, rclcpp::PublisherBase::WeakPtr>;
428 
429  using PublisherBufferMap =
430  std::unordered_map<uint64_t, rclcpp::experimental::buffers::IntraProcessBufferBase::WeakPtr>;
431 
432  using PublisherToSubscriptionIdsMap =
433  std::unordered_map<uint64_t, SplittedSubscriptions>;
434 
436  struct PublisherInfo
437  {
438  uint64_t pub_id;
439  rclcpp::PublisherBase::WeakPtr publisher;
440  };
441 
442  using GidToPublisherInfoMap =
443  std::unordered_map<rmw_gid_t, PublisherInfo, rmw_gid_hash, rmw_gid_equal>;
444 
445  RCLCPP_PUBLIC
446  static
447  uint64_t
448  get_next_unique_id();
449 
450  RCLCPP_PUBLIC
451  void
452  insert_sub_id_for_pub(uint64_t sub_id, uint64_t pub_id, bool use_take_shared_method);
453 
454  RCLCPP_PUBLIC
455  bool
456  can_communicate(
457  const rclcpp::PublisherBase::SharedPtr & pub,
458  const rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr & sub) const;
459 
460  template<
461  typename ROSMessageType,
462  typename Alloc = std::allocator<ROSMessageType>
463  >
464  void do_transient_local_publish(
465  const uint64_t pub_id, const uint64_t sub_id,
466  const bool use_take_shared_method)
467  {
468  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
469  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
470  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
471 
472  auto publisher_buffer = publisher_buffers_[pub_id].lock();
473  if (!publisher_buffer) {
474  throw std::runtime_error("publisher buffer has unexpectedly gone out of scope");
475  }
476  auto buffer = std::dynamic_pointer_cast<
478  ROSMessageType,
479  ROSMessageTypeAllocator,
480  ROSMessageTypeDeleter
481  >
482  >(publisher_buffer);
483  if (!buffer) {
484  throw std::runtime_error(
485  "failed to dynamic cast publisher's IntraProcessBufferBase to "
486  "IntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
487  "ROSMessageTypeDeleter> which can happen when the publisher and "
488  "subscription use different allocator types, which is not supported");
489  }
490  if (use_take_shared_method) {
491  auto data_vec = buffer->get_all_data_shared();
492  for (auto shared_data : data_vec) {
493  this->template add_shared_msg_to_buffer<
494  ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
495  shared_data, sub_id);
496  }
497  } else {
498  auto data_vec = buffer->get_all_data_unique();
499  for (auto & owned_data : data_vec) {
500  auto allocator = ROSMessageTypeAllocator();
501  this->template add_owned_msg_to_buffer<
502  ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
503  std::move(owned_data), sub_id, allocator);
504  }
505  }
506  }
507 
508  template<
509  typename MessageT,
510  typename Alloc,
511  typename Deleter,
512  typename ROSMessageType>
513  void
514  add_shared_msg_to_buffers(
515  std::shared_ptr<const MessageT> message,
516  std::vector<uint64_t> subscription_ids)
517  {
518  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
519  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
520  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
521 
522  using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
523  using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
524  using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
525  using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
526 
527  for (auto id : subscription_ids) {
528  auto subscription_it = subscriptions_.find(id);
529  if (subscription_it == subscriptions_.end()) {
530  throw std::runtime_error("subscription has unexpectedly gone out of scope");
531  }
532  auto subscription_base = subscription_it->second.lock();
533  if (subscription_base == nullptr) {
534  subscriptions_.erase(id);
535  continue;
536  }
537 
538  auto subscription = std::dynamic_pointer_cast<
540  PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
541  >(subscription_base);
542  if (subscription != nullptr) {
543  subscription->provide_intra_process_data(message);
544  continue;
545  }
546 
547  auto ros_message_subscription = std::dynamic_pointer_cast<
549  ROSMessageTypeAllocator, ROSMessageTypeDeleter>
550  >(subscription_base);
551  if (nullptr == ros_message_subscription) {
552  throw std::runtime_error(
553  "failed to dynamic cast SubscriptionIntraProcessBase to "
554  "SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
555  "SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
556  "ROSMessageTypeDeleter> which can happen when the publisher and "
557  "subscription use different allocator types, which is not supported");
558  }
559 
561  ROSMessageType ros_msg;
563  ros_message_subscription->provide_intra_process_message(
564  std::make_shared<ROSMessageType>(ros_msg));
565  } else {
566  if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
567  ros_message_subscription->provide_intra_process_message(message);
568  } else {
569  if constexpr (std::is_same<typename rclcpp::TypeAdapter<MessageT,
570  ROSMessageType>::ros_message_type, ROSMessageType>::value)
571  {
572  ROSMessageType ros_msg;
574  *message, ros_msg);
575  ros_message_subscription->provide_intra_process_message(
576  std::make_shared<ROSMessageType>(ros_msg));
577  }
578  }
579  }
580  }
581  }
582 
583  template<
584  typename MessageT,
585  typename Alloc,
586  typename Deleter,
587  typename ROSMessageType>
588  void
589  add_owned_msg_to_buffers(
590  std::unique_ptr<MessageT, Deleter> message,
591  std::vector<uint64_t> subscription_ids,
592  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
593  {
594  using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
595  using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
596 
597  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
598  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
599  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
600 
601  using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
602  using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
603  using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
604  using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
605 
606  for (auto it = subscription_ids.begin(); it != subscription_ids.end(); it++) {
607  auto subscription_it = subscriptions_.find(*it);
608  if (subscription_it == subscriptions_.end()) {
609  throw std::runtime_error("subscription has unexpectedly gone out of scope");
610  }
611  auto subscription_base = subscription_it->second.lock();
612  if (subscription_base == nullptr) {
613  subscriptions_.erase(subscription_it);
614  continue;
615  }
616 
617  auto subscription = std::dynamic_pointer_cast<
619  PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
620  >(subscription_base);
621  if (subscription != nullptr) {
622  if (std::next(it) == subscription_ids.end()) {
623  // If this is the last subscription, give up ownership
624  subscription->provide_intra_process_data(std::move(message));
625  // Last message delivered, break from for loop
626  break;
627  } else {
628  // Copy the message since we have additional subscriptions to serve
629  Deleter deleter = message.get_deleter();
630  auto ptr = MessageAllocTraits::allocate(allocator, 1);
631  MessageAllocTraits::construct(allocator, ptr, *message);
632 
633  subscription->provide_intra_process_data(MessageUniquePtr(ptr, deleter));
634  }
635 
636  continue;
637  }
638 
639  auto ros_message_subscription = std::dynamic_pointer_cast<
641  ROSMessageTypeAllocator, ROSMessageTypeDeleter>
642  >(subscription_base);
643  if (nullptr == ros_message_subscription) {
644  throw std::runtime_error(
645  "failed to dynamic cast SubscriptionIntraProcessBase to "
646  "SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
647  "SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
648  "ROSMessageTypeDeleter> which can happen when the publisher and "
649  "subscription use different allocator types, which is not supported");
650  }
651 
653  ROSMessageTypeAllocator ros_message_alloc(allocator);
654  auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_alloc, 1);
655  ROSMessageTypeAllocatorTraits::construct(ros_message_alloc, ptr);
656  ROSMessageTypeDeleter deleter;
657  allocator::set_allocator_for_deleter(&deleter, &allocator);
659  auto ros_msg = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, deleter);
660  ros_message_subscription->provide_intra_process_message(std::move(ros_msg));
661  } else {
662  if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
663  if (std::next(it) == subscription_ids.end()) {
664  // If this is the last subscription, give up ownership
665  ros_message_subscription->provide_intra_process_message(std::move(message));
666  // Last message delivered, break from for loop
667  break;
668  } else {
669  // Copy the message since we have additional subscriptions to serve
670  Deleter deleter = message.get_deleter();
671  allocator::set_allocator_for_deleter(&deleter, &allocator);
672  auto ptr = MessageAllocTraits::allocate(allocator, 1);
673  MessageAllocTraits::construct(allocator, ptr, *message);
674 
675  ros_message_subscription->provide_intra_process_message(
676  MessageUniquePtr(ptr, deleter));
677  }
678  }
679  }
680  }
681  }
682 
683  PublisherToSubscriptionIdsMap pub_to_subs_;
684  SubscriptionMap subscriptions_;
685  PublisherMap publishers_;
686  PublisherBufferMap publisher_buffers_;
687 
688  mutable std::shared_timed_mutex mutex_;
689 
690  GidToPublisherInfoMap gid_to_publisher_info_;
691 };
692 
693 } // namespace experimental
694 } // namespace rclcpp
695 
696 #endif // RCLCPP__EXPERIMENTAL__INTRA_PROCESS_MANAGER_HPP_
This class performs intra process communication between nodes.
RCLCPP_PUBLIC bool matches_any_publishers(const rmw_gid_t *id) const
Return true if the given rmw_gid_t matches any stored Publishers.
RCLCPP_PUBLIC void remove_subscription(uint64_t intra_process_subscription_id)
Unregister a subscription using the subscription's unique id.
uint64_t add_subscription(const rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr &subscription)
Register a subscription with the manager, returns subscriptions unique id.
void do_intra_process_publish(uint64_t intra_process_publisher_id, std::unique_ptr< MessageT, Deleter > message, typename allocator::AllocRebind< MessageT, Alloc >::allocator_type &allocator)
Publishes an intra-process message, passed as a unique pointer.
RCLCPP_PUBLIC void remove_publisher(uint64_t intra_process_publisher_id)
Unregister a publisher using the publisher's unique id.
RCLCPP_PUBLIC size_t get_subscription_count(uint64_t intra_process_publisher_id) const
Return the number of intraprocess subscriptions that are matched with a given publisher id.
RCLCPP_PUBLIC size_t lowest_available_capacity(const uint64_t intra_process_publisher_id) const
Return the lowest available capacity for all subscription buffers for a publisher id.
RCLCPP_PUBLIC uint64_t add_publisher(const rclcpp::PublisherBase::SharedPtr &publisher, const rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr &buffer=rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr())
Register a publisher with the manager, returns the publisher unique id.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Definition: logger.cpp:32
Template structure used to adapt custom, user-defined types to ROS types.