9#include <condition_variable>
17namespace display_device {
60 bool m_stop_requested {
false};
61 std::function<void()> m_cleanup;
69 template<
class FunctionT>
71 static_cast<bool>(exec_fn);
77 template<
class T,
bool AddConst>
87 using type = std::add_const_t<T>;
93 template<
class T,
bool AddConst>
100 template<
class T,
class FunctionT>
107 template<
class T,
class FunctionT>
109 exec_fn(value, token);
115 template<
class T,
class FunctionT>
150 m_iface {iface ? std::move(iface) : throw std::logic_error {
"Nullptr interface provided in RetryScheduler!"}},
152 std::unique_lock lock {m_mutex};
153 while (m_keep_alive) {
154 m_syncing_thread =
false;
155 if (
auto duration {takeNextDuration(m_sleep_durations)}; duration > std::chrono::milliseconds::zero()) {
157 m_sleep_cv.wait_for(lock, duration, [
this]() {
158 return m_syncing_thread;
162 m_sleep_cv.wait(lock, [
this]() {
163 return m_syncing_thread;
167 if (m_syncing_thread) {
174 clearThreadLoopUnlocked();
176 m_retry_function(*m_iface, scheduler_stop_token);
178 }
catch (
const std::exception &error) {
179 DD_LOG(error) <<
"Exception thrown in the RetryScheduler thread. Stopping scheduler. Error:\n"
183 clearThreadLoopUnlocked();
193 std::lock_guard lock {m_mutex};
194 m_keep_alive =
false;
195 syncThreadUnlocked();
221 throw std::logic_error {
"Empty callback function provided in RetryScheduler::schedule!"};
225 throw std::logic_error {
"At least 1 sleep duration must be specified in RetryScheduler::schedule!"};
229 return duration == std::chrono::milliseconds::zero();
231 throw std::logic_error {
"All of the durations specified in RetryScheduler::schedule must be larger than a 0!"};
234 std::lock_guard lock {m_mutex};
245 std::this_thread::sleep_for(takeNextDuration(sleep_durations));
248 exec_fn(*m_iface, stop_token);
252 m_retry_function = std::move(exec_fn);
253 m_sleep_durations = std::move(sleep_durations);
254 syncThreadUnlocked();
256 }
catch (
const std::exception &error) {
258 DD_LOG(error) <<
"Exception thrown in the RetryScheduler::schedule. Stopping scheduler. Error:\n"
266 template<
class FunctionT>
268 return executeImpl(*
this, std::forward<FunctionT>(exec_fn));
274 template<
class FunctionT>
276 return executeImpl(*
this, std::forward<FunctionT>(exec_fn));
284 return static_cast<bool>(m_retry_function);
291 std::lock_guard lock {m_mutex};
296 static std::chrono::milliseconds takeNextDuration(std::vector<std::chrono::milliseconds> &durations) {
297 if (durations.size() > 1) {
298 const auto front_it {std::begin(durations)};
299 const auto front_value {*front_it};
300 durations.erase(front_it);
304 return durations.empty() ? std::chrono::milliseconds::zero() : durations.back();
343 static auto executeImpl(
auto &self,
auto &&exec_fn)
344 requires detail::ExecuteCallbackLike<T,
decltype(exec_fn)>
346 using FunctionT =
decltype(exec_fn);
347 constexpr bool IsConst = std::is_const_v<std::remove_reference_t<
decltype(self)>>;
349 if constexpr (detail::OptionalFunction<FunctionT>) {
351 throw std::logic_error {
"Empty callback function provided in RetryScheduler::execute!"};
355 std::lock_guard lock {self.m_mutex};
356 detail::auto_const_t<std::decay_t<T>, IsConst> &iface_ref {*self.m_iface};
357 if constexpr (detail::ExecuteWithStopToken<T, FunctionT>) {
358 detail::auto_const_t<SchedulerStopToken, IsConst> stop_token {[&self]() {
359 if constexpr (!IsConst) {
363 return std::forward<FunctionT>(exec_fn)(iface_ref, stop_token);
365 return std::forward<FunctionT>(exec_fn)(iface_ref);
372 void clearThreadLoopUnlocked() {
373 m_sleep_durations = {};
374 m_retry_function =
nullptr;
380 void syncThreadUnlocked() {
381 m_syncing_thread =
true;
382 m_sleep_cv.notify_one();
388 void stopUnlocked() {
390 clearThreadLoopUnlocked();
391 syncThreadUnlocked();
395 std::unique_ptr<T> m_iface;
396 std::vector<std::chrono::milliseconds> m_sleep_durations;
397 std::function<void(T &, SchedulerStopToken &)> m_retry_function {
nullptr};
399 mutable std::mutex m_mutex {};
400 std::condition_variable m_sleep_cv {};
401 bool m_syncing_thread {
false};
402 bool m_keep_alive {
true};
405 std::thread m_thread;
A wrapper class around an interface that provides a thread-safe access to the interface and allows to...
Definition retry_scheduler.h:143
auto execute(FunctionT &&exec_fn)
A non-const variant of the executeImpl method. See it for details.
Definition retry_scheduler.h:267
RetryScheduler(std::unique_ptr< T > iface)
Default constructor.
Definition retry_scheduler.h:149
void schedule(std::function< void(T &, SchedulerStopToken &stop_token)> exec_fn, const SchedulerOptions &options)
Schedule an interface executor function to be executed at specified intervals.
Definition retry_scheduler.h:219
bool isScheduled() const
Check whether anything is scheduled for execution.
Definition retry_scheduler.h:283
~RetryScheduler()
A destructor that gracefully shuts down the thread.
Definition retry_scheduler.h:191
auto execute(FunctionT &&exec_fn) const
A const variant of the executeImpl method. See it for details.
Definition retry_scheduler.h:275
void stop()
Stop the scheduled function - will no longer be execute once THIS method returns.
Definition retry_scheduler.h:290
A convenience class for stopping the RetryScheduler.
Definition retry_scheduler.h:25
SchedulerStopToken(std::function< void()> cleanup)
Default constructor.
Definition retry_scheduler.cpp:9
SchedulerStopToken & operator=(const SchedulerStopToken &)=delete
Deleted copy operator.
SchedulerStopToken(const SchedulerStopToken &)=delete
Deleted copy constructor.
bool stopRequested() const
Check if stop was requested.
Definition retry_scheduler.cpp:23
void requestStop()
Request the scheduler to be stopped.
Definition retry_scheduler.cpp:19
~SchedulerStopToken()
Executes cleanup logic if scheduler stop was requested.
Definition retry_scheduler.cpp:13
Check if the function signature matches the acceptable signature for RetryScheduler::execute.
Definition retry_scheduler.h:116
Check if the function signature matches the acceptable signature for RetryScheduler::execute with a s...
Definition retry_scheduler.h:108
Check if the function signature matches the acceptable signature for RetryScheduler::execute without ...
Definition retry_scheduler.h:101
Given that we know that we are dealing with a function, check if it is an optional function (like std...
Definition retry_scheduler.h:70
Declarations for the logging utility.
#define DD_LOG(level)
Helper MACRO that disables output string computation if log level is not enabled.
Definition logging.h:153
typename AutoConst< T, AddConst >::type auto_const_t
A convenience template helper for adding const to the type.
Definition retry_scheduler.h:94
Scheduler options to be used when scheduling executor function.
Definition retry_scheduler.h:122
Execution m_execution
Executor's execution logic.
Definition retry_scheduler.h:133
std::vector< std::chrono::milliseconds > m_sleep_durations
Specifies for long the scheduled thread sleeps before invoking executor. Last duration is reused inde...
Definition retry_scheduler.h:132
Execution
Defines the executor's execution logic when it is scheduled.
Definition retry_scheduler.h:126
@ ImmediateWithSleep
The first sleep duration is TAKEN from m_sleep_durations and the calling thread is put to sleep....
@ Immediate
Executor is executed in the calling thread immediately and scheduled afterward.
@ ScheduledOnly
Executor is executed in the thread only.
A convenience template struct helper for adding const to the type.
Definition retry_scheduler.h:78