Skip to content

Commit

Permalink
Made the lib optinally thread-safe, added running state
Browse files Browse the repository at this point in the history
Signed-off-by: AssemblyJohn <[email protected]>
  • Loading branch information
AssemblyJohn committed Feb 5, 2024
1 parent d7ee45a commit 3f240c7
Showing 1 changed file with 71 additions and 14 deletions.
85 changes: 71 additions & 14 deletions include/everest/timer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,36 @@
#include <thread>

namespace Everest {

template <typename Type, bool Exists> struct OptionalTimerMember {
Type data;
};

template <typename Type> struct OptionalTimerMember<Type, false> {};

template <template<typename> typename Guard, typename Mutex, bool Enabled> struct OptionalGuard {
OptionalGuard(OptionalTimerMember<Mutex, Enabled> &in_mutex) {

Check notice on line 24 in include/everest/timer.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/everest/timer.hpp#L24

Struct 'OptionalGuard' has a constructor with 1 argument that is not explicit.
if constexpr (Enabled) {
guard.data = std::move(Guard<Mutex>(in_mutex.data));
}
}

OptionalTimerMember<Guard<Mutex>, Enabled> guard;
};

// template <typename TimerClock = date::steady_clock> class Timer {
template <typename TimerClock = date::utc_clock> class Timer {
template <typename TimerClock = date::utc_clock, bool ThreadSafe = false> class Timer {
private:
boost::asio::basic_waitable_timer<TimerClock>* timer = nullptr;
std::function<void()> callback;
std::function<void(const boost::system::error_code& e)> callback_wrapper;
std::chrono::nanoseconds interval_nanoseconds;
std::condition_variable cv;
std::mutex wait_mutex;
bool running = false;
std::chrono::nanoseconds interval_nanoseconds;
boost::asio::io_context io_context;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work;
std::thread* timer_thread = nullptr;
bool running = false;

OptionalTimerMember<std::mutex, ThreadSafe> mutex;

public:
/// This timer will initialize a boost::asio::io_context
Expand Down Expand Up @@ -68,23 +85,32 @@ template <typename TimerClock = date::utc_clock> class Timer {
/// Executes the given callback at the given timepoint
template <class Clock, class Duration = typename Clock::duration>
void at(const std::function<void()>& callback, const std::chrono::time_point<Clock, Duration>& time_point) {
this->stop();

this->callback = callback;
if constexpr(ThreadSafe) {
OptionalGuard<std::unique_lock, std::mutex, ThreadSafe> optional_guard(this->mutex);

Check notice on line 89 in include/everest/timer.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/everest/timer.hpp#L89

Variable 'optional_guard' is assigned a value that is never used.
this->stop();
this->callback = callback;
} else {
this->stop();
this->callback = callback;
}

this->at(time_point);
}

/// Executes the at the given timepoint
template <class Clock, class Duration = typename Clock::duration>
void at(const std::chrono::time_point<Clock, Duration>& time_point) {
OptionalGuard<std::unique_lock, std::mutex, ThreadSafe> optional_guard(this->mutex);

this->stop();

if (this->callback == nullptr) {
return;
}

if (this->timer != nullptr) {
running = true;

// use asio timer
this->timer->expires_at(time_point);
this->timer->async_wait([this](const boost::system::error_code& e) {
Expand All @@ -93,22 +119,32 @@ template <typename TimerClock = date::utc_clock> class Timer {
}

this->callback();
running = false;
});
}
}

/// Execute the given callback peridically from now in the given interval
template <class Rep, class Period>
void interval(const std::function<void()>& callback, const std::chrono::duration<Rep, Period>& interval) {
this->stop();

this->callback = callback;
if constexpr(ThreadSafe) {
OptionalGuard<std::unique_lock, std::mutex, ThreadSafe> optional_guard(this->mutex);

this->stop();
this->callback = callback;
} else {
this->stop();
this->callback = callback;
}


this->interval(interval);
}

/// Execute peridically from now in the given interval
template <class Rep, class Period> void interval(const std::chrono::duration<Rep, Period>& interval) {
OptionalGuard<std::unique_lock, std::mutex, ThreadSafe> optional_guard(this->mutex);

this->stop();
this->interval_nanoseconds = interval;
if (interval_nanoseconds == std::chrono::nanoseconds(0)) {
Expand All @@ -120,9 +156,12 @@ template <typename TimerClock = date::utc_clock> class Timer {
}

if (this->timer != nullptr) {
running = true;

// use asio timer
this->callback_wrapper = [this](const boost::system::error_code& e) {
if (e) {
running = false;
return;
}

Expand All @@ -140,40 +179,58 @@ template <typename TimerClock = date::utc_clock> class Timer {
// Execute the given callback once after the given interval
template <class Rep, class Period>
void timeout(const std::function<void()>& callback, const std::chrono::duration<Rep, Period>& interval) {
this->stop();

this->callback = callback;
if constexpr (ThreadSafe) {
OptionalGuard<std::unique_lock, std::mutex, ThreadSafe> optional_guard(this->mutex);
this->stop();
this->callback = callback;
} else {
this->stop();
this->callback = callback;
}

this->timeout(interval);
}

// Execute the given callback once after the given interval
template <class Rep, class Period> void timeout(const std::chrono::duration<Rep, Period>& interval) {
OptionalGuard<std::unique_lock, std::mutex, ThreadSafe> optional_guard(this->mutex);
this->stop();

if (this->callback == nullptr) {
return;
}

if (this->timer != nullptr) {
running = true;

// use asio timer
this->timer->expires_from_now(interval);
this->timer->async_wait([this](const boost::system::error_code& e) {
if (e) {
running = false;
return;
}

this->callback();
running = false;
});
}
}

/// Stop timer from excuting its callback
void stop() {
OptionalGuard<std::unique_lock, std::mutex, ThreadSafe> optional_guard(this->mutex);

if (this->timer != nullptr) {
// asio based timer
this->timer->cancel();
}

running = false;
}

bool is_running() {
return running;
}
};

Expand Down

0 comments on commit 3f240c7

Please sign in to comment.