ROS 2 rclcpp + rcl - lyrical  lyrical
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.hpp"
35 #include "rclcpp/experimental/subscription_intra_process_base.hpp"
36 #include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
37 #include "rclcpp/logger.hpp"
38 #include "rclcpp/logging.hpp"
39 #include "rclcpp/macros.hpp"
40 #include "rclcpp/publisher_base.hpp"
41 #include "rclcpp/type_adapter.hpp"
42 #include "rclcpp/visibility_control.hpp"
43 
44 namespace rclcpp
45 {
46 
47 namespace experimental
48 {
49 
51 
94 {
95 private:
96  RCLCPP_DISABLE_COPY(IntraProcessManager)
97 
98 public:
99  RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessManager)
100 
101  RCLCPP_PUBLIC
103 
104  RCLCPP_PUBLIC
105  virtual ~IntraProcessManager();
106 
108 
117  template<
118  typename ROSMessageType,
119  typename Alloc = std::allocator<ROSMessageType>
120  >
121  uint64_t
123  const rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr & subscription)
124  {
125  std::unique_lock<std::shared_timed_mutex> lock(mutex_);
126 
127  uint64_t sub_id = IntraProcessManager::get_next_unique_id();
128 
129  subscriptions_[sub_id] = subscription;
130 
131  // adds the subscription id to all the matchable publishers
132  for (auto & pair : publishers_) {
133  auto publisher = pair.second.lock();
134  if (!publisher) {
135  continue;
136  }
137  if (can_communicate(publisher, subscription)) {
138  uint64_t pub_id = pair.first;
139  insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
140  if (publisher->is_durability_transient_local() &&
141  subscription->is_durability_transient_local())
142  {
143  do_transient_local_publish<ROSMessageType, Alloc>(
144  pub_id, sub_id,
145  subscription->use_take_shared_method());
146  }
147  }
148  }
149 
150  return sub_id;
151  }
152 
154 
159  RCLCPP_PUBLIC
160  void
161  remove_subscription(uint64_t intra_process_subscription_id);
162 
164 
177  RCLCPP_PUBLIC
178  uint64_t
180  const rclcpp::PublisherBase::SharedPtr & publisher,
181  const rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr & buffer =
182  rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr());
183 
185 
190  RCLCPP_PUBLIC
191  void
192  remove_publisher(uint64_t intra_process_publisher_id);
193 
195 
218  template<
219  typename MessageT,
220  typename ROSMessageType,
221  typename Alloc,
222  typename Deleter = std::default_delete<MessageT>
223  >
224  void
226  uint64_t intra_process_publisher_id,
227  std::unique_ptr<MessageT, Deleter> message,
228  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
229  {
230  using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
231  using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
232 
233  std::shared_lock<std::shared_timed_mutex> lock(mutex_);
234 
235  auto publisher_it = pub_to_subs_.find(intra_process_publisher_id);
236  if (publisher_it == pub_to_subs_.end()) {
237  // Publisher is either invalid or no longer exists.
238  RCLCPP_WARN(
239  rclcpp::get_logger("rclcpp"),
240  "Calling do_intra_process_publish for invalid or no longer existing publisher id");
241  return;
242  }
243  const auto & sub_ids = publisher_it->second;
244 
245  if (sub_ids.take_ownership_subscriptions.empty()) {
246  // None of the buffers require ownership, so we promote the pointer
247  std::shared_ptr<MessageT> msg = std::move(message);
248 
249  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
250  msg, sub_ids.take_shared_subscriptions);
251  } else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
252  sub_ids.take_shared_subscriptions.size() <= 1)
253  {
254  // There is at maximum 1 buffer that does not require ownership.
255  // So this case is equivalent to all the buffers requiring ownership
256 
257  // Merge the two vector of ids into a unique one
258  std::vector<uint64_t> concatenated_vector(
259  sub_ids.take_shared_subscriptions.begin(), sub_ids.take_shared_subscriptions.end());
260  concatenated_vector.insert(
261  concatenated_vector.end(),
262  sub_ids.take_ownership_subscriptions.begin(),
263  sub_ids.take_ownership_subscriptions.end());
264  this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
265  std::move(message),
266  concatenated_vector,
267  allocator);
268  } else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
269  sub_ids.take_shared_subscriptions.size() > 1)
270  {
271  // Construct a new shared pointer from the message
272  // for the buffers that do not require ownership
273  auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
274 
275  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
276  shared_msg, sub_ids.take_shared_subscriptions);
277  this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
278  std::move(message), sub_ids.take_ownership_subscriptions, allocator);
279  }
280  }
281 
282  template<
283  typename MessageT,
284  typename ROSMessageType,
285  typename Alloc,
286  typename Deleter = std::default_delete<MessageT>
287  >
288  std::shared_ptr<const MessageT>
289  do_intra_process_publish_and_return_shared(
290  uint64_t intra_process_publisher_id,
291  std::unique_ptr<MessageT, Deleter> message,
292  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
293  {
294  using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
295  using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
296 
297  std::shared_lock<std::shared_timed_mutex> lock(mutex_);
298 
299  auto publisher_it = pub_to_subs_.find(intra_process_publisher_id);
300  if (publisher_it == pub_to_subs_.end()) {
301  // Publisher is either invalid or no longer exists.
302  RCLCPP_WARN(
303  rclcpp::get_logger("rclcpp"),
304  "Calling do_intra_process_publish for invalid or no longer existing publisher id");
305  return nullptr;
306  }
307  const auto & sub_ids = publisher_it->second;
308 
309  if (sub_ids.take_ownership_subscriptions.empty()) {
310  // If there are no owning, just convert to shared.
311  std::shared_ptr<MessageT> shared_msg = std::move(message);
312  if (!sub_ids.take_shared_subscriptions.empty()) {
313  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
314  shared_msg, sub_ids.take_shared_subscriptions);
315  }
316  return shared_msg;
317  } else {
318  // Construct a new shared pointer from the message for the buffers that
319  // do not require ownership and to return.
320  auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
321 
322  if (!sub_ids.take_shared_subscriptions.empty()) {
323  this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
324  shared_msg,
325  sub_ids.take_shared_subscriptions);
326  }
327  if (!sub_ids.take_ownership_subscriptions.empty()) {
328  this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
329  std::move(message),
330  sub_ids.take_ownership_subscriptions,
331  allocator);
332  }
333  return shared_msg;
334  }
335  }
336 
337  template<
338  typename MessageT,
339  typename Alloc,
340  typename Deleter,
341  typename ROSMessageType>
342  void
343  add_shared_msg_to_buffer(
344  std::shared_ptr<const MessageT> message,
345  uint64_t subscription_id)
346  {
347  add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(message, {subscription_id});
348  }
349 
350  template<
351  typename MessageT,
352  typename Alloc,
353  typename Deleter,
354  typename ROSMessageType>
355  void
356  add_owned_msg_to_buffer(
357  std::unique_ptr<MessageT, Deleter> message,
358  uint64_t subscription_id,
359  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
360  {
361  add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
362  std::move(message), {subscription_id}, allocator);
363  }
364 
366  RCLCPP_PUBLIC
367  bool
368  matches_any_publishers(const rmw_gid_t * id) const;
369 
371  RCLCPP_PUBLIC
372  size_t
373  get_subscription_count(uint64_t intra_process_publisher_id) const;
374 
375  RCLCPP_PUBLIC
376  rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr
377  get_subscription_intra_process(uint64_t intra_process_subscription_id);
378 
380  RCLCPP_PUBLIC
381  size_t
382  lowest_available_capacity(const uint64_t intra_process_publisher_id) const;
383 
384 private:
385  struct SplittedSubscriptions
386  {
387  std::vector<uint64_t> take_shared_subscriptions;
388  std::vector<uint64_t> take_ownership_subscriptions;
389  };
390 
392  struct rmw_gid_hash
393  {
394  std::size_t operator()(const rmw_gid_t & gid) const noexcept
395  {
396  // Using the FNV-1a hash algorithm on the gid data
397  constexpr std::size_t FNV_prime = 1099511628211u;
398  std::size_t result = 14695981039346656037u;
399 
400  for (std::size_t i = 0; i < RMW_GID_STORAGE_SIZE; ++i) {
401  result ^= gid.data[i];
402  result *= FNV_prime;
403  }
404  return result;
405  }
406  };
407 
409  struct rmw_gid_equal
410  {
411  bool operator()(const rmw_gid_t & lhs, const rmw_gid_t & rhs) const noexcept
412  {
413  // Compare the data bytes only.
414  // implementation_identifier pointer comparison is not used here because
415  // intra-process communication is always within the same process and RMW,
416  // and pointer comparison is fragile across dynamically loaded components.
417  return std::equal(
418  std::begin(lhs.data),
419  std::end(lhs.data),
420  std::begin(rhs.data));
421  }
422  };
423 
424  using SubscriptionMap =
425  std::unordered_map<uint64_t, rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr>;
426 
427  using PublisherMap =
428  std::unordered_map<uint64_t, rclcpp::PublisherBase::WeakPtr>;
429 
430  using PublisherBufferMap =
431  std::unordered_map<uint64_t, rclcpp::experimental::buffers::IntraProcessBufferBase::WeakPtr>;
432 
433  using PublisherToSubscriptionIdsMap =
434  std::unordered_map<uint64_t, SplittedSubscriptions>;
435 
437  struct PublisherInfo
438  {
439  uint64_t pub_id;
440  rclcpp::PublisherBase::WeakPtr publisher;
441  };
442 
443  using GidToPublisherInfoMap =
444  std::unordered_map<rmw_gid_t, PublisherInfo, rmw_gid_hash, rmw_gid_equal>;
445 
446  RCLCPP_PUBLIC
447  static
448  uint64_t
449  get_next_unique_id();
450 
451  RCLCPP_PUBLIC
452  void
453  insert_sub_id_for_pub(uint64_t sub_id, uint64_t pub_id, bool use_take_shared_method);
454 
455  RCLCPP_PUBLIC
456  bool
457  can_communicate(
458  const rclcpp::PublisherBase::SharedPtr & pub,
459  const rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr & sub) const;
460 
461  template<
462  typename ROSMessageType,
463  typename Alloc = std::allocator<ROSMessageType>
464  >
465  void do_transient_local_publish(
466  const uint64_t pub_id, const uint64_t sub_id,
467  const bool use_take_shared_method)
468  {
469  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
470  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
471  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
472 
473  auto publisher_buffer = publisher_buffers_[pub_id].lock();
474  if (!publisher_buffer) {
475  throw std::runtime_error("publisher buffer has unexpectedly gone out of scope");
476  }
477  auto buffer = std::dynamic_pointer_cast<
479  ROSMessageType,
480  ROSMessageTypeAllocator,
481  ROSMessageTypeDeleter
482  >
483  >(publisher_buffer);
484  if (!buffer) {
485  throw std::runtime_error(
486  "failed to dynamic cast publisher's IntraProcessBufferBase to "
487  "IntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
488  "ROSMessageTypeDeleter> which can happen when the publisher and "
489  "subscription use different allocator types, which is not supported");
490  }
491  if (use_take_shared_method) {
492  auto data_vec = buffer->get_all_data_shared();
493  for (auto shared_data : data_vec) {
494  this->template add_shared_msg_to_buffer<
495  ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
496  shared_data, sub_id);
497  }
498  } else {
499  auto data_vec = buffer->get_all_data_unique();
500  for (auto & owned_data : data_vec) {
501  auto allocator = ROSMessageTypeAllocator();
502  this->template add_owned_msg_to_buffer<
503  ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
504  std::move(owned_data), sub_id, allocator);
505  }
506  }
507  }
508 
509  template<
510  typename MessageT,
511  typename Alloc,
512  typename Deleter,
513  typename ROSMessageType>
514  void
515  add_shared_msg_to_buffers(
516  std::shared_ptr<const MessageT> message,
517  std::vector<uint64_t> subscription_ids)
518  {
519  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
520  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
521  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
522 
523  using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
524  using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
525  using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
526  using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
527 
528  for (auto id : subscription_ids) {
529  auto subscription_it = subscriptions_.find(id);
530  if (subscription_it == subscriptions_.end()) {
531  throw std::runtime_error("subscription has unexpectedly gone out of scope");
532  }
533  auto subscription_base = subscription_it->second.lock();
534  if (subscription_base == nullptr) {
535  subscriptions_.erase(id);
536  continue;
537  }
538 
539  auto subscription = std::dynamic_pointer_cast<
541  PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
542  >(subscription_base);
543  if (subscription != nullptr) {
544  subscription->provide_intra_process_data(message);
545  continue;
546  }
547 
548  auto ros_message_subscription = std::dynamic_pointer_cast<
550  ROSMessageTypeAllocator, ROSMessageTypeDeleter>
551  >(subscription_base);
552  if (nullptr == ros_message_subscription) {
553  throw std::runtime_error(
554  "failed to dynamic cast SubscriptionIntraProcessBase to "
555  "SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
556  "SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
557  "ROSMessageTypeDeleter> which can happen when the publisher and "
558  "subscription use different allocator types, which is not supported");
559  }
560 
562  ROSMessageType ros_msg;
564  ros_message_subscription->provide_intra_process_message(
565  std::make_shared<ROSMessageType>(ros_msg));
566  } else {
567  if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
568  ros_message_subscription->provide_intra_process_message(message);
569  } else {
570  if constexpr (std::is_same<typename rclcpp::TypeAdapter<MessageT,
571  ROSMessageType>::ros_message_type, ROSMessageType>::value)
572  {
573  ROSMessageType ros_msg;
575  *message, ros_msg);
576  ros_message_subscription->provide_intra_process_message(
577  std::make_shared<ROSMessageType>(ros_msg));
578  }
579  }
580  }
581  }
582  }
583 
584  template<
585  typename MessageT,
586  typename Alloc,
587  typename Deleter,
588  typename ROSMessageType>
589  void
590  add_owned_msg_to_buffers(
591  std::unique_ptr<MessageT, Deleter> message,
592  std::vector<uint64_t> subscription_ids,
593  typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
594  {
595  using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
596  using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
597 
598  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
599  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
600  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
601 
602  using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
603  using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
604  using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
605  using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
606 
607  for (auto it = subscription_ids.begin(); it != subscription_ids.end(); it++) {
608  auto subscription_it = subscriptions_.find(*it);
609  if (subscription_it == subscriptions_.end()) {
610  throw std::runtime_error("subscription has unexpectedly gone out of scope");
611  }
612  auto subscription_base = subscription_it->second.lock();
613  if (subscription_base == nullptr) {
614  subscriptions_.erase(subscription_it);
615  continue;
616  }
617 
618  auto subscription = std::dynamic_pointer_cast<
620  PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
621  >(subscription_base);
622  if (subscription != nullptr) {
623  if (std::next(it) == subscription_ids.end()) {
624  // If this is the last subscription, give up ownership
625  subscription->provide_intra_process_data(std::move(message));
626  // Last message delivered, break from for loop
627  break;
628  } else {
629  // Copy the message since we have additional subscriptions to serve
630  Deleter deleter = message.get_deleter();
631  auto ptr = MessageAllocTraits::allocate(allocator, 1);
632  MessageAllocTraits::construct(allocator, ptr, *message);
633 
634  subscription->provide_intra_process_data(MessageUniquePtr(ptr, deleter));
635  }
636 
637  continue;
638  }
639 
640  auto ros_message_subscription = std::dynamic_pointer_cast<
642  ROSMessageTypeAllocator, ROSMessageTypeDeleter>
643  >(subscription_base);
644  if (nullptr == ros_message_subscription) {
645  throw std::runtime_error(
646  "failed to dynamic cast SubscriptionIntraProcessBase to "
647  "SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
648  "SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
649  "ROSMessageTypeDeleter> which can happen when the publisher and "
650  "subscription use different allocator types, which is not supported");
651  }
652 
654  ROSMessageTypeAllocator ros_message_alloc(allocator);
655  auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_alloc, 1);
656  ROSMessageTypeAllocatorTraits::construct(ros_message_alloc, ptr);
657  ROSMessageTypeDeleter deleter;
658  allocator::set_allocator_for_deleter(&deleter, &allocator);
660  auto ros_msg = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, deleter);
661  ros_message_subscription->provide_intra_process_message(std::move(ros_msg));
662  } else {
663  if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
664  if (std::next(it) == subscription_ids.end()) {
665  // If this is the last subscription, give up ownership
666  ros_message_subscription->provide_intra_process_message(std::move(message));
667  // Last message delivered, break from for loop
668  break;
669  } else {
670  // Copy the message since we have additional subscriptions to serve
671  Deleter deleter = message.get_deleter();
672  allocator::set_allocator_for_deleter(&deleter, &allocator);
673  auto ptr = MessageAllocTraits::allocate(allocator, 1);
674  MessageAllocTraits::construct(allocator, ptr, *message);
675 
676  ros_message_subscription->provide_intra_process_message(
677  MessageUniquePtr(ptr, deleter));
678  }
679  }
680  }
681  }
682  }
683 
684  PublisherToSubscriptionIdsMap pub_to_subs_;
685  SubscriptionMap subscriptions_;
686  PublisherMap publishers_;
687  PublisherBufferMap publisher_buffers_;
688 
689  mutable std::shared_timed_mutex mutex_;
690 
691  GidToPublisherInfoMap gid_to_publisher_info_;
692 };
693 
694 } // namespace experimental
695 } // namespace rclcpp
696 
697 #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:34
Template structure used to adapt custom, user-defined types to ROS types.