0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 07:23:53 +01:00

ircd::ctx: Reorg continuation for core wakeup conditions.

This commit is contained in:
Jason Volk 2018-12-07 12:05:27 -08:00
parent 9eabd745f5
commit 4a2ad1c186
2 changed files with 81 additions and 32 deletions

View file

@ -18,10 +18,12 @@
namespace ircd::ctx
{
using yield_context = boost::asio::yield_context;
struct continuation;
struct to_asio;
using yield_context = boost::asio::yield_context;
using interruptor = std::function<void (ctx *const &) noexcept>;
using predicate = std::function<bool ()>;
}
namespace ircd
@ -43,17 +45,37 @@ namespace ircd
/// executes before control continues beyond the yield_context call itself and
/// ties this sequence together neatly.
///
/// The instance contains references to some callables which must remain valid.
///
/// - predicate (NOT YET USED)
/// A wakeup condition. This should be a simple boolean function which
/// tests whether the context should be woken up. The continuation references
/// this to convey the condition to a scheduler which may test many predicates
/// while contexts are asleep and then determine a schedule. This is an
/// alternative to waking up contexts first to test their predicates.
///
/// - interruptor
/// An interruption action. This is called when a context cannot wakeup on its
/// own after receiving an interruption without help from this action. Common
/// use for this is with yields to asio.
///
struct ircd::ctx::continuation
{
static const predicate true_predicate;
static const predicate false_predicate;
static const interruptor noop_interruptor;
ctx *self;
const predicate &pred;
const interruptor &intr;
operator const boost::asio::yield_context &() const;
operator boost::asio::yield_context &();
virtual void interrupted(ctx *const &) noexcept;
continuation(const predicate & = true_predicate,
const interruptor & = noop_interruptor);
continuation();
virtual ~continuation() noexcept;
~continuation() noexcept;
};
/// This type of continuation should be used when yielding a context to a
@ -68,12 +90,6 @@ struct ircd::ctx::continuation
struct ircd::ctx::to_asio
:ircd::ctx::continuation
{
using function = std::function<void (ctx *const &)>;
function handler;
void interrupted(ctx *const &) noexcept final override;
to_asio(function handler);
to_asio(const interruptor &);
to_asio() = default;
};

View file

@ -163,14 +163,27 @@ ircd::ctx::ctx::wait()
if(--notes > 0)
return false;
const auto interruption{[this]
// An interrupt invokes this closure to force the alarm to return.
const interruptor interruptor{[this]
(ctx *const &interruptor) noexcept
{
wake();
}};
// This is currently a dummy predicate; this is where we can take the
// user's real wakeup condition (i.e from a ctx::dock) and use it with
// an internal scheduler.
const predicate &predicate{[this]
{
return notes > 0;
}};
// The register switch itself occurs inside the alarm.async_wait() call.
// The construction of the arguments to the call on this stack comprise
// our final control before the context switch. The destruction of the
// arguments comprise the initial control after the context switch.
boost::system::error_code ec;
alarm.async_wait(boost::asio::yield_context{to_asio{interruption}}[ec]);
alarm.async_wait(yield_context{continuation{predicate, interruptor}}[ec]);
assert(ec == errc::operation_canceled || ec == errc::success);
assert(current == this);
@ -363,7 +376,7 @@ ircd::ctx::terminate(ctx &ctx)
return;
if(likely(&ctx != current && ctx.cont != nullptr))
ctx.cont->interrupted(current);
ctx.cont->intr(current);
}
/// Marks `ctx` for interruption and enqueues it for resumption to receive the
@ -386,7 +399,7 @@ ircd::ctx::interrupt(ctx &ctx)
return;
if(likely(&ctx != current && ctx.cont != nullptr))
ctx.cont->interrupted(current);
ctx.cont->intr(current);
}
/// Marks `ctx` for whether to allow or suppress interruption. Suppression
@ -800,15 +813,45 @@ noexcept
// ctx/continuation.h
//
decltype(ircd::ctx::continuation::true_predicate)
ircd::ctx::continuation::true_predicate{[]
() -> bool
{
return true;
}};
decltype(ircd::ctx::continuation::false_predicate)
ircd::ctx::continuation::false_predicate{[]
() -> bool
{
return false;
}};
decltype(ircd::ctx::continuation::noop_interruptor)
ircd::ctx::continuation::noop_interruptor{[]
(ctx *const &interruptor) -> void
{
return;
}};
//
// continuation
//
ircd::ctx::continuation::continuation()
ircd::ctx::continuation::continuation(const predicate &pred,
const interruptor &intr)
:self
{
ircd::ctx::current
}
,pred
{
pred
}
,intr
{
intr
}
{
mark(prof::event::CUR_YIELD);
@ -843,12 +886,6 @@ noexcept
// pointer while the context is awake.
}
void
ircd::ctx::continuation::interrupted(ctx *const &interruptor)
noexcept
{
}
ircd::ctx::continuation::operator boost::asio::yield_context &()
{
return *self->yc;
@ -864,16 +901,12 @@ const
// to_asio
//
ircd::ctx::to_asio::to_asio(function handler)
:handler{std::move(handler)}
{}
void
ircd::ctx::to_asio::interrupted(ctx *const &interruptor)
noexcept
ircd::ctx::to_asio::to_asio(const interruptor &intr)
:continuation
{
false_predicate, intr
}
{
if(handler)
handler(interruptor);
}
///////////////////////////////////////////////////////////////////////////////