ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
event_handler.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__EVENT_HANDLER_HPP_
16 #define RCLCPP__EVENT_HANDLER_HPP_
17 
18 #include <atomic>
19 #include <functional>
20 #include <memory>
21 #include <mutex>
22 #include <stdexcept>
23 #include <string>
24 #include <vector>
25 
26 #include "rcl/error_handling.h"
27 #include "rcl/event_callback.h"
28 #include "rmw/incompatible_qos_events_statuses.h"
29 #include "rmw/events_statuses/incompatible_type.h"
30 
31 #include "rcutils/logging_macros.h"
32 
33 #include "rclcpp/detail/cpp_callback_trampoline.hpp"
34 #include "rclcpp/exceptions.hpp"
35 #include "rclcpp/function_traits.hpp"
36 #include "rclcpp/waitable.hpp"
37 
38 namespace rclcpp
39 {
40 
41 using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
42 using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
43 using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
44 using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
45 using QOSMessageLostInfo = rmw_message_lost_status_t;
46 using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
47 using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
48 
49 using IncompatibleTypeInfo = rmw_incompatible_type_status_t;
50 using MatchedInfo = rmw_matched_status_t;
51 
52 using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
53 using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
54 using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
55 using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
56 using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
57 using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
58 using QOSRequestedIncompatibleQoSCallbackType =
59  std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
60 
61 using IncompatibleTypeCallbackType = std::function<void (IncompatibleTypeInfo &)>;
62 using PublisherMatchedCallbackType = std::function<void (MatchedInfo &)>;
63 using SubscriptionMatchedCallbackType = std::function<void (MatchedInfo &)>;
64 
67 {
68  QOSDeadlineOfferedCallbackType deadline_callback;
69  QOSLivelinessLostCallbackType liveliness_callback;
70  QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
71  IncompatibleTypeCallbackType incompatible_type_callback;
72  PublisherMatchedCallbackType matched_callback;
73 };
74 
77 {
78  QOSDeadlineRequestedCallbackType deadline_callback;
79  QOSLivelinessChangedCallbackType liveliness_callback;
80  QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
81  QOSMessageLostCallbackType message_lost_callback;
82  IncompatibleTypeCallbackType incompatible_type_callback;
83  SubscriptionMatchedCallbackType matched_callback;
84 };
85 
86 class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
87 {
88 public:
89  RCLCPP_PUBLIC
91  rcl_ret_t ret,
92  const rcl_error_state_t * error_state,
93  const std::string & prefix);
94 
95  RCLCPP_PUBLIC
97  const exceptions::RCLErrorBase & base_exc,
98  const std::string & prefix);
99 };
100 
102 {
103 public:
104  enum class EntityType : std::size_t
105  {
106  Event,
107  };
108 
109  RCLCPP_PUBLIC
110  virtual ~EventHandlerBase();
111 
112  RCLCPP_PUBLIC
113  virtual
114  void enable() = 0;
115 
116  RCLCPP_PUBLIC
117  virtual
118  void disable() = 0;
119 
121  RCLCPP_PUBLIC
122  size_t
123  get_number_of_ready_events() override;
124 
126  RCLCPP_PUBLIC
127  void
128  add_to_wait_set(rcl_wait_set_t & wait_set) override;
129 
131  RCLCPP_PUBLIC
132  bool
133  is_ready(const rcl_wait_set_t & wait_set) override;
134 
136 
171  RCLCPP_PUBLIC
172  void
173  set_on_ready_callback(std::function<void(size_t, int)> callback) override;
174 
176  RCLCPP_PUBLIC
177  void
178  clear_on_ready_callback() override;
179 
180  RCLCPP_PUBLIC
181  std::vector<std::shared_ptr<rclcpp::TimerBase>>
182  get_timers() const override;
183 
184 protected:
185  RCLCPP_PUBLIC
186  void
187  set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
188 
189  std::recursive_mutex on_new_event_callback_mutex_;
190  std::function<void(size_t)> on_new_event_callback_{nullptr};
191 
192  rcl_event_t event_handle_;
193  size_t wait_set_event_index_;
194 };
195 
196 template<typename EventCallbackT, typename ParentHandleT>
198 {
199 public:
200  template<typename InitFuncT, typename EventTypeEnum>
201  EventHandler(
202  const EventCallbackT & callback,
203  InitFuncT init_func,
204  ParentHandleT parent_handle,
205  EventTypeEnum event_type)
206  : parent_handle_(parent_handle), event_callback_(callback)
207  {
208  event_handle_ = rcl_get_zero_initialized_event();
209  rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
210  if (ret != RCL_RET_OK) {
211  if (ret == RCL_RET_UNSUPPORTED) {
212  UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
213  rcl_reset_error();
214  throw exc;
215  } else {
216  rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
217  }
218  }
219  }
220 
221  ~EventHandler()
222  {
223  // Since the rmw event listener holds a reference to the
224  // "on ready" callback, we need to clear it on destruction of this class.
225  // This clearing is not needed for other rclcpp entities like pub/subs, since
226  // they do own the underlying rmw entities, which are destroyed
227  // on their rclcpp destructors, thus no risk of dangling pointers.
229  }
230 
232  std::shared_ptr<void>
233  take_data() override
234  {
235  EventCallbackInfoT callback_info;
236  rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
237  if (ret != RCL_RET_OK) {
238  RCUTILS_LOG_ERROR_NAMED(
239  "rclcpp",
240  "Couldn't take event info: %s", rcl_get_error_string().str);
241  rcl_reset_error();
242  return nullptr;
243  }
244  return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
245  }
246 
247  std::shared_ptr<void>
248  take_data_by_entity_id([[maybe_unused]] size_t id) override
249  {
250  return take_data();
251  }
252 
254  void
255  execute(const std::shared_ptr<void> & data) override
256  {
257  std::unique_lock<std::mutex> event_callback_lock(event_callback_mutex_);
258  if (disabled_.load()) {
259  return;
260  }
261  if (!data) {
262  throw std::runtime_error("'data' is empty");
263  }
264  auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
265  event_callback_(*callback_ptr);
266  callback_ptr.reset();
267  }
268 
270 
274  void disable() override
275  {
276  {
277  // Temporary remove the on_new_event_callback_ to prevent it from being called
278  std::lock_guard<std::recursive_mutex> on_new_event_lock(on_new_event_callback_mutex_);
279  if (on_new_event_callback_) {
280  set_on_new_event_callback(nullptr, nullptr);
281  }
282  }
283  std::lock_guard<std::mutex> event_callback_lock(event_callback_mutex_);
284  disabled_.store(true);
285  }
286 
288 
292  void enable() override
293  {
294  {
295  // Set callback again if it was previously removed in disable()
296  std::lock_guard<std::recursive_mutex> on_new_event_lock(on_new_event_callback_mutex_);
297  if (on_new_event_callback_) {
298  set_on_new_event_callback(
299  rclcpp::detail::cpp_callback_trampoline<
300  decltype(on_new_event_callback_), const void *, size_t>,
301  static_cast<const void *>(&on_new_event_callback_));
302  }
303  }
304  std::lock_guard<std::mutex> event_callback_lock(event_callback_mutex_);
305  disabled_.store(false);
306  }
307 
308 private:
309  using EventCallbackInfoT = typename std::remove_reference<typename
311 
312  ParentHandleT parent_handle_;
313  EventCallbackT event_callback_;
314  std::mutex event_callback_mutex_;
315  std::atomic_bool disabled_{false};
316 };
317 } // namespace rclcpp
318 
319 #endif // RCLCPP__EVENT_HANDLER_HPP_
RCLCPP_PUBLIC size_t get_number_of_ready_events() override
Get the number of ready events.
RCLCPP_PUBLIC void add_to_wait_set(rcl_wait_set_t &wait_set) override
Add the Waitable to a wait set.
RCLCPP_PUBLIC void set_on_ready_callback(std::function< void(size_t, int)> callback) override
Set a callback to be called when each new event instance occurs.
RCLCPP_PUBLIC bool is_ready(const rcl_wait_set_t &wait_set) override
Check if the Waitable is ready.
RCLCPP_PUBLIC void clear_on_ready_callback() override
Unset the callback registered for new events, if any.
RCLCPP_PUBLIC std::vector< std::shared_ptr< rclcpp::TimerBase > > get_timers() const override
Returns all timers used by this waitable.
void disable() override
Disable the event callback from being called when execute(..) invoked.
void enable() override
Enable the event callback to be called when execute(..) invoked.
void execute(const std::shared_ptr< void > &data) override
Execute any entities of the Waitable that are ready.
std::shared_ptr< void > take_data() override
Take data so that the callback cannot be scheduled again.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_event(const rcl_event_t *event, void *event_info)
Definition: event.c:162
RCL_PUBLIC RCL_WARN_UNUSED rcl_event_t rcl_get_zero_initialized_event(void)
Return a rcl_event_t struct with members set to NULL.
Definition: event.c:35
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
Structure which encapsulates a ROS QoS event handle.
Definition: event.h:61
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42
Contains callbacks for various types of events a Publisher can receive from the middleware.
Contains callbacks for non-message events that a Subscription can receive from the middleware.
#define RCL_RET_UNSUPPORTED
Unsupported return code.
Definition: types.h:37
#define RCL_RET_OK
Success return code.
Definition: types.h:27
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24