mirror of
https://github.com/matrix-construct/construct
synced 2024-11-17 15:30:52 +01:00
ircd::ctx: Device to allow context switching in exception handler.
This commit is contained in:
parent
ecce9d0433
commit
441a692dfc
2 changed files with 40 additions and 0 deletions
|
@ -63,6 +63,7 @@ namespace ircd::ctx { inline namespace this_ctx
|
||||||
/// Interface to the currently running context
|
/// Interface to the currently running context
|
||||||
{
|
{
|
||||||
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
|
||||||
|
|
||||||
/// Points to the currently running context or null for main stack (do not modify)
|
/// Points to the currently running context or null for main stack (do not modify)
|
||||||
extern __thread struct ctx *current;
|
extern __thread struct ctx *current;
|
||||||
|
@ -147,6 +148,27 @@ class ircd::ctx::this_ctx::critical_assertion
|
||||||
~critical_assertion() noexcept;
|
~critical_assertion() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An instance of exception_handler must be present to allow a context
|
||||||
|
/// switch inside a catch block. This is due to ABI limitations that stack
|
||||||
|
/// exceptions with thread-local assumptions and don't expect catch blocks
|
||||||
|
/// on the same thread to interleave when we switch the stack.
|
||||||
|
///
|
||||||
|
/// We first increment the refcount for the caught exception so it remains
|
||||||
|
/// intuitively accessible for the rest of the catch block. Then the presence
|
||||||
|
/// of this object makes the ABI believe the catch block has ended.
|
||||||
|
///
|
||||||
|
/// The exception cannot then be rethrown. DO NOT RETHROW THE EXCEPTION.
|
||||||
|
///
|
||||||
|
struct ircd::ctx::this_ctx::exception_handler
|
||||||
|
:std::exception_ptr
|
||||||
|
{
|
||||||
|
exception_handler() noexcept;
|
||||||
|
exception_handler(exception_handler &&) = delete;
|
||||||
|
exception_handler(const exception_handler &) = delete;
|
||||||
|
exception_handler &operator=(exception_handler &&) = delete;
|
||||||
|
exception_handler &operator=(const exception_handler &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
/// 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
|
||||||
|
|
18
ircd/ctx.cc
18
ircd/ctx.cc
|
@ -9,6 +9,7 @@
|
||||||
// full license for this software is available in the LICENSE file.
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
#include <RB_INC_X86INTRIN_H
|
#include <RB_INC_X86INTRIN_H
|
||||||
|
#include <cxxabi.h>
|
||||||
#include <ircd/asio.h>
|
#include <ircd/asio.h>
|
||||||
|
|
||||||
/// Internal context implementation
|
/// Internal context implementation
|
||||||
|
@ -480,6 +481,20 @@ ircd::ctx::id(const ctx &ctx)
|
||||||
return ctx.id;
|
return ctx.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// exception_handler
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::ctx::this_ctx::exception_handler::exception_handler()
|
||||||
|
noexcept
|
||||||
|
:std::exception_ptr{std::current_exception()}
|
||||||
|
{
|
||||||
|
assert(bool(*this));
|
||||||
|
assert(!std::uncaught_exceptions());
|
||||||
|
__cxa_end_catch();
|
||||||
|
assert(!std::current_exception());
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// ctx/continuation.h
|
// ctx/continuation.h
|
||||||
|
@ -519,6 +534,9 @@ ircd::ctx::continuation::continuation(ctx *const &self)
|
||||||
assert(self != nullptr);
|
assert(self != nullptr);
|
||||||
assert(self->notes <= 1);
|
assert(self->notes <= 1);
|
||||||
|
|
||||||
|
// Note: Construct an instance of ctx::exception_handler to enable yielding
|
||||||
|
// in your catch block.
|
||||||
|
//
|
||||||
// GNU cxxabi uses a singly-linked forward list (aka the 'exception
|
// GNU cxxabi uses a singly-linked forward list (aka the 'exception
|
||||||
// stack') for pending exception activities. Due to this limitation we
|
// stack') for pending exception activities. Due to this limitation we
|
||||||
// cannot interleave _cxa_begin_catch() and __cxa_end_catch() by yielding
|
// cannot interleave _cxa_begin_catch() and __cxa_end_catch() by yielding
|
||||||
|
|
Loading…
Reference in a new issue