Files
core_misc/tjp/core/time-obsolete/SchedulerManual.cpp
Timothy Prepscius fa54be052a flatten 20260225
2026-02-25 12:39:24 -05:00

230 lines
4.0 KiB
C++

// TJP COPYRIGHT HEADER
//
// Timer.h
// algorithm
//
// Created by Timothy Prepscius on 1/19/18.
// Copyright © 2018 Timothy Prepscius. All rights reserved.
//
#include "SchedulerManual.hpp"
#include <core/log/Log.h>
namespace timprepscius {
namespace core {
namespace time {
SchedulerManual::SchedulerManual(const StrongPtr<TimeSource> &timeSource_) :
timeSource (timeSource_),
running(false),
stopped(false),
nextIndex(1)
{
}
SchedulerManual::~SchedulerManual()
{
debug_assert(!running);
}
SchedulerManual::EventImp::EventImp(
SchedulerManual *parent_,
Time period_,
bool repeat_,
std::function<void()> &&f_
) :
parent(parent_),
period(period_),
repeat(repeat_),
f(f_)
{
}
SchedulerEventPtr SchedulerManual::schedule_no_lock (const StrongPtr<EventImp> &eventImp, Time now)
{
debug_assert(mutex.locked_by_caller());
eventImp->at = { now + eventImp->period, nextIndex++ };
sLogDebug ("core::time::SchedulerManual", logVar(ptr_of(eventImp)) << logVar(now) << logVar(eventImp->at.time) << logVar(eventImp->period) << logVar(eventImp->repeat));
auto insertion = events.emplace(eventImp->at, weak(eventImp));
debug_assert(insertion.second);
debug_assert(eventImp->position == events.end());
eventImp->position = insertion.first;
changed.notify_all();
return eventImp;
}
SchedulerEventPtr SchedulerManual::schedule (const StrongPtr<EventImp> &eventImp, Time now)
{
auto l = lock_of(mutex);
return schedule_no_lock(eventImp, now);
}
SchedulerEventPtr SchedulerManual::schedule (Time period, bool repeat, std::function<void()> &&f)
{
auto eventImp = strong<EventImp>(
this,
period,
repeat,
std::move(f)
);
eventImp->position = events.end();
schedule(eventImp, timeSource->getTime());
return eventImp;
}
void SchedulerManual::EventImp::cancel ()
{
auto lock = lock_of(mutex);
parent->cancel(this);
}
void SchedulerManual::cancel(EventImp *event)
{
sLogDebug("core::time::scheduler", logVar(event));
if (event)
{
auto l = lock_of(mutex);
if (event->position != events.end())
events.erase(event->position);
event->position = events.end();
changed.notify_all();
}
}
Duration SchedulerManual::durationUntilNextEvent()
{
debug_assert(mutex.locked_by_caller());
if (events.empty())
return time::FarFuture;
return events.begin()->first.time - timeSource->getTime();
}
void SchedulerManual::update_has_lock ()
{
auto currentTime = EventTime { timeSource->getTime(), nextIndex };
while (!events.empty())
{
if (stopped)
return;
auto position = events.begin();
auto &event_ = position->second;
if (position->first < currentTime)
{
auto event = strong(event_);
debug_assert(mutex.locked_by_caller());
events.erase(position);
if (event)
{
event->position = events.end();
if (event->repeat)
{
schedule_no_lock(event, currentTime.time);
}
}
mutex.unlock();
if (event)
{
auto lock = lock_of(event->mutex);
try
{
event->f();
}
catch (Exception &e)
{
sLogError("core::time::SchedulerManual", "there was a problem houston " << e.what());
}
}
}
else
{
break;
}
mutex.lock();
}
};
void SchedulerManual::run()
{
running = true;
stopped = false;
mutex.lock();
while (!stopped)
{
auto duration = std::chrono::duration<double>(toReal(durationUntilNextEvent()));
auto now = std::chrono::system_clock::now();
auto then = now + duration;
changed.wait_until(mutex, then);
update_has_lock();
}
running = false;
stopped_.notify_all();
mutex.unlock();
}
void SchedulerManual::cycle()
{
mutex.lock();
running = true;
if (!events.empty())
{
update_has_lock();
}
running = false;
mutex.unlock();
}
void SchedulerManual::stop ()
{
auto lock = lock_of(mutex);
stopped = true;
changed.notify_all();
}
void SchedulerManual::clear ()
{
auto l = lock_of(mutex);
for (auto &[id, event_]: events)
{
if (auto event = strong(event_))
{
event->position = events.end();
}
}
events.clear();
}
} // namespace
} // namespace
} // namespace