17 #include <condition_variable>
25 #include <rclcpp/callback_group.hpp>
26 #include "global_event_id_provider.hpp"
32 namespace cbg_executor
37 std::condition_variable condition_variable;
38 std::atomic<bool> wakeup =
false;
47 std::unique_lock lk(mutex);
48 condition_variable.wait(lk, [
this]() ->
bool {
53 void block_for(std::chrono::nanoseconds timeout)
55 std::unique_lock lk(mutex);
56 condition_variable.wait_for(lk, timeout, [
this]() ->
bool {
70 std::unique_lock lk(mutex);
73 condition_variable.notify_one();
84 void unblock_thread_safe()
86 std::unique_lock lk(mutex);
88 condition_variable.notify_one();
103 std::mutex workers_mutex;
104 std::deque<Worker *> workers;
106 bool release_workers =
false;
114 if(workers.empty()) {
118 Worker * worker = workers.front();
129 if(release_workers) {
132 workers.push_front(worker);
143 auto it = std::find(workers.begin(), workers.end(), worker);
144 if(it != workers.end()) {
156 std::deque<Worker *> cpy;
158 release_workers =
true;
168 rclcpp::Waitable::WeakPtr waitable;
169 int internal_event_type;
173 return waitable.expired();
180 : callback(std::move(callback))
184 std::function<void()> callback;
195 : scheduler(scheduler), type(type)
207 virtual std::function<void(
size_t)> get_ready_callback_for_entity(
208 const rclcpp::SubscriptionBase::WeakPtr & entity) = 0;
209 virtual std::function<void(std::function<
void()> executed_callback)>
210 get_ready_callback_for_entity(
const rclcpp::TimerBase::WeakPtr & entity) = 0;
211 virtual std::function<void(
size_t)> get_ready_callback_for_entity(
212 const rclcpp::ClientBase::WeakPtr & entity) = 0;
213 virtual std::function<void(
size_t)> get_ready_callback_for_entity(
214 const rclcpp::ServiceBase::WeakPtr & entity) = 0;
215 virtual std::function<void(
size_t,
216 int)> get_ready_callback_for_entity(
const rclcpp::Waitable::WeakPtr & entity) = 0;
217 virtual std::function<void(
size_t)> get_ready_callback_for_entity(
226 std::lock_guard l(ready_mutex);
238 CallbackGroupType get_type() {
return type;}
243 bool in_queue =
false;
260 template<
typename add_fun>
264 std::lock_guard l(ready_mutex);
268 if(not_ready || !idle) {
281 void mark_as_skipped()
295 if (type != CallbackGroupType::Reentrant) {
300 std::mutex ready_mutex;
304 bool not_ready =
false;
310 CallbackGroupType type;
316 std::function<void()> execute_function;
327 : sync_function(sync_function) {}
335 CallbackGroupHandle * add_callback_group(
const rclcpp::CallbackGroup::SharedPtr & callback_group)
337 auto uPtr = get_handle_for_callback_group(callback_group);
338 CallbackGroupHandle * ret = uPtr.get();
340 std::lock_guard lk(ready_callback_groups_mutex);
342 callback_groups.push_back(std::move(uPtr));
346 void remove_callback_group(
const CallbackGroupHandle *callback_handle)
348 std::lock_guard lk(ready_callback_groups_mutex);
350 auto cbg_it = std::find(ready_callback_groups.begin(),
351 ready_callback_groups.end(), callback_handle);
352 if (cbg_it != ready_callback_groups.end()) {
353 ready_callback_groups.erase(cbg_it);
356 callback_groups.remove_if([&callback_handle] (
const auto & e) {
357 return e.get() == callback_handle;
370 std::lock_guard l(ready_callback_groups_mutex);
372 if (!handle->in_queue) {
373 ready_callback_groups.push_back(handle);
374 handle->in_queue =
true;
378 if(callback_group_was_idle) {
385 std::optional<ExecutableEntity> entity;
386 bool moreEntitiesReady{};
397 std::lock_guard l(ready_callback_groups_mutex);
398 worker_checking_for_work =
false;
403 ExecutableEntity{.execute_function = sync_function, .callback_handle =
nullptr},
404 .moreEntitiesReady =
false};
411 GlobalEventIdProvider::MonotonicId max_id)
413 std::lock_guard l(ready_callback_groups_mutex);
414 worker_checking_for_work =
false;
418 return ExecutableEntityWithInfo{.entity =
419 ExecutableEntity{.execute_function = sync_function, .callback_handle =
nullptr},
420 .moreEntitiesReady =
false};
431 GlobalEventIdProvider::MonotonicId max_id) = 0;
443 bool wake_worker =
false;
445 std::lock_guard l(ready_callback_groups_mutex);
463 if(e.callback_handle !=
nullptr) {
475 std::lock_guard l(ready_callback_groups_mutex);
476 worker_checking_for_work =
true;
486 Worker * worker =
nullptr;
488 std::scoped_lock l(ready_callback_groups_mutex, worker_queue.workers_mutex);
489 if(worker_checking_for_work) {
493 if(worker ==
nullptr) {
496 worker_checking_for_work =
true;
516 void block_worker_thread_for(
Worker * worker, std::chrono::nanoseconds timeout)
521 worker->block_for(timeout);
524 std::lock_guard lk(worker_queue.workers_mutex);
528 void release_all_worker_threads()
530 std::deque<Worker *> workers;
532 std::lock_guard lk(worker_queue.workers_mutex);
535 for(Worker * worker : workers) {
536 worker->unblock_thread_safe();
541 virtual std::unique_ptr<CallbackGroupHandle> get_handle_for_callback_group(
542 const rclcpp::CallbackGroup::SharedPtr & callback_group) = 0;
550 worker->prepare_block();
551 std::scoped_lock l(ready_callback_groups_mutex, worker_queue.workers_mutex);
552 if(needs_sync || !ready_callback_groups.empty()) {
560 std::function<void ()> sync_function;
562 bool needs_sync =
false;
564 std::mutex ready_callback_groups_mutex;
565 std::deque<CallbackGroupHandle *> ready_callback_groups;
567 bool worker_checking_for_work =
false;
571 std::list<std::unique_ptr<CallbackGroupHandle>> callback_groups;
bool prepare_and_enqueue_worker(Worker *worker)
void unblock_one_worker_thread()
void callback_group_ready(CallbackGroupHandle *handle, bool callback_group_was_idle)
virtual ExecutableEntityWithInfo get_next_ready_entity_intern()=0
void mark_entity_as_executed(const ExecutableEntity &e)
void suppress_thread_wakeup()
ExecutableEntityWithInfo get_next_ready_entity()
void block_worker_thread(Worker *worker)
CBGScheduler(std::function< void()> sync_function)
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
virtual bool has_ready_entities() const =0
void add_ready_entity(const add_fun &fun)
void remove_worker_thread(Worker *worker)
std::deque< Worker * > release_all_worker_threads()
Worker * pop_blocked_worker_thread()
bool push_blocked_worker_thread(Worker *worker)