2020-08-04 01:19:35 +02:00
|
|
|
#include "async.h"
|
|
|
|
|
2020-08-26 15:30:48 +02:00
|
|
|
#include <algorithm>
|
2020-08-28 16:59:25 +02:00
|
|
|
#include <cassert>
|
2020-08-26 15:30:48 +02:00
|
|
|
|
|
|
|
#include <iostream>
|
2020-08-04 01:19:35 +02:00
|
|
|
|
|
|
|
namespace gin {
|
|
|
|
namespace {
|
2020-08-09 02:04:48 +02:00
|
|
|
thread_local EventLoop *local_loop = nullptr;
|
2020-08-16 20:08:11 +02:00
|
|
|
|
|
|
|
EventLoop ¤tEventLoop() {
|
|
|
|
EventLoop *loop = local_loop;
|
|
|
|
assert(loop);
|
|
|
|
return *loop;
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2020-08-20 00:36:21 +02:00
|
|
|
ConveyorNode::ConveyorNode() : child{nullptr} {}
|
2020-08-16 20:08:11 +02:00
|
|
|
|
2020-08-20 00:36:21 +02:00
|
|
|
ConveyorNode::ConveyorNode(Own<ConveyorNode> &&node) : child{std::move(node)} {}
|
2020-08-16 20:08:11 +02:00
|
|
|
|
2020-08-20 00:36:21 +02:00
|
|
|
void ConveyorStorage::setParent(ConveyorStorage *p) { parent = p; }
|
2020-08-16 20:08:11 +02:00
|
|
|
|
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 {
|
2020-08-16 20:08:11 +02:00
|
|
|
Error err{error};
|
2020-08-25 20:52:32 +02:00
|
|
|
return err;
|
2020-08-16 20:08:11 +02:00
|
|
|
}
|
|
|
|
|
2020-08-28 16:59:25 +02:00
|
|
|
Error PropagateError::operator()(Error &&error) { return std::move(error); }
|
2020-08-04 01:19:35 +02:00
|
|
|
|
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-04 01:19:35 +02:00
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
Event::~Event() { disarm(); }
|
2020-08-04 01:19:35 +02:00
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
void Event::armNext() {
|
2020-08-09 02:09:49 +02:00
|
|
|
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-04 01:19:35 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
void Event::armLater() {
|
2020-08-09 02:09:49 +02:00
|
|
|
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-04 01:19:35 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
void Event::armLast() {
|
2020-08-09 02:09:49 +02:00
|
|
|
assert(&loop == local_loop);
|
2020-08-09 02:04:48 +02:00
|
|
|
|
2020-08-09 02:09:49 +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
|
|
|
|
2020-08-09 02:09:49 +02:00
|
|
|
if (loop.tail == prev) {
|
|
|
|
loop.tail = &next;
|
|
|
|
}
|
2020-08-04 01:19:35 +02:00
|
|
|
|
2020-08-09 02:09:49 +02:00
|
|
|
loop.setRunnable(true);
|
2020-08-09 02:04:48 +02:00
|
|
|
}
|
2020-08-09 02:09:49 +02:00
|
|
|
}
|
2020-08-04 01:19:35 +02:00
|
|
|
|
2020-08-09 02:09:49 +02:00
|
|
|
void Event::disarm() {
|
2020-08-20 00:36:21 +02:00
|
|
|
if (prev != nullptr) {
|
2020-08-09 02:09:49 +02:00
|
|
|
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-04 01:19:35 +02:00
|
|
|
}
|
|
|
|
|
2020-08-20 00:36:21 +02:00
|
|
|
bool Event::isArmed() const { return prev != nullptr; }
|
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
void EventLoop::setRunnable(bool runnable) { is_runnable = runnable; }
|
2020-08-04 01:19:35 +02:00
|
|
|
|
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
|
|
|
|
2020-08-09 02:03:09 +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() {
|
2020-08-09 02:09:49 +02:00
|
|
|
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() {
|
2020-08-09 02:09:49 +02:00
|
|
|
assert(local_loop == this);
|
|
|
|
local_loop = nullptr;
|
2020-08-04 01:19:35 +02: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-08-09 02:09:49 +02:00
|
|
|
return false;
|
2020-08-04 01:19:35 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 02:04:48 +02:00
|
|
|
bool EventLoop::wait(const std::chrono::steady_clock::time_point &time_point) {
|
2020-08-09 02:09:49 +02:00
|
|
|
return false;
|
2020-08-04 01:19:35 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 02:03:09 +02:00
|
|
|
bool EventLoop::wait() { return false; }
|
2020-08-06 02:19:05 +02:00
|
|
|
|
2020-08-20 00:50:36 +02:00
|
|
|
bool EventLoop::poll() {
|
2020-08-20 00:52:51 +02:00
|
|
|
while (head) {
|
|
|
|
if (!turn()) {
|
2020-08-20 00:50:36 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-08-20 00:52:51 +02:00
|
|
|
}
|
2020-08-20 00:50:36 +02:00
|
|
|
return true;
|
|
|
|
}
|
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-08-28 16:59:25 +02:00
|
|
|
ConveyorSink &EventLoop::daemon() {
|
|
|
|
if (!daemon_sink) {
|
2020-08-26 16:39:59 +02:00
|
|
|
daemon_sink = heap<ConveyorSink>();
|
|
|
|
}
|
|
|
|
return *daemon_sink;
|
|
|
|
}
|
|
|
|
|
2020-08-09 02:04:48 +02:00
|
|
|
WaitScope::WaitScope(EventLoop &loop) : loop{loop} { loop.enterScope(); }
|
2020-08-04 01:19:35 +02:00
|
|
|
|
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) {
|
2020-08-09 02:09:49 +02:00
|
|
|
loop.wait(duration);
|
2020-08-04 01:19:35 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 02:04:48 +02:00
|
|
|
void WaitScope::wait(const std::chrono::steady_clock::time_point &time_point) {
|
2020-08-09 02:09:49 +02:00
|
|
|
loop.wait(time_point);
|
2020-08-04 01:19:35 +02:00
|
|
|
}
|
2020-08-09 02:03:09 +02:00
|
|
|
|
|
|
|
void WaitScope::poll() { loop.poll(); }
|
2020-08-16 20:08:11 +02:00
|
|
|
|
2020-08-28 16:59:25 +02:00
|
|
|
void ConveyorSink::destroySinkConveyorNode(ConveyorNode &node) {
|
|
|
|
if (!isArmed()) {
|
2020-08-26 15:30:48 +02:00
|
|
|
armLast();
|
|
|
|
}
|
|
|
|
|
2020-08-26 16:39:59 +02:00
|
|
|
delete_nodes.push(&node);
|
|
|
|
}
|
|
|
|
|
2020-08-28 16:59:25 +02:00
|
|
|
void ConveyorSink::fail(Error &&error) {
|
2020-08-26 16:39:59 +02:00
|
|
|
/// @todo call error_handler
|
|
|
|
}
|
|
|
|
|
2020-08-28 16:59:25 +02:00
|
|
|
void ConveyorSink::add(Conveyor<void> &&sink) {
|
2020-08-26 16:39:59 +02:00
|
|
|
auto nas = Conveyor<void>::fromConveyor(std::move(sink));
|
2020-08-28 16:59:25 +02:00
|
|
|
Own<SinkConveyorNode> sink_node =
|
|
|
|
heap<SinkConveyorNode>(std::move(nas.first), *this);
|
|
|
|
if (nas.second) {
|
2020-08-26 16:39:59 +02:00
|
|
|
nas.second->setParent(sink_node.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 16:59:25 +02:00
|
|
|
void ConveyorSink::fire() {
|
|
|
|
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();
|
|
|
|
});
|
2020-08-26 16:39:59 +02:00
|
|
|
delete_nodes.pop();
|
2020-08-26 15:30:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-20 00:36:21 +02:00
|
|
|
ConvertConveyorNodeBase::ConvertConveyorNodeBase(Own<ConveyorNode> &&dep)
|
|
|
|
: ConveyorNode{std::move(dep)} {}
|
|
|
|
|
|
|
|
void ConvertConveyorNodeBase::getResult(ErrorOrValue &err_or_val) {
|
|
|
|
getImpl(err_or_val);
|
|
|
|
}
|
2020-08-23 15:47:14 +02:00
|
|
|
|
2020-08-24 12:47:18 +02:00
|
|
|
void AttachConveyorNodeBase::getResult(ErrorOrValue &err_or_val) {
|
|
|
|
if (child) {
|
2020-08-23 15:47:14 +02:00
|
|
|
child->getResult(err_or_val);
|
|
|
|
}
|
|
|
|
}
|
2020-08-26 16:39:59 +02:00
|
|
|
|
2020-08-28 16:59:25 +02:00
|
|
|
void detachConveyor(Conveyor<void> &&conveyor) {
|
|
|
|
EventLoop &loop = currentEventLoop();
|
|
|
|
ConveyorSink &sink = loop.daemon();
|
2020-08-26 16:39:59 +02:00
|
|
|
sink.add(std::move(conveyor));
|
|
|
|
}
|
2020-08-28 21:08:04 +02:00
|
|
|
} // namespace gin
|