orotool/src/evloop.cpp

160 lines
3.9 KiB
C++
Raw Normal View History

#include "evloop.hpp"
#include "html_fetch_task.hpp"
#include <ev++.h>
#include <thread>
#include <vector>
#include <iostream>
#include <algorithm>
#include <random>
#include <functional>
#include <string>
#include <future>
#include <cassert>
namespace duck {
namespace {
class KeepaliveTimer : public ev::timer {
public:
KeepaliveTimer (ev::loop_ref& loop, RunningPool::subpool_type*) {
this->set(loop);
this->set<KeepaliveTimer, &KeepaliveTimer::on_timer_ev>(this);
ev::timer::start(5.0, 5.0);
}
void on_timer_ev() {
}
};
} //unnamed namespace
void lock_mutex_libev (struct ev_loop* ev) noexcept {
EvThreadPool* const obj = static_cast<EvThreadPool*>(ev_userdata(ev));
obj->lock_mutex_libev();
}
void unlock_mutex_libev (struct ev_loop* ev) noexcept {
EvThreadPool* const obj = static_cast<EvThreadPool*>(ev_userdata(ev));
obj->unlock_mutex_libev();
}
RunningPool::RunningPool (ev::default_loop* loop, RunningPool::subpool_type* sub, std::mutex* mtx, ev::async* async) :
m_loop(loop),
m_subflow(sub),
m_ev_mutex(mtx),
m_async(async)
{
assert(m_ev_mutex);
std::cout << "Created RunningPool(" << m_loop << ", " << m_subflow << ")\n";
}
EvThreadPool::EvThreadPool() :
m_loop(ev::AUTO)
#if THREADPOOL == THREADPOOL_ROAR11
, m_pool(std::max(2U, std::thread::hardware_concurrency()) - 1)
#endif
{
assert(nullptr == ev_userdata(m_loop));
m_async.set(m_loop);
m_async.set<EvThreadPool, &EvThreadPool::do_nothing>(this);
m_async.start();
ev_set_userdata(m_loop, this);
ev_set_loop_release_cb(m_loop, &duck::unlock_mutex_libev, &duck::lock_mutex_libev);
}
RunningPool EvThreadPool::start() {
#if THREADPOOL == THREADPOOL_TASKFLOW
std::promise<RunningPool::subpool_type*> subflow_promise;
m_taskflow.emplace([this,&subflow_promise](RunningPool::subpool_type& sub){
subflow_promise.set_value(&sub);
//KeepaliveTimer keepalive{m_loop, &sub};
m_ev_mutex.lock();
m_loop.run(0);
m_ev_mutex.unlock();
});
m_executor.run(m_taskflow);
std::future<RunningPool::subpool_type*> future_subflow = subflow_promise.get_future();
return RunningPool{&m_loop, future_subflow.get(), &m_ev_mutex, &m_async};
#else
std::cout << "Submitting run job to thread pool\n";
m_pool.submit([this]() {
//KeepaliveTimer keepalive{m_loop, &m_pool};
m_ev_mutex.lock();
m_loop.run(0);
m_ev_mutex.unlock();
});
std::cout << "Work submitted, returing RunningPool object\n";
return RunningPool{&m_loop, &m_pool, &m_ev_mutex, &m_async};
#endif
}
void EvThreadPool::join() {
#if THREADPOOL == THREADPOOL_TASKFLOW
m_executor.wait_for_all();
#else
m_pool.join();
#endif
std::cout << "all tasks completed\n";
}
ev::loop_ref& EvThreadPool::loop() {
return m_loop;
}
void EvThreadPool::do_nothing() {
}
void EvThreadPool::lock_mutex_libev() noexcept {
try {
m_ev_mutex.lock();
}
catch (const std::system_error&) {
assert(false);
std::cerr << "Locking mutex failed, this will probably result in bad program behaviour\n";
}
}
void EvThreadPool::unlock_mutex_libev() noexcept {
m_ev_mutex.unlock();
}
EvTimerTask::EvTimerTask (double delay, ev::loop_ref& loop, RunningPool::subpool_type* subflow, std::mutex* ev_mtx, ev::async* async) :
m_subpool(subflow),
m_ev_mutex(ev_mtx),
m_loop(&loop),
m_async(async)
{
assert(ev_mtx);
this->set(loop);
this->set<EvTimerTask, &EvTimerTask::on_timer_ev>(this);
set_timer(delay);
}
void EvTimerTask::set_timer (double delay) {
std::unique_lock<std::mutex> lock(*m_ev_mutex);
ev_now_update(*m_loop);
ev::timer::start(delay, 0.0);
m_async->send();
}
RunningPool::subpool_type& EvTimerTask::subflow() {
return *m_subpool;
}
void EvTimerTask::on_timer_ev() {
std::cout << "EvTimerTask::on_timer_ev()\n";
ev::timer::stop();
this->on_timer();
}
void test() {
EvThreadPool worker;
auto running_pool = worker.start();
std::cout << "Instantiating html timer\n";
auto fetcher = running_pool.make_timer<HtmlFetchTimer>("test_url_lol");
worker.join();
}
} //namespace duck