Auto hotspot implementation

This commit is contained in:
Robin Davies
2024-09-11 00:06:52 -04:00
parent bbfd0a07fd
commit 448979e7fe
61 changed files with 5234 additions and 178 deletions
+273
View File
@@ -0,0 +1,273 @@
#include "DBusDispatcher.hpp"
#include "DBusLog.hpp"
#include <sdbus-c++/IConnection.h>
#include <poll.h>
#include <sys/eventfd.h>
#include "ss.hpp"
#include <chrono>
#include <cassert>
DBusDispatcher::DBusDispatcher(bool systemBus)
{
// SignalStop requires this to be true.
if (systemBus)
{
busConnection = sdbus::createSystemBusConnection();
}
else
{
busConnection = sdbus::createSessionBusConnection();
}
}
DBusDispatcher::~DBusDispatcher()
{
Stop();
busConnection = nullptr;
}
DBusDispatcher::PostHandle DBusDispatcher::Post(DBusDispatcher::PostCallback &&fn)
{
auto nextHandle = NextHandle();
{
std::lock_guard lock{postMutex};
this->postedEvents.push_back(CallbackEntry{std::move(fn), clock::time_point::min(), nextHandle});
}
WakeThread();
return nextHandle;
}
bool DBusDispatcher::CancelPost(DBusDispatcher::PostHandle handle)
{
{
std::lock_guard lock{postMutex};
for (auto i = postedEvents.begin(); i != postedEvents.end(); ++i)
{
if (i->handle == handle)
{
postedEvents.erase(i);
return true;
}
}
return false;
}
}
DBusDispatcher::PostHandle DBusDispatcher::PostDelayed(const clock::duration &delay, PostCallback &&fn)
{
PostHandle nextHandle = NextHandle();
{
std::lock_guard lock{postMutex};
this->postedEvents.emplace_back(
CallbackEntry{
std::move(fn),
clock::now() + delay,
nextHandle});
}
WakeThread();
return nextHandle;
}
void DBusDispatcher::Run()
{
this->eventFd = eventfd(0, 0);
this->serviceThread = std::thread(
[this]()
{ this->ThreadProc(); });
}
void DBusDispatcher::WakeThread()
{
uint64_t val = 1;
if (eventFd != -1)
{
std::ignore = write(eventFd, &val, sizeof(val));
}
}
void DBusDispatcher::ThreadProc()
{
try
{
while (true)
{
bool idle;
bool quitting;
while (true)
{
idle = true;
quitting = false;
while (busConnection->processPendingRequest())
{
idle = false;
}
{
// process one event.
PostCallback callback;
auto now = clock::now();
{
std::lock_guard lock{postMutex};
for (auto iter = postedEvents.begin(); iter != postedEvents.end(); ++iter)
{
if (now >= iter->time)
{
callback = std::move(iter->callback);
postedEvents.erase(iter);
idle = false;
break;
}
}
quitting = this->stopping; // transfer with the mutex held.
}
if (callback)
{
callback();
}
}
if (idle)
{
break;
}
}
if (idle && signalStopRequested)
{
signalStopRequested = false;
if (!signalStopExecuted) // only ever do this once.
{
signalStopExecuted = true;
std::atomic_thread_fence(std::memory_order::acquire);
signalStopCallback();
signalStopCallback = std::function<void(void)>();
this->stopping = true;
idle = false;
}
}
if (idle)
{
if (quitting)
{
if (postedEvents.size() == 0)
{
break;
}
}
sdbus::IConnection::PollData pollData = busConnection->getEventLoopPollData();
struct pollfd pollFds[2];
pollFds[0].fd = pollData.fd;
pollFds[0].events = pollData.events;
pollFds[0].revents = 0;
pollFds[1].fd = this->eventFd;
pollFds[1].events = POLLIN;
pollFds[1].revents = 0;
int pollTimeout = pollData.getPollTimeout();
int eventTimeout = GetEventTimeoutMs();
if (eventTimeout != -1 && eventTimeout < pollTimeout)
{
pollTimeout = eventTimeout;/*+-*/
}
if (pollTimeout > 250 || pollTimeout == -1)
{
pollTimeout = 250; // poll for quit every 250 ms.
}
if (pollTimeout != 0)
{
poll(pollFds, 2, pollTimeout);
if (pollFds[1].revents & POLLIN) // received a wakup event?
{
uint64_t counter;
std::ignore = read(pollFds[1].fd, &counter, sizeof(counter)); // reset the wakeup event.
}
}
}
}
}
catch (const std::exception &e)
{
std::string msg = SS("Abnormal termination. " << e.what());
LogError("DBusDispatcher", "ThreadProc", msg);
}
isFinished = true;
LogTrace("DBusDispatcher", "ThreadProc", "Service thread terminated.");
}
void DBusDispatcher::Wait()
{
try
{
if (!threadJoined)
{
threadJoined = true;
serviceThread.join();
}
}
catch (const std::exception &)
{
}
if (eventFd != -1)
{
close(eventFd);
eventFd = -1;
}
}
bool DBusDispatcher::IsFinished()
{
return isFinished;
}
void DBusDispatcher::Stop()
{
if (!closed)
{
closed = true;
this->stopping = true;
WakeThread();
Wait();
}
}
void DBusDispatcher::SignalStop(std::function<void(void)> &&callback)
{
this->signalStopCallback = std::move(callback);
std::atomic_thread_fence(::std::memory_order::release);
this->signalStopRequested = true;
}
int DBusDispatcher::GetEventTimeoutMs()
{
std::lock_guard lock{postMutex};
clock::time_point nextTime = clock::time_point::max();
for (const auto &event : this->postedEvents)
{
if (event.time == clock::time_point::min())
return 0;
if (event.time < nextTime)
{
nextTime = event.time;
}
}
if (nextTime == clock::time_point::max())
{
return -1;
}
auto clockDuration = nextTime - clock::now();
auto durationMs = std::chrono::duration_cast<std::chrono::milliseconds>(clockDuration);
auto ticks = durationMs.count();
if (ticks > 250)
return 250;
if (ticks < 0)
return 0;
return (int)ticks;
}
bool DBusDispatcher::IsStopping()
{
std::lock_guard lock{postMutex};
return stopping;
}