Commit 9483a46b authored by Xavier Thompson's avatar Xavier Thompson

Enable opt-in deferred reclamation of forks

parent d279c180
......@@ -63,15 +63,19 @@ namespace typon
{
return span->_coroutine;
}
auto rank = coroutine.promise()._rank;
if (auto & exception = coroutine.promise()._exception)
{
span->set_exception(exception, coroutine.promise()._rank);
span->set_exception(exception, rank);
}
if (!(rank & 1))
{
auto & ref = coroutine.promise()._node._ref;
if (!ref.exchange(false, std::memory_order_acq_rel))
{
coroutine.destroy();
}
}
u64 n = span->_n.fetch_sub(1, std::memory_order_acq_rel);
if (n == 1)
{
......@@ -85,25 +89,45 @@ namespace typon
}
};
struct awaitable
struct awaitable : std::suspend_always
{
std::coroutine_handle<promise_type> _coroutine;
awaitable(std::coroutine_handle<promise_type> coroutine) noexcept
: _coroutine(coroutine)
{}
template <typename Promise>
auto await_suspend(std::coroutine_handle<Promise> continuation) noexcept
{
Span * span = &(continuation.promise()._span);
_coroutine.promise()._span = span;
_coroutine.promise()._rank = (span->_thefts << 1);
std::coroutine_handle<> on_stack_handle = _coroutine;
Scheduler::push(span);
return on_stack_handle;
}
bool await_ready() noexcept
auto await_resume()
{
auto thefts = _coroutine.promise()._span->_thefts;
auto rank = _coroutine.promise()._rank;
return Forked<T>(_coroutine, (thefts == (rank >> 1)), true);
}
};
auto operator co_await() &&
{
return false;
return awaitable { {}, _coroutine };
}
struct noloop_awaitable : std::suspend_always
{
std::coroutine_handle<promise_type> _coroutine;
template <typename Promise>
auto await_suspend(std::coroutine_handle<Promise> continuation) noexcept
{
Span * span = &(continuation.promise()._span);
_coroutine.promise()._span = span;
_coroutine.promise()._rank = span->_thefts;
_coroutine.promise()._rank = (span->_thefts << 1) + 1;
std::coroutine_handle<> on_stack_handle = _coroutine;
Scheduler::push(span);
......@@ -114,13 +138,18 @@ namespace typon
{
auto thefts = _coroutine.promise()._span->_thefts;
auto rank = _coroutine.promise()._rank;
return Forked<T>(_coroutine, (thefts == rank));
bool ready = thefts == (rank >> 1);
if (!ready)
{
_coroutine.promise()._span->_children.push_back(_coroutine);
}
return Forked<T>(_coroutine, ready, false);
}
};
auto operator co_await() &&
auto noloop() &&
{
return awaitable { _coroutine };
return noloop_awaitable { {}, _coroutine };
}
};
......
......@@ -111,7 +111,7 @@ namespace typon
Result<T> * _result = nullptr;
template <typename Promise>
Forked(std::coroutine_handle<Promise> coroutine, bool ready)
Forked(std::coroutine_handle<Promise> coroutine, bool ready, bool owning)
{
if (ready)
{
......@@ -120,7 +120,7 @@ namespace typon
}
else
{
this->_node = &(coroutine.promise()._node);
this->_node = owning ? &(coroutine.promise()._node) : nullptr;
_result = &(coroutine.promise());
}
}
......@@ -197,11 +197,11 @@ namespace typon
ForkNode * _node;
template <typename Promise>
Forked(std::coroutine_handle<Promise> coroutine, bool ready)
Forked(std::coroutine_handle<Promise> coroutine, bool ready, bool owning)
{
_ready = ready;
_result = &(coroutine.promise());
_node = &(coroutine.promise()._node);
_node = (owning | ready) ? &(coroutine.promise()._node) : nullptr;
if (ready)
{
if (auto & exception = coroutine.promise()._exception)
......
......@@ -7,6 +7,7 @@
#include <cstdint>
#include <exception>
#include <limits>
#include <vector>
#include <typon/defer.hpp>
#include <typon/theft_point.hpp>
......@@ -31,6 +32,8 @@ namespace typon
std::atomic<Error *> _error { nullptr };
std::vector<std::coroutine_handle<>> _children;
std::atomic<u64> _n = UMAX;
Span(std::coroutine_handle<> coroutine) noexcept
......@@ -43,6 +46,16 @@ namespace typon
{
delete error;
}
clear_children();
}
void clear_children() noexcept
{
for (auto & child : _children)
{
child.destroy();
}
_children.clear();
}
void check_exception()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment