ROS 2 rclcpp + rcl - rolling  rolling-20536064
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>
149 FirstInFirstOutScheduler::get_handle_for_callback_group(
150  const rclcpp::CallbackGroup::SharedPtr & callback_group)
151 {
152  return std::make_unique<FirstInFirstOutCallbackGroupHandle>(*this, callback_group->type());
153 }
154 
155 CBGScheduler::ExecutableEntityWithInfo FirstInFirstOutScheduler::get_next_ready_entity_intern()
156 {
157  std::lock_guard l(ready_callback_groups_mutex);
158 
159  while(!ready_callback_groups.empty()) {
160  FirstInFirstOutCallbackGroupHandle *ready_cbg =
161  static_cast<FirstInFirstOutCallbackGroupHandle *>(ready_callback_groups.front());
162  ready_callback_groups.pop_front();
163  ready_cbg->in_queue = false;
164 
165  std::optional<FirstInFirstOutScheduler::ExecutableEntity> ret =
166  ready_cbg->get_next_ready_entity();
167 
168  if (ready_cbg->get_type() == CallbackGroupType::Reentrant && ready_cbg->has_ready_entities()) {
169  ready_callback_groups.push_back(ready_cbg);
170  ready_cbg->in_queue = true;
171  }
172 
173  if(ret) {
174  return CBGScheduler::ExecutableEntityWithInfo{.entity = std::move(ret),
175  .moreEntitiesReady = !ready_callback_groups.empty()};
176  }
177  }
178 
179  return CBGScheduler::ExecutableEntityWithInfo{.entity = std::nullopt,
180  .moreEntitiesReady = false};
181 }
182 
183 CBGScheduler::ExecutableEntityWithInfo FirstInFirstOutScheduler::get_next_ready_entity_intern(
184  GlobalEventIdProvider::MonotonicId max_id)
185 {
186  std::lock_guard l(ready_callback_groups_mutex);
187 
188  // as, we remove an reappend ready callback_groups during execution,
189  // the first ready cbg may not contain the lowest id. Therefore we
190  // need to search the whole deque
191  for(auto it = ready_callback_groups.begin(); it != ready_callback_groups.end(); it++) {
192  FirstInFirstOutCallbackGroupHandle *ready_cbg(
193  static_cast<FirstInFirstOutCallbackGroupHandle *>(*it));
194  std::optional<FirstInFirstOutScheduler::ExecutableEntity> ret =
195  ready_cbg->get_next_ready_entity(max_id);
196  if(ret) {
197  ready_callback_groups.erase(it);
198  ready_cbg->in_queue = false;
199 
200  if (
201  ready_cbg->get_type() == CallbackGroupType::Reentrant && ready_cbg->has_ready_entities())
202  {
203  ready_callback_groups.push_back(ready_cbg);
204  ready_cbg->in_queue = true;
205  }
206  return CBGScheduler::ExecutableEntityWithInfo{
207  .entity = std::move(ret), .moreEntitiesReady = !ready_callback_groups.empty()};
208  }
209  }
210 
211  return CBGScheduler::ExecutableEntityWithInfo{.entity = std::nullopt,
212  .moreEntitiesReady = false};
213 }
214 } // namespace cbg_executor
215 } // namespace executors
216 } // namespace rclcpp
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.