forstio/source/kelgin/async.cpp

348 lines
6.9 KiB
C++
Raw Normal View History

#include "async.h"
#include <algorithm>
2020-08-28 16:59:25 +02:00
#include <cassert>
namespace gin {
namespace {
2020-08-09 02:04:48 +02:00
thread_local EventLoop *local_loop = nullptr;
EventLoop &currentEventLoop() {
EventLoop *loop = local_loop;
assert(loop);
return *loop;
}
} // namespace
ConveyorNode::ConveyorNode() {}
ConveyorStorage::ConveyorStorage(ConveyorStorage *c) : child_storage{c} {}
2021-10-02 14:34:49 +02:00
ConveyorStorage::~ConveyorStorage() {
if (parent) {
parent->unlinkChild();
2021-10-02 14:34:49 +02:00
}
}
void ConveyorStorage::unlinkChild() { child_storage = nullptr; }
void ConveyorEventStorage::setParent(ConveyorStorage *p) {
/*
* parent check isn't needed, but is used
* for the assert, because the storage should
* be armed if there was an element present
* and a valid parent
*/
if (/*!parent && */ p && !isArmed() && queued() > 0) {
assert(!parent);
2021-10-02 14:34:49 +02:00
if (p->space() > 0) {
armLater();
2021-10-02 14:34:49 +02:00
}
}
2021-04-25 15:44:29 +02:00
parent = p;
}
ConveyorEventStorage::ConveyorEventStorage(ConveyorStorage *c)
: ConveyorStorage{c} {}
2020-08-20 00:36:21 +02:00
ConveyorBase::ConveyorBase(Own<ConveyorNode> &&node_p,
ConveyorStorage *storage_p)
: node{std::move(node_p)}, storage{storage_p} {}
2020-08-18 19:59:59 +02:00
2020-08-25 20:52:32 +02:00
Error PropagateError::operator()(const Error &error) const {
2021-03-13 22:22:01 +01:00
return error.copyError();
}
2020-08-28 16:59:25 +02:00
Error PropagateError::operator()(Error &&error) { return std::move(error); }
2020-08-20 00:36:21 +02:00
Event::Event() : Event(currentEventLoop()) {}
2020-08-09 02:04:48 +02:00
Event::Event(EventLoop &loop) : loop{loop} {}
2020-08-09 02:03:09 +02:00
Event::~Event() { disarm(); }
2020-08-09 02:03:09 +02:00
void Event::armNext() {
assert(&loop == local_loop);
if (prev == nullptr) {
// Push the next_insert_point back by one
// and inserts itself before that
next = *loop.next_insert_point;
prev = loop.next_insert_point;
*prev = this;
if (next) {
next->prev = &next;
}
// Set the new insertion ptr location to next
loop.next_insert_point = &next;
// Pushes back the later insert point if it was pointing at the
// previous event
if (loop.later_insert_point == prev) {
loop.later_insert_point = &next;
}
// If tail points at the same location then
// we are at the end and have to update tail then.
// Technically should be possible by checking if
// next is a `nullptr`
if (loop.tail == prev) {
loop.tail = &next;
}
loop.setRunnable(true);
2020-08-09 02:04:48 +02:00
}
}
2020-08-09 02:03:09 +02:00
void Event::armLater() {
assert(&loop == local_loop);
if (prev == nullptr) {
next = *loop.later_insert_point;
prev = loop.later_insert_point;
*prev = this;
if (next) {
next->prev = &next;
}
loop.later_insert_point = &next;
if (loop.tail == prev) {
loop.tail = &next;
}
loop.setRunnable(true);
2020-08-09 02:04:48 +02:00
}
}
2020-08-09 02:03:09 +02:00
void Event::armLast() {
assert(&loop == local_loop);
2020-08-09 02:04:48 +02:00
if (prev == nullptr) {
next = *loop.later_insert_point;
prev = loop.later_insert_point;
*prev = this;
if (next) {
next->prev = &next;
}
2020-08-09 02:04:48 +02:00
if (loop.tail == prev) {
loop.tail = &next;
}
loop.setRunnable(true);
2020-08-09 02:04:48 +02:00
}
}
void Event::disarm() {
2020-08-20 00:36:21 +02:00
if (prev != nullptr) {
if (loop.tail == &next) {
loop.tail = prev;
}
if (loop.next_insert_point == &next) {
loop.next_insert_point = prev;
}
*prev = next;
if (next) {
next->prev = prev;
}
prev = nullptr;
next = nullptr;
2020-08-09 02:04:48 +02:00
}
}
2020-08-20 00:36:21 +02:00
bool Event::isArmed() const { return prev != nullptr; }
2021-05-01 15:26:45 +02:00
SinkConveyor::SinkConveyor() : node{nullptr} {}
2020-10-29 02:36:01 +01:00
SinkConveyor::SinkConveyor(Own<ConveyorNode> &&node_p)
: node{std::move(node_p)} {}
2020-10-29 02:35:43 +01:00
2020-08-09 02:03:09 +02:00
void EventLoop::setRunnable(bool runnable) { is_runnable = runnable; }
2020-08-28 16:59:25 +02:00
EventLoop::EventLoop() {}
2020-08-06 02:19:05 +02:00
2020-08-28 16:59:25 +02:00
EventLoop::EventLoop(Own<EventPort> &&event_port)
: event_port{std::move(event_port)} {}
2020-08-25 19:51:45 +02:00
2021-04-25 15:44:29 +02:00
EventLoop::~EventLoop() { assert(local_loop != this); }
2020-08-06 02:19:05 +02:00
2020-08-09 02:03:09 +02:00
void EventLoop::enterScope() {
assert(!local_loop);
local_loop = this;
2020-08-06 02:19:05 +02:00
}
2020-08-09 02:03:09 +02:00
void EventLoop::leaveScope() {
assert(local_loop == this);
local_loop = nullptr;
}
bool EventLoop::turnLoop() {
2020-11-03 13:27:00 +01:00
size_t turn_step = 0;
2020-11-04 02:37:37 +01:00
while (head && turn_step < 65536) {
2020-11-03 13:27:00 +01:00
if (!turn()) {
return false;
}
++turn_step;
}
2020-11-04 02:37:37 +01:00
return true;
2020-11-03 13:27:00 +01:00
}
2020-08-20 00:52:51 +02:00
bool EventLoop::turn() {
Event *event = head;
2020-08-20 00:50:36 +02:00
2020-08-20 00:52:51 +02:00
if (!event) {
2020-08-20 00:50:36 +02:00
return false;
}
head = event->next;
2020-08-20 00:52:51 +02:00
if (head) {
2020-08-20 00:50:36 +02:00
head->prev = &head;
}
next_insert_point = &head;
2020-08-20 00:52:51 +02:00
if (later_insert_point == &event->next) {
2020-08-20 00:50:36 +02:00
later_insert_point = &head;
}
2020-08-20 00:52:51 +02:00
if (tail == &event->next) {
2020-08-20 00:50:36 +02:00
tail = &head;
}
event->next = nullptr;
event->prev = nullptr;
next_insert_point = &head;
2020-08-25 19:51:45 +02:00
event->fire();
2020-08-20 00:50:36 +02:00
return true;
}
2020-08-09 02:04:48 +02:00
bool EventLoop::wait(const std::chrono::steady_clock::duration &duration) {
2020-09-02 16:50:42 +02:00
if (event_port) {
2020-10-11 22:21:06 +02:00
event_port->wait(duration);
2020-09-02 16:50:42 +02:00
}
2020-11-03 13:27:00 +01:00
return turnLoop();
}
2020-08-09 02:04:48 +02:00
bool EventLoop::wait(const std::chrono::steady_clock::time_point &time_point) {
2020-09-02 16:50:42 +02:00
if (event_port) {
2020-10-11 22:21:06 +02:00
event_port->wait(time_point);
2020-09-02 16:50:42 +02:00
}
2020-11-03 13:27:00 +01:00
return turnLoop();
}
2020-09-02 16:50:42 +02:00
bool EventLoop::wait() {
if (event_port) {
event_port->wait();
}
2020-11-03 13:27:00 +01:00
return turnLoop();
2020-09-02 16:50:42 +02:00
}
2020-08-06 02:19:05 +02:00
2020-08-20 00:50:36 +02:00
bool EventLoop::poll() {
if (event_port) {
event_port->poll();
}
2020-11-04 02:37:37 +01:00
2020-11-03 13:27:00 +01:00
return turnLoop();
2020-08-20 00:50:36 +02:00
}
2020-08-09 02:03:09 +02:00
2020-08-28 16:59:25 +02:00
EventPort *EventLoop::eventPort() { return event_port.get(); }
2020-08-25 19:51:45 +02:00
2020-10-29 02:35:43 +01:00
ConveyorSinks &EventLoop::daemon() {
2020-08-28 16:59:25 +02:00
if (!daemon_sink) {
2020-10-29 02:35:43 +01:00
daemon_sink = heap<ConveyorSinks>();
}
return *daemon_sink;
}
2020-08-09 02:04:48 +02:00
WaitScope::WaitScope(EventLoop &loop) : loop{loop} { loop.enterScope(); }
2020-08-09 02:03:09 +02:00
WaitScope::~WaitScope() { loop.leaveScope(); }
void WaitScope::wait() { loop.wait(); }
2020-08-09 02:04:48 +02:00
void WaitScope::wait(const std::chrono::steady_clock::duration &duration) {
loop.wait(duration);
}
2020-08-09 02:04:48 +02:00
void WaitScope::wait(const std::chrono::steady_clock::time_point &time_point) {
loop.wait(time_point);
}
2020-08-09 02:03:09 +02:00
void WaitScope::poll() { loop.poll(); }
ImmediateConveyorNodeBase::ImmediateConveyorNodeBase()
: ConveyorEventStorage{nullptr} {}
2021-10-02 14:34:49 +02:00
MergeConveyorNodeBase::MergeConveyorNodeBase()
: ConveyorEventStorage{nullptr} {}
2020-10-29 02:35:43 +01:00
void ConveyorSinks::destroySinkConveyorNode(ConveyorNode &node) {
2020-08-28 16:59:25 +02:00
if (!isArmed()) {
armLast();
}
delete_nodes.push(&node);
}
2020-10-29 02:35:43 +01:00
void ConveyorSinks::fail(Error &&error) {
/// @todo call error_handler
}
ConveyorSinks::ConveyorSinks(EventLoop &event_loop) : Event{event_loop} {}
2020-10-29 02:35:43 +01:00
void ConveyorSinks::add(Conveyor<void> &&sink) {
auto nas = Conveyor<void>::fromConveyor(std::move(sink));
2021-03-17 11:24:18 +01:00
Own<SinkConveyorNode> sink_node = nullptr;
try {
sink_node =
heap<SinkConveyorNode>(nas.second, std::move(nas.first), *this);
} catch (std::bad_alloc &) {
2021-03-17 11:24:18 +01:00
return;
}
2020-08-28 16:59:25 +02:00
if (nas.second) {
nas.second->setParent(sink_node.get());
}
2021-03-17 11:24:18 +01:00
sink_nodes.emplace_back(std::move(sink_node));
}
2020-10-29 02:35:43 +01:00
void ConveyorSinks::fire() {
2020-08-28 16:59:25 +02:00
while (!delete_nodes.empty()) {
ConveyorNode *node = delete_nodes.front();
/*auto erased = */ std::remove_if(sink_nodes.begin(), sink_nodes.end(),
[node](Own<ConveyorNode> &element) {
return node == element.get();
});
delete_nodes.pop();
}
}
2020-08-20 00:36:21 +02:00
ConvertConveyorNodeBase::ConvertConveyorNodeBase(Own<ConveyorNode> &&dep)
: child{std::move(dep)} {}
2020-08-20 00:36:21 +02:00
void ConvertConveyorNodeBase::getResult(ErrorOrValue &err_or_val) {
getImpl(err_or_val);
}
2020-08-23 15:47:14 +02:00
void AttachConveyorNodeBase::getResult(ErrorOrValue &err_or_val) noexcept {
2020-08-24 12:47:18 +02:00
if (child) {
2020-08-23 15:47:14 +02:00
child->getResult(err_or_val);
}
}
2020-08-28 16:59:25 +02:00
void detachConveyor(Conveyor<void> &&conveyor) {
EventLoop &loop = currentEventLoop();
2020-10-29 02:35:43 +01:00
ConveyorSinks &sink = loop.daemon();
sink.add(std::move(conveyor));
}
2020-08-28 21:08:04 +02:00
} // namespace gin