ROS 2 rclcpp + rcl - jazzy  jazzy
ROS 2 C++ Client Library with ROS Client Library
first_in_first_out_scheduler.cpp
1 // Copyright 2024 Cellumation GmbH.
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 #include "first_in_first_out_scheduler.hpp"
15 #include <utility>
16 
17 namespace rclcpp
18 {
19 namespace executors
20 {
21 namespace cbg_executor
22 {
23 std::function<void(size_t)> FirstInFirstOutCallbackGroupHandle::get_ready_callback_for_entity(
24  const rclcpp::SubscriptionBase::WeakPtr & entity)
25 {
26  return [weak_ptr = entity, this](size_t nr_msg) {
27  add_ready_entity([&] () {
28  for (size_t i = 0; i < nr_msg; i++) {
29  ready_entities.emplace_back(weak_ptr);
30  }
31  });
32  };
33 }
34 
35 std::function<void(std::function<void()> executed_callback)> FirstInFirstOutCallbackGroupHandle::
36 get_ready_callback_for_entity(const rclcpp::TimerBase::WeakPtr & entity)
37 {
38  return [weak_ptr = entity, this](std::function<void()> executed_callback) {
39  add_ready_entity([&] () {
40  ready_entities.emplace_back(ReadyEntity::ReadyTimerWithExecutedCallback{weak_ptr,
41  executed_callback});
42  });
43  };
44 }
45 
46 std::function<void(size_t)> FirstInFirstOutCallbackGroupHandle::get_ready_callback_for_entity(
47  const rclcpp::ClientBase::WeakPtr & entity)
48 {
49  return [weak_ptr = entity, this](size_t nr_msg) {
50  add_ready_entity([&] () {
51  for (size_t i = 0; i < nr_msg; i++) {
52  ready_entities.emplace_back(weak_ptr);
53  }
54  });
55  };
56 }
57 
58 std::function<void(size_t)> FirstInFirstOutCallbackGroupHandle::get_ready_callback_for_entity(
59  const rclcpp::ServiceBase::WeakPtr & entity)
60 {
61  return [weak_ptr = entity, this](size_t nr_msg) {
62  add_ready_entity([&] () {
63  for (size_t i = 0; i < nr_msg; i++) {
64  ready_entities.emplace_back(weak_ptr);
65  }
66  });
67  };
68 }
69 
70 std::function<void(size_t,
71  int)> FirstInFirstOutCallbackGroupHandle::get_ready_callback_for_entity(
72  const rclcpp::Waitable::WeakPtr & entity)
73 {
74  return [weak_ptr = entity, this](size_t nr_msg, int event_type) {
75  add_ready_entity([&] () {
76  for (size_t i = 0; i < nr_msg; i++) {
77  ready_entities.emplace_back(CBGScheduler::WaitableWithEventType({weak_ptr,
78  event_type}));
79  }
80  });
81  };
82 }
83 std::function<void(size_t)> FirstInFirstOutCallbackGroupHandle::get_ready_callback_for_entity(
84  const CBGScheduler::CallbackEventType & entity)
85 {
86  return [weak_ptr = entity, this](size_t nr_msg) {
87  add_ready_entity([&] () {
88  for (size_t i = 0; i < nr_msg; i++) {
89  ready_entities.emplace_back(weak_ptr);
90  }
91  });
92  };
93 }
94 
95 std::optional<CBGScheduler::ExecutableEntity> FirstInFirstOutCallbackGroupHandle::
96 get_next_ready_entity()
97 {
98  std::lock_guard l(ready_mutex);
99 
100  while(!ready_entities.empty()) {
101  auto & first = ready_entities.front();
102 
103  std::function<void()> exec_fun = first.get_execute_function();
104  ready_entities.pop_front();
105  if(!exec_fun) {
106  // was deleted, or in case of timer was canceled
107  continue;
108  }
109 
111 
112  return CBGScheduler::ExecutableEntity{exec_fun, this};
113  }
114 
115  mark_as_skipped();
116 
117  return std::nullopt;
118 }
119 
120 std::optional<CBGScheduler::ExecutableEntity> FirstInFirstOutCallbackGroupHandle::
121 get_next_ready_entity(GlobalEventIdProvider::MonotonicId max_id)
122 {
123  std::lock_guard l(ready_mutex);
124 
125  while(!ready_entities.empty()) {
126  auto & first = ready_entities.front();
127  if(first.id > max_id) {
128  return std::nullopt;
129  }
130 
131  std::function<void()> exec_fun = first.get_execute_function();
132  ready_entities.pop_front();
133  if(!exec_fun) {
134  // was deleted, or in case of timer was canceled
135  continue;
136  }
137 
139 
140  return CBGScheduler::ExecutableEntity{exec_fun, this};
141  }
142 
143  mark_as_skipped();
144 
145  return std::nullopt;
146 }
147 
148 std::unique_ptr<FirstInFirstOutScheduler::CallbackGroupHandle> FirstInFirstOutScheduler::
149 get_handle_for_callback_group(const rclcpp::CallbackGroup::SharedPtr &/*callback_group*/)
150 {
151  return std::make_unique<FirstInFirstOutCallbackGroupHandle>(*this);
152 }
153 
154 CBGScheduler::ExecutableEntityWithInfo FirstInFirstOutScheduler::get_next_ready_entity_intern()
155 {
156  std::lock_guard l(ready_callback_groups_mutex);
157 
158  while(!ready_callback_groups.empty()) {
159  FirstInFirstOutCallbackGroupHandle *ready_cbg =
160  static_cast<FirstInFirstOutCallbackGroupHandle *>(ready_callback_groups.front());
161  ready_callback_groups.pop_front();
162 
163  std::optional<FirstInFirstOutScheduler::ExecutableEntity> ret =
164  ready_cbg->get_next_ready_entity();
165  if(ret) {
166  return CBGScheduler::ExecutableEntityWithInfo{std::move(ret),
167  !ready_callback_groups.empty()};
168  }
169  }
170 
171  return CBGScheduler::ExecutableEntityWithInfo{std::nullopt,
172  false};
173 }
174 
175 CBGScheduler::ExecutableEntityWithInfo FirstInFirstOutScheduler::get_next_ready_entity_intern(
176  GlobalEventIdProvider::MonotonicId max_id)
177 {
178  std::lock_guard l(ready_callback_groups_mutex);
179 
180  // as, we remove an reappend ready callback_groups during execution,
181  // the first ready cbg may not contain the lowest id. Therefore we
182  // need to search the whole deque
183  for(auto it = ready_callback_groups.begin(); it != ready_callback_groups.end(); it++) {
184  FirstInFirstOutCallbackGroupHandle *ready_cbg(
185  static_cast<FirstInFirstOutCallbackGroupHandle *>(*it));
186  std::optional<FirstInFirstOutScheduler::ExecutableEntity> ret =
187  ready_cbg->get_next_ready_entity(max_id);
188  if(ret) {
189  ready_callback_groups.erase(it);
190  return CBGScheduler::ExecutableEntityWithInfo{std::move(ret),
191  !ready_callback_groups.empty()};
192  }
193  }
194 
195  return CBGScheduler::ExecutableEntityWithInfo{std::nullopt,
196  false};
197 }
198 } // namespace cbg_executor
199 } // namespace executors
200 } // namespace rclcpp
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.