mirror of
https://github.com/matrix-construct/construct
synced 2024-11-16 23:10:54 +01:00
ircd::ctx: Support interrupt suppression; suite.
This commit is contained in:
parent
fd13e71684
commit
7e8ec1ca63
5 changed files with 112 additions and 0 deletions
|
@ -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)
|
||||||
|
|
|
@ -55,6 +55,7 @@ namespace ircd::ctx
|
||||||
const int64_t ¬es(const ctx &); // Peeks at internal semaphore count
|
const int64_t ¬es(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
|
||||||
|
|
|
@ -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
|
||||||
|
|
77
ircd/ctx.cc
77
ircd/ctx.cc
|
@ -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
|
||||||
//
|
//
|
||||||
|
|
|
@ -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' : '-')
|
||||||
;
|
;
|
||||||
|
|
Loading…
Reference in a new issue