0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-29 04:08:54 +02:00

ircd::ctx: Support interrupt suppression; suite.

This commit is contained in:
Jason Volk 2018-05-22 00:00:26 -07:00
parent fd13e71684
commit 7e8ec1ca63
5 changed files with 112 additions and 0 deletions

View file

@ -102,6 +102,7 @@ enum ircd::ctx::context::flags
POST = 0x01, ///< Defers spawn with an ios.post() POST = 0x01, ///< Defers spawn with an ios.post()
DISPATCH = 0x02, ///< Defers spawn with an ios.dispatch() (possibly) DISPATCH = 0x02, ///< Defers spawn with an ios.dispatch() (possibly)
DETACH = 0x04, ///< Context deletes itself; see struct context constructor notes DETACH = 0x04, ///< Context deletes itself; see struct context constructor notes
NOINTERRUPT = 0x08, ///< Interruption points won't throw while lit.
INTERRUPTED = 0x10, ///< (INDICATOR) Marked INTERRUPTED = 0x10, ///< (INDICATOR) Marked
TERMINATED = 0x20, ///< (INDICATOR) TERMINATED = 0x20, ///< (INDICATOR)

View file

@ -55,6 +55,7 @@ namespace ircd::ctx
const int64_t &notes(const ctx &); // Peeks at internal semaphore count const int64_t &notes(const ctx &); // Peeks at internal semaphore count
const uint64_t &yields(const ctx &); // Context switching counter const uint64_t &yields(const ctx &); // Context switching counter
const ulong &cycles(const ctx &); // Accumulated tsc (not counting cur slice) const ulong &cycles(const ctx &); // Accumulated tsc (not counting cur slice)
bool interruptible(const ctx &); // Context can throw at interruption point
bool interruption(const ctx &); // Context was marked for interruption bool interruption(const ctx &); // Context was marked for interruption
bool termination(const ctx &); // Context was marked for termination bool termination(const ctx &); // Context was marked for termination
bool finished(const ctx &); // Context function returned (or exception). bool finished(const ctx &); // Context function returned (or exception).
@ -62,6 +63,7 @@ namespace ircd::ctx
bool running(const ctx &); // Context is the currently running ctx. bool running(const ctx &); // Context is the currently running ctx.
bool waiting(const ctx &); // started() && !finished() && !running() bool waiting(const ctx &); // started() && !finished() && !running()
void interruptible(ctx &, const bool &); // False for interrupt suppression.
void interrupt(ctx &); // Interrupt the context. void interrupt(ctx &); // Interrupt the context.
void terminate(ctx &); // Interrupt for termination. void terminate(ctx &); // Interrupt for termination.
void signal(ctx &, std::function<void ()>); // Post function to context strand void signal(ctx &, std::function<void ()>); // Post function to context strand

View file

@ -18,6 +18,7 @@ inline namespace this_ctx
struct critical_indicator; // Indicates if yielding happened for a section struct critical_indicator; // Indicates if yielding happened for a section
struct critical_assertion; // Assert no yielding for a section struct critical_assertion; // Assert no yielding for a section
struct exception_handler; // Must be present to yield in a handler struct exception_handler; // Must be present to yield in a handler
struct uninterruptible; // Scope convenience for interruptible()
struct ctx &cur(); ///< Assumptional reference to *current struct ctx &cur(); ///< Assumptional reference to *current
@ -29,6 +30,8 @@ inline namespace this_ctx
void interruption_point(); // throws if interruption_requested() void interruption_point(); // throws if interruption_requested()
bool interruption_requested(); // interruption(cur()) bool interruption_requested(); // interruption(cur())
void interruptible(const bool &); // interruptible(cur(), bool) +INTERRUPTION POINT
void interruptible(const bool &, std::nothrow_t) noexcept;
struct stack_usage_assertion; // Assert safety factor (see ctx/prof.h) struct stack_usage_assertion; // Assert safety factor (see ctx/prof.h)
size_t stack_at_here() __attribute__((noinline)); size_t stack_at_here() __attribute__((noinline));
@ -134,6 +137,34 @@ struct ircd::ctx::this_ctx::exception_handler
exception_handler &operator=(const exception_handler &) = delete; exception_handler &operator=(const exception_handler &) = delete;
}; };
/// An instance of uninterruptible will suppress interrupts sent to the
/// context for the scope. Suppression does not discard any interrupt,
/// it merely ignores it at all interruption points until the suppression
/// ends, after which it will be thrown.
///
struct ircd::ctx::this_ctx::uninterruptible
{
struct nothrow;
uninterruptible();
uninterruptible(uninterruptible &&) = delete;
uninterruptible(const uninterruptible &) = delete;
~uninterruptible() noexcept(false);
};
/// A variant of uinterruptible for users that must guarantee the ending of
/// the suppression scope will not be an interruption point. The default
/// behavior for uninterruptible is to throw, even from its destructor, to
/// fulfill the interruption request without any more delay.
///
struct ircd::ctx::this_ctx::uninterruptible::nothrow
{
nothrow() noexcept;
nothrow(nothrow &&) = delete;
nothrow(const nothrow &) = delete;
~nothrow() noexcept;
};
/// This overload matches ::sleep() and acts as a drop-in for ircd contexts. /// This overload matches ::sleep() and acts as a drop-in for ircd contexts.
/// interruption point. /// interruption point.
inline void inline void

View file

@ -232,6 +232,12 @@ ircd::ctx::ctx::interruption_point(std::nothrow_t)
// so please eat this branch misprediction. // so please eat this branch misprediction.
if(unlikely(flags & context::INTERRUPTED)) if(unlikely(flags & context::INTERRUPTED))
{ {
// The NOINTERRUPT flag works by pretending there is no INTERRUPTED
// flag set and also does not clear the flag. This allows the interrupt
// to remaing pending until the uninterruptible section is complete.
if(flags & context::NOINTERRUPT)
return false;
mark(prof::event::CUR_INTERRUPT); mark(prof::event::CUR_INTERRUPT);
flags &= ~context::INTERRUPTED; flags &= ~context::INTERRUPTED;
return true; return true;
@ -332,6 +338,20 @@ ircd::ctx::interrupt(ctx &ctx)
ctx.cont->interrupted(current); ctx.cont->interrupted(current);
} }
/// Marks `ctx` for whether to allow or suppress interruption. Suppression
/// does not ignore an interrupt itself, it only ignores the interruption
/// points. Thus when a suppression ends if the interrupt flag was ever set
/// the next interruption point will throw as expected.
void
ircd::ctx::interruptible(ctx &ctx,
const bool &b)
{
if(b)
ctx.flags &= ~context::NOINTERRUPT;
else
ctx.flags |= context::NOINTERRUPT;
}
/// started() && !finished() && !running /// started() && !finished() && !running
bool bool
ircd::ctx::waiting(const ctx &ctx) ircd::ctx::waiting(const ctx &ctx)
@ -374,6 +394,13 @@ ircd::ctx::interruption(const ctx &c)
return c.flags & context::INTERRUPTED; return c.flags & context::INTERRUPTED;
} }
/// Indicates if `ctx` will suppress any interrupts.
bool
ircd::ctx::interruptible(const ctx &c)
{
return c.flags & ~context::NOINTERRUPT;
}
/// Returns the cycle count for `ctx` /// Returns the cycle count for `ctx`
const ulong & const ulong &
ircd::ctx::cycles(const ctx &ctx) ircd::ctx::cycles(const ctx &ctx)
@ -521,6 +548,25 @@ ircd::ctx::this_ctx::stack_at_here()
return cur().stack_base - uintptr_t(__builtin_frame_address(0)); return cur().stack_base - uintptr_t(__builtin_frame_address(0));
} }
/// Throws interrupted if the currently running context was interrupted
/// and clears the interrupt flag.
void
ircd::ctx::this_ctx::interruptible(const bool &b)
{
interruptible(b, std::nothrow);
interruption_point();
}
/// Throws interrupted if the currently running context was interrupted
/// and clears the interrupt flag.
void
ircd::ctx::this_ctx::interruptible(const bool &b,
std::nothrow_t)
noexcept
{
interruptible(cur(), b);
}
/// Throws interrupted if the currently running context was interrupted /// Throws interrupted if the currently running context was interrupted
/// and clears the interrupt flag. /// and clears the interrupt flag.
void void
@ -553,6 +599,37 @@ ircd::ctx::this_ctx::name()
return current? name(cur()) : nada; return current? name(cur()) : nada;
} }
//
// uinterruptible
//
ircd::ctx::this_ctx::uninterruptible::uninterruptible()
{
interruptible(false);
}
ircd::ctx::this_ctx::uninterruptible::~uninterruptible()
noexcept(false)
{
interruptible(true);
}
//
// uninterruptible::nothrow
//
ircd::ctx::this_ctx::uninterruptible::nothrow::nothrow()
noexcept
{
interruptible(false, std::nothrow);
}
ircd::ctx::this_ctx::uninterruptible::nothrow::~nothrow()
noexcept
{
interruptible(true, std::nothrow);
}
// //
// exception_handler // exception_handler
// //

View file

@ -826,6 +826,7 @@ console_cmd__ctx__list(opt &out, const string_view &line)
<< (running(ctx)? 'R' : '-') << (running(ctx)? 'R' : '-')
<< (waiting(ctx)? 'W' : '-') << (waiting(ctx)? 'W' : '-')
<< (finished(ctx)? 'F' : '-') << (finished(ctx)? 'F' : '-')
<< (interruptible(ctx)? '-' : 'N')
<< (interruption(ctx)? 'I' : '-') << (interruption(ctx)? 'I' : '-')
<< (termination(ctx)? 'T' : '-') << (termination(ctx)? 'T' : '-')
; ;