ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
event_handler.cpp
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 #include <functional>
16 #include <memory>
17 #include <mutex>
18 #include <stdexcept>
19 #include <string>
20 #include <vector>
21 
22 #include "rcl/error_handling.h"
23 #include "rcl/event.h"
24 
25 #include "rmw/impl/cpp/demangle.hpp"
26 
27 #include "rclcpp/detail/cpp_callback_trampoline.hpp"
28 #include "rclcpp/event_handler.hpp"
29 #include "rclcpp/exceptions/exceptions.hpp"
30 #include "rclcpp/logging.hpp"
31 #include "rclcpp/timer.hpp"
32 
33 namespace rclcpp
34 {
35 
36 UnsupportedEventTypeException::UnsupportedEventTypeException(
37  rcl_ret_t ret,
38  const rcl_error_state_t * error_state,
39  const std::string & prefix)
40 : UnsupportedEventTypeException(exceptions::RCLErrorBase(ret, error_state), prefix)
41 {}
42 
43 UnsupportedEventTypeException::UnsupportedEventTypeException(
44  const exceptions::RCLErrorBase & base_exc,
45  const std::string & prefix)
46 : exceptions::RCLErrorBase(base_exc),
47  std::runtime_error(prefix + (prefix.empty() ? "" : ": ") + base_exc.formatted_message)
48 {}
49 
50 EventHandlerBase::~EventHandlerBase()
51 {
52  if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {
53  RCUTILS_LOG_ERROR_NAMED(
54  "rclcpp",
55  "Error in destruction of rcl event handle: %s", rcl_get_error_string().str);
56  rcl_reset_error();
57  }
58 }
59 
61 size_t
62 EventHandlerBase::get_number_of_ready_events()
63 {
64  return 1;
65 }
66 
68 void
69 EventHandlerBase::add_to_wait_set(rcl_wait_set_t & wait_set)
70 {
71  rcl_ret_t ret = rcl_wait_set_add_event(&wait_set, &event_handle_, &wait_set_event_index_);
72  if (RCL_RET_OK != ret) {
73  exceptions::throw_from_rcl_error(ret, "Couldn't add event to wait set");
74  }
75 }
76 
78 bool
79 EventHandlerBase::is_ready(const rcl_wait_set_t & wait_set)
80 {
81  return wait_set.events[wait_set_event_index_] == &event_handle_;
82 }
83 
84 void
85 EventHandlerBase::set_on_new_event_callback(
86  rcl_event_callback_t callback,
87  const void * user_data)
88 {
90  &event_handle_,
91  callback,
92  user_data);
93 
94  if (RCL_RET_OK != ret) {
95  using rclcpp::exceptions::throw_from_rcl_error;
96  throw_from_rcl_error(ret, "failed to set the on new message callback for Event");
97  }
98 }
99 
100 void
101 EventHandlerBase::set_on_ready_callback(std::function<void(size_t, int)> callback)
102 {
103  if (!callback) {
104  throw std::invalid_argument(
105  "The callback passed to set_on_ready_callback "
106  "is not callable.");
107  }
108 
109  // Note: we bind the int identifier argument to this waitable's entity types
110  auto new_callback =
111  [callback, this](size_t number_of_events) {
112  try {
113  callback(number_of_events, static_cast<int>(EntityType::Event));
114  } catch (const std::exception & exception) {
115  RCLCPP_ERROR_STREAM(
116  // TODO(wjwwood): get this class access to the node logger it is associated with
117  rclcpp::get_logger("rclcpp"),
118  "rclcpp::EventHandlerBase@" << this <<
119  " caught " << rmw::impl::cpp::demangle(exception) <<
120  " exception in user-provided callback for the 'on ready' callback: " <<
121  exception.what());
122  } catch (...) {
123  RCLCPP_ERROR_STREAM(
124  rclcpp::get_logger("rclcpp"),
125  "rclcpp::EventHandlerBase@" << this <<
126  " caught unhandled exception in user-provided callback " <<
127  "for the 'on ready' callback");
128  }
129  };
130 
131  std::lock_guard<std::recursive_mutex> lock(on_new_event_callback_mutex_);
132 
133  // Set it temporarily to the new callback, while we replace the old one.
134  // This two-step setting, prevents a gap where the old std::function has
135  // been replaced but the middleware hasn't been told about the new one yet.
136  set_on_new_event_callback(
137  rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
138  static_cast<const void *>(&new_callback));
139 
140  // Store the std::function to keep it in scope, also overwrites the existing one.
141  on_new_event_callback_ = new_callback;
142 
143  // Set it again, now using the permanent storage.
144  set_on_new_event_callback(
145  rclcpp::detail::cpp_callback_trampoline<
146  decltype(on_new_event_callback_), const void *, size_t>,
147  static_cast<const void *>(&on_new_event_callback_));
148 }
149 
150 void
151 EventHandlerBase::clear_on_ready_callback()
152 {
153  std::lock_guard<std::recursive_mutex> lock(on_new_event_callback_mutex_);
154  if (on_new_event_callback_) {
155  set_on_new_event_callback(nullptr, nullptr);
156  on_new_event_callback_ = nullptr;
157  }
158 }
159 
160 std::vector<std::shared_ptr<rclcpp::TimerBase>>
161 EventHandlerBase::get_timers() const
162 {
163  return {};
164 }
165 
166 } // namespace rclcpp
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_event_set_callback(const rcl_event_t *event, rcl_event_callback_t callback, const void *user_data)
Set the callback function for the event.
Definition: event.c:292
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_event_fini(rcl_event_t *event)
Definition: event.c:187
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
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42
const rcl_event_t ** events
Storage for event pointers.
Definition: wait.h:64
#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
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_event(rcl_wait_set_t *wait_set, const rcl_event_t *event, size_t *index)
Store a pointer to the event in the next empty spot in the set.
Definition: wait.c:526