polybar/src/components/taskqueue.cpp

110 lines
3.1 KiB
C++

#include "components/taskqueue.hpp"
#include <algorithm>
POLYBAR_NS
taskqueue::make_type taskqueue::make() {
return std::make_unique<taskqueue>();
}
taskqueue::taskqueue() {
m_thread = std::thread([&] {
while (m_active) {
std::unique_lock<std::mutex> guard(m_lock);
if (m_deferred.empty()) {
m_hold.wait(guard);
} else {
auto now = deferred::clock::now();
auto wait = m_deferred.front()->now + m_deferred.front()->wait;
for (auto&& task : m_deferred) {
auto when = task->now + task->wait;
if (when < wait) {
wait = move(when);
}
}
if (wait > now) {
m_hold.wait_for(guard, wait - now);
}
}
if (!m_deferred.empty()) {
guard.unlock();
tick();
}
}
});
}
taskqueue::~taskqueue() {
if (m_active && m_thread.joinable()) {
m_active = false;
m_hold.notify_all();
m_thread.join();
}
}
void taskqueue::defer(
string id, deferred::duration ms, deferred::callback fn, deferred::duration offset, size_t count) {
std::unique_lock<std::mutex> guard(m_lock);
deferred::timepoint now{chrono::time_point_cast<deferred::duration>(deferred::clock::now() + move(offset))};
m_deferred.emplace_back(make_unique<deferred>(move(id), move(now), move(ms), move(fn), move(count)));
guard.unlock();
m_hold.notify_one();
}
void taskqueue::defer_unique(
string id, deferred::duration ms, deferred::callback fn, deferred::duration offset, size_t count) {
purge(id);
std::unique_lock<std::mutex> guard(m_lock);
deferred::timepoint now{chrono::time_point_cast<deferred::duration>(deferred::clock::now() + move(offset))};
m_deferred.emplace_back(make_unique<deferred>(move(id), move(now), move(ms), move(fn), move(count)));
guard.unlock();
m_hold.notify_one();
}
void taskqueue::tick() {
if (!m_lock.try_lock()) {
return;
}
std::unique_lock<std::mutex> guard(m_lock, std::adopt_lock);
auto now = chrono::time_point_cast<deferred::duration>(deferred::clock::now());
vector<pair<deferred::callback, size_t>> cbs;
for (auto it = m_deferred.rbegin(); it != m_deferred.rend(); ++it) {
auto& task = *it;
if (task->now + task->wait > now) {
continue;
} else if (task->count--) {
cbs.emplace_back(make_pair(task->func, task->count));
task->now = now;
} else {
m_deferred.erase(std::remove_if(m_deferred.begin(), m_deferred.end(),
[&](const unique_ptr<deferred>& d) { return d == task; }),
m_deferred.end());
}
}
guard.unlock();
for (auto&& p : cbs) {
p.first(p.second);
}
}
bool taskqueue::purge(const string& id) {
std::lock_guard<std::mutex> guard(m_lock);
return m_deferred.erase(std::remove_if(m_deferred.begin(), m_deferred.end(),
[id](const unique_ptr<deferred>& d) { return d->id == id; }),
m_deferred.end()) == m_deferred.end();
}
bool taskqueue::exist(const string& id) {
std::lock_guard<std::mutex> guard(m_lock);
for (const auto& task : m_deferred) {
if (task->id == id) {
return true;
}
}
return false;
}
POLYBAR_NS_END