0
0
Fork 0
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:
Jason Volk 2018-03-24 17:41:16 -07:00
parent ecce9d0433
commit 441a692dfc
2 changed files with 40 additions and 0 deletions

View file

@ -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

View file

@ -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