9#include <condition_variable>
23namespace display_device {
66 bool m_stop_requested {
false};
67 std::function<void()> m_cleanup;
77 DD_LOG(error) << message <<
" Error:\n"
85 template<
class FunctionT>
87 static_cast<bool>(exec_fn);
95 template<
class T,
bool AddConst>
119 using type = std::add_const_t<T>;
127 template<
class T,
bool AddConst>
134 template<
class T,
class FunctionT>
141 template<
class T,
class FunctionT>
143 exec_fn(value, token);
149 template<
class T,
class FunctionT>
184 m_iface {iface ? std::move(iface) : throw std::invalid_argument {
"Nullptr interface provided in RetryScheduler!"}},
195 std::lock_guard lock {m_mutex};
196 m_keep_alive =
false;
197 syncThreadUnlocked();
200 if (m_thread.joinable()) {
225 throw std::invalid_argument {
"Empty callback function provided in RetryScheduler::schedule!"};
229 throw std::invalid_argument {
"At least 1 sleep duration must be specified in RetryScheduler::schedule!"};
233 return duration == std::chrono::milliseconds::zero();
235 throw std::invalid_argument {
"All of the durations specified in RetryScheduler::schedule must be larger than a 0!"};
238 std::lock_guard lock {m_mutex};
249 std::this_thread::sleep_for(takeNextDuration(sleep_durations));
252 exec_fn(*m_iface, stop_token);
256 m_retry_function = std::move(exec_fn);
257 m_sleep_durations = std::move(sleep_durations);
258 syncThreadUnlocked();
260 }
catch (
const std::exception &error) {
262 detail::logSchedulerException(error,
"Exception thrown in the RetryScheduler::schedule. Stopping scheduler.");
272 template<
class FunctionT>
274 return executeImpl(*
this, std::forward<FunctionT>(exec_fn));
283 template<
class FunctionT>
285 return executeImpl(*
this, std::forward<FunctionT>(exec_fn));
293 return static_cast<bool>(m_retry_function);
300 std::lock_guard lock {m_mutex};
305 static std::chrono::milliseconds takeNextDuration(std::vector<std::chrono::milliseconds> &durations) {
306 if (durations.size() > 1) {
307 const auto front_it {std::begin(durations)};
308 const auto front_value {*front_it};
309 durations.erase(front_it);
313 return durations.empty() ? std::chrono::milliseconds::zero() : durations.back();
352 template<
class SelfT,
class FunctionT>
353 requires detail::ExecuteCallbackLike<T, FunctionT>
354 static auto executeImpl(SelfT &self, FunctionT &&exec_fn) {
355 constexpr bool IsConst = std::is_const_v<std::remove_reference_t<SelfT>>;
357 if constexpr (detail::OptionalFunction<FunctionT>) {
359 throw std::invalid_argument {
"Empty callback function provided in RetryScheduler::execute!"};
363 std::lock_guard lock {self.m_mutex};
364 detail::auto_const_t<std::decay_t<T>, IsConst> &iface_ref {*self.m_iface};
365 if constexpr (detail::ExecuteWithStopToken<T, FunctionT>) {
366 detail::auto_const_t<SchedulerStopToken, IsConst> stop_token {makeStopCallback(self)};
367 return std::forward<FunctionT>(exec_fn)(iface_ref, stop_token);
369 return std::forward<FunctionT>(exec_fn)(iface_ref);
373 template<
class SelfT>
374 static auto makeStopCallback(SelfT &self) {
375 constexpr bool IsConst = std::is_const_v<std::remove_reference_t<SelfT>>;
376 if constexpr (IsConst) {
387 void runThreadLoop() {
388 std::unique_lock lock {m_mutex};
389 while (m_keep_alive) {
390 m_syncing_thread =
false;
391 waitForNextRetry(lock);
393 if (m_syncing_thread) {
399 SchedulerStopToken scheduler_stop_token {[
this]() {
400 clearThreadLoopUnlocked();
402 m_retry_function(*m_iface, scheduler_stop_token);
404 }
catch (
const std::exception &error) {
405 detail::logSchedulerException(error,
"Exception thrown in the RetryScheduler thread. Stopping scheduler.");
408 clearThreadLoopUnlocked();
412 void waitForNextRetry(std::unique_lock<std::mutex> &lock) {
413 if (
const auto duration {takeNextDuration(m_sleep_durations)}; duration > std::chrono::milliseconds::zero()) {
415 m_sleep_cv.wait_for(lock, duration, [
this]() {
416 return m_syncing_thread;
422 m_sleep_cv.wait(lock, [
this]() {
423 return m_syncing_thread;
430 void clearThreadLoopUnlocked() {
431 m_sleep_durations = {};
432 m_retry_function =
nullptr;
438 void syncThreadUnlocked() {
439 m_syncing_thread =
true;
440 m_sleep_cv.notify_one();
446 void stopUnlocked() {
448 clearThreadLoopUnlocked();
449 syncThreadUnlocked();
453 std::unique_ptr<T> m_iface;
454 std::vector<std::chrono::milliseconds> m_sleep_durations;
455 std::function<void(T &, SchedulerStopToken &)> m_retry_function {
nullptr};
457 mutable std::mutex m_mutex {};
458 std::condition_variable m_sleep_cv {};
459 bool m_syncing_thread {
false};
460 bool m_keep_alive {
true};
463 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:177
auto execute(FunctionT &&exec_fn)
A non-const variant of the executeImpl method. See it for details.
Definition retry_scheduler.h:273
RetryScheduler(std::unique_ptr< T > iface)
Default constructor.
Definition retry_scheduler.h:183
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:223
bool isScheduled() const
Check whether anything is scheduled for execution.
Definition retry_scheduler.h:292
~RetryScheduler()
A destructor that gracefully shuts down the thread.
Definition retry_scheduler.h:193
auto execute(FunctionT &&exec_fn) const
A const variant of the executeImpl method. See it for details.
Definition retry_scheduler.h:284
void stop()
Stop the scheduled function - will no longer be execute once THIS method returns.
Definition retry_scheduler.h:299
A convenience class for stopping the RetryScheduler.
Definition retry_scheduler.h:31
~SchedulerStopToken() noexcept
Executes cleanup logic if scheduler stop was requested.
Definition retry_scheduler.cpp:24
SchedulerStopToken(std::function< void()> cleanup)
Default constructor.
Definition retry_scheduler.cpp:20
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:38
void requestStop()
Request the scheduler to be stopped.
Definition retry_scheduler.cpp:34
Check if the function signature matches the acceptable signature for RetryScheduler::execute.
Definition retry_scheduler.h:150
Check if the function signature matches the acceptable signature for RetryScheduler::execute with a s...
Definition retry_scheduler.h:142
Check if the function signature matches the acceptable signature for RetryScheduler::execute without ...
Definition retry_scheduler.h:135
Given that we know that we are dealing with a function, check if it is an optional function (like std...
Definition retry_scheduler.h:86
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:128
void logSchedulerException(const std::exception &exception, const char *message)
Log an exception thrown by the scheduler or scheduler callback.
Definition retry_scheduler.h:76
Scheduler options to be used when scheduling executor function.
Definition retry_scheduler.h:156
Execution m_execution
Executor's execution logic.
Definition retry_scheduler.h:167
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:166
Execution
Defines the executor's execution logic when it is scheduled.
Definition retry_scheduler.h:160
@ 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.
T type
Original type.
Definition retry_scheduler.h:107
std::add_const_t< T > type
Const-qualified type.
Definition retry_scheduler.h:119
A convenience template struct helper for adding const to the type.
Definition retry_scheduler.h:96