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