4#include "Stroika/Foundation/StroikaPreComp.h"
6#include <condition_variable>
12#include "Stroika/Foundation/Containers/Collection.h"
13#include "Stroika/Foundation/Debug/Main.h"
27using namespace Stroika::Foundation::Time;
29using Memory::MakeSharedPtr;
32 thread_local const void* tRunnerOf_{};
44 sb <<
"id: "sv << fID;
45 sb <<
", callNextAt: "sv << fCallNextAt;
46 sb <<
", frequency: "sv << fFrequency;
47 sb <<
", hysteresis: "sv << fHysteresis;
59 virtual ~Rep_ () =
default;
63 fData_.rwget ()->Add (RegisteredTask{timer, intervalTimer, Time::GetTickCount () + when});
66 void AddRepeating (TimerID timer,
const TimerCallback& intervalTimer,
const Time::Duration& repeatInterval,
const optional<Time::Duration>& hysteresis)
69 fData_.rwget ()->Add ({timer, intervalTimer, Time::GetTickCount () + repeatInterval, repeatInterval, hysteresis});
72 bool Remove (TimerID timer)
noexcept
77 unique_lock runningLock{fRunningMutex_};
79 wasThere = fData_.rwget ()->RemoveIf (timer);
82 if (tRunnerOf_ !=
this) {
83 fRunningChanged_.wait (runningLock, [&] () {
return fRunning_ != timer; });
89 RegisteredTaskCollection GetAllRegisteredTasks ()
const
92 return fData_.load ();
98 condition_variable fRunningChanged_;
99 optional<TimerID> fRunning_;
118 Require (Debug::AppearsDuringMainLifetime ());
119 fDataChanged_.WaitUntilQuietly (GetNextWakeupTime_ ());
120 fDataChanged_.Reset ();
128 for (
const RegisteredTask& i : elts2Run) {
130 lock_guard runningLock{fRunningMutex_};
131 if (not fData_.
cget ()->Contains (i.fID)) {
136 [[maybe_unused]]
auto&& doneRunning =
Finally ([
this] ()
noexcept {
138 lock_guard runningLock{fRunningMutex_};
141 fRunningChanged_.notify_all ();
143 IgnoreExceptionsExceptThreadAbortForCall (i.fCallback ());
145 auto rwDataLock = fData_.
rwget ();
146 if (optional<RegisteredTask> current = rwDataLock->Lookup (i.fID)) {
147 if (current->fFrequency.has_value ()) {
148 current->fCallNextAt = Time::GetTickCount () + *current->fFrequency;
149 if (current->fHysteresis) {
150 uniform_real_distribution<> dis{-current->fHysteresis->count (), current->fHysteresis->count ()};
153 rwDataLock->Add (*current);
156 rwDataLock->Remove (i.fID);
167 auto lk = fThread_.rwget ();
168 if (lk.cref () ==
nullptr) {
169 if (not fData_.
cget ()->empty ()) {
170 using namespace Execution;
171 lk.store (MakeSharedPtr<Thread::CleanupPtr> (Thread::CleanupPtr::eAbortBeforeWaiting,
172 Thread::New ([
this] () { RunnerLoop_ (); }, Thread::eAutoStart,
"Default-Interval-Timer"sv)));
176 fDataChanged_.Set ();
181IntervalTimer::Manager::DefaultRep::DefaultRep ()
189 fHiddenRep_->AddOneShot (timer, intervalTimer, when);
192void IntervalTimer::Manager::DefaultRep::AddRepeating (
TimerID timer,
const TimerCallback& intervalTimer,
193 const Time::Duration& repeatInterval,
const optional<Time::Duration>& hysteresis)
196 fHiddenRep_->AddRepeating (timer, intervalTimer, repeatInterval, hysteresis);
202 return fHiddenRep_->Remove (timer);
208 return fHiddenRep_->GetAllRegisteredTasks ();
216IntervalTimer::Manager::Activator::Activator ()
220 Require (Debug::AppearsDuringMainLifetime ());
221 Manager::sThe = Manager{MakeSharedPtr<IntervalTimer::Manager::DefaultRep> ()};
224IntervalTimer::Manager::Activator::~Activator ()
228 Require (Debug::AppearsDuringMainLifetime ());
238 RunImmediatelyFlag runImmediately,
const optional<Time::Duration>& hysteresis)
239 : fManager_{&manager}
241 , fTimer_{manager.AddRepeating (f, repeatInterval, hysteresis)}
243 if (runImmediately == RunImmediatelyFlag::eRunImmediately) {
244 IgnoreExceptionsExceptThreadAbortForCall (fFunction_ ());
#define RequireNotNull(p)
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
constexpr DurationSeconds kInfinity
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
a cross between Mapping<KEY, T> and Collection<T> and Set<T>
virtual bool Remove(TimerID timer) noexcept override
As Manager::Remove says: once it returns, the timer's callback is not running, and is not called agai...
Common::UniqueID< IntervalTimer > TimerID
Names a timer Manager::AddOneShot or AddRepeating added - for Remove. No two the same in a process,...
function< void()> TimerCallback
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
nonvirtual WritableReference rwget()
get a read-write smart pointer to the underlying Synchronized<> object, holding the full lock the who...
nonvirtual ReadableReference cget() const
get a read-only smart pointer to the underlying Synchronized<> object, holding the readlock the whole...
Duration is a chrono::duration<double> (=.
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Ptr New(const function< void()> &fun2CallOnce, const optional< Characters::String > &name, const optional< Configuration > &configuration)
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >
nonvirtual Characters::String ToString() const