mirror of
https://github.com/matrix-construct/construct
synced 2025-01-14 00:34:18 +01:00
ircd::ctx: Reorg continuation for core wakeup conditions.
This commit is contained in:
parent
9eabd745f5
commit
4a2ad1c186
2 changed files with 81 additions and 32 deletions
|
@ -18,10 +18,12 @@
|
||||||
|
|
||||||
namespace ircd::ctx
|
namespace ircd::ctx
|
||||||
{
|
{
|
||||||
using yield_context = boost::asio::yield_context;
|
|
||||||
|
|
||||||
struct continuation;
|
struct continuation;
|
||||||
struct to_asio;
|
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
|
namespace ircd
|
||||||
|
@ -43,17 +45,37 @@ namespace ircd
|
||||||
/// executes before control continues beyond the yield_context call itself and
|
/// executes before control continues beyond the yield_context call itself and
|
||||||
/// ties this sequence together neatly.
|
/// 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
|
struct ircd::ctx::continuation
|
||||||
{
|
{
|
||||||
|
static const predicate true_predicate;
|
||||||
|
static const predicate false_predicate;
|
||||||
|
static const interruptor noop_interruptor;
|
||||||
|
|
||||||
ctx *self;
|
ctx *self;
|
||||||
|
const predicate &pred;
|
||||||
|
const interruptor &intr;
|
||||||
|
|
||||||
operator const boost::asio::yield_context &() const;
|
operator const boost::asio::yield_context &() const;
|
||||||
operator boost::asio::yield_context &();
|
operator boost::asio::yield_context &();
|
||||||
|
|
||||||
virtual void interrupted(ctx *const &) noexcept;
|
continuation(const predicate & = true_predicate,
|
||||||
|
const interruptor & = noop_interruptor);
|
||||||
|
|
||||||
continuation();
|
~continuation() noexcept;
|
||||||
virtual ~continuation() noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This type of continuation should be used when yielding a context to a
|
/// 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
|
struct ircd::ctx::to_asio
|
||||||
:ircd::ctx::continuation
|
:ircd::ctx::continuation
|
||||||
{
|
{
|
||||||
using function = std::function<void (ctx *const &)>;
|
to_asio(const interruptor &);
|
||||||
|
|
||||||
function handler;
|
|
||||||
|
|
||||||
void interrupted(ctx *const &) noexcept final override;
|
|
||||||
|
|
||||||
to_asio(function handler);
|
|
||||||
to_asio() = default;
|
to_asio() = default;
|
||||||
};
|
};
|
||||||
|
|
73
ircd/ctx.cc
73
ircd/ctx.cc
|
@ -163,14 +163,27 @@ ircd::ctx::ctx::wait()
|
||||||
if(--notes > 0)
|
if(--notes > 0)
|
||||||
return false;
|
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
|
(ctx *const &interruptor) noexcept
|
||||||
{
|
{
|
||||||
wake();
|
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;
|
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(ec == errc::operation_canceled || ec == errc::success);
|
||||||
assert(current == this);
|
assert(current == this);
|
||||||
|
@ -363,7 +376,7 @@ ircd::ctx::terminate(ctx &ctx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(likely(&ctx != current && ctx.cont != nullptr))
|
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
|
/// Marks `ctx` for interruption and enqueues it for resumption to receive the
|
||||||
|
@ -386,7 +399,7 @@ ircd::ctx::interrupt(ctx &ctx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(likely(&ctx != current && ctx.cont != nullptr))
|
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
|
/// Marks `ctx` for whether to allow or suppress interruption. Suppression
|
||||||
|
@ -800,15 +813,45 @@ noexcept
|
||||||
// ctx/continuation.h
|
// 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
|
// continuation
|
||||||
//
|
//
|
||||||
|
|
||||||
ircd::ctx::continuation::continuation()
|
ircd::ctx::continuation::continuation(const predicate &pred,
|
||||||
|
const interruptor &intr)
|
||||||
:self
|
:self
|
||||||
{
|
{
|
||||||
ircd::ctx::current
|
ircd::ctx::current
|
||||||
}
|
}
|
||||||
|
,pred
|
||||||
|
{
|
||||||
|
pred
|
||||||
|
}
|
||||||
|
,intr
|
||||||
|
{
|
||||||
|
intr
|
||||||
|
}
|
||||||
{
|
{
|
||||||
mark(prof::event::CUR_YIELD);
|
mark(prof::event::CUR_YIELD);
|
||||||
|
|
||||||
|
@ -843,12 +886,6 @@ noexcept
|
||||||
// pointer while the context is awake.
|
// pointer while the context is awake.
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ircd::ctx::continuation::interrupted(ctx *const &interruptor)
|
|
||||||
noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::ctx::continuation::operator boost::asio::yield_context &()
|
ircd::ctx::continuation::operator boost::asio::yield_context &()
|
||||||
{
|
{
|
||||||
return *self->yc;
|
return *self->yc;
|
||||||
|
@ -864,16 +901,12 @@ const
|
||||||
// to_asio
|
// to_asio
|
||||||
//
|
//
|
||||||
|
|
||||||
ircd::ctx::to_asio::to_asio(function handler)
|
ircd::ctx::to_asio::to_asio(const interruptor &intr)
|
||||||
:handler{std::move(handler)}
|
:continuation
|
||||||
{}
|
{
|
||||||
|
false_predicate, intr
|
||||||
void
|
}
|
||||||
ircd::ctx::to_asio::interrupted(ctx *const &interruptor)
|
|
||||||
noexcept
|
|
||||||
{
|
{
|
||||||
if(handler)
|
|
||||||
handler(interruptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in a new issue