0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-28 17:52:54 +01:00

ircd::ctx: Split exception_handler w/ cxxabi header requirement.

This commit is contained in:
Jason Volk 2019-07-21 15:26:44 -07:00
parent 480834f49b
commit 471c08a41e
4 changed files with 136 additions and 56 deletions

View file

@ -11,11 +11,10 @@
#pragma once #pragma once
#define HAVE_IRCD_CTX_EXCEPTION_HANDLER_H #define HAVE_IRCD_CTX_EXCEPTION_HANDLER_H
namespace ircd::ctx { namespace ircd::ctx
inline namespace this_ctx
{ {
struct exception_handler; struct exception_handler;
}} }
/// An instance of exception_handler must be present to allow a context /// 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 /// switch inside a catch block. This is due to ABI limitations that stack
@ -28,9 +27,14 @@ inline namespace this_ctx
/// ///
/// The exception cannot then be rethrown. DO NOT RETHROW THE EXCEPTION. /// The exception cannot then be rethrown. DO NOT RETHROW THE EXCEPTION.
/// ///
struct ircd::ctx::this_ctx::exception_handler struct ircd::ctx::exception_handler
:std::exception_ptr :std::exception_ptr
{ {
static uint uncaught_exceptions(const uint &) noexcept;
static uint uncaught_exceptions() noexcept;
static void end_catch() noexcept;
public:
exception_handler() noexcept; exception_handler() noexcept;
exception_handler(exception_handler &&) = delete; exception_handler(exception_handler &&) = delete;
exception_handler(const exception_handler &) = delete; exception_handler(const exception_handler &) = delete;

View file

@ -149,6 +149,7 @@ libircd_la_SOURCES += prof.cc
libircd_la_SOURCES += fs.cc libircd_la_SOURCES += fs.cc
libircd_la_SOURCES += ios.cc libircd_la_SOURCES += ios.cc
libircd_la_SOURCES += ctx.cc libircd_la_SOURCES += ctx.cc
libircd_la_SOURCES += ctx_eh.cc
libircd_la_SOURCES += ctx_ole.cc libircd_la_SOURCES += ctx_ole.cc
if AIO if AIO
libircd_la_SOURCES += fs_aio.cc libircd_la_SOURCES += fs_aio.cc

View file

@ -8,7 +8,6 @@
// copyright notice and this permission notice is present in all copies. The // copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file. // full license for this software is available in the LICENSE file.
#include <cxxabi.h>
#include <ircd/asio.h> #include <ircd/asio.h>
#include "ctx.h" #include "ctx.h"
@ -756,30 +755,6 @@ noexcept
interruptible(theirs, std::nothrow); interruptible(theirs, std::nothrow);
} }
//
// exception_handler
//
ircd::ctx::this_ctx::exception_handler::exception_handler()
noexcept
:std::exception_ptr
{
std::current_exception()
}
{
assert(bool(*this));
#ifdef HAVE_CXXABI_H
if(current)
__cxxabiv1::__cxa_end_catch();
#endif
// We don't yet support more levels of exceptions; after ending this
// catch we can't still be in another one. This doesn't apply if we're
// not on any ctx currently.
assert(!current || !std::uncaught_exceptions());
}
// //
// critical_assertion // critical_assertion
// //
@ -996,14 +971,6 @@ ircd::ctx::continuation::noop_interruptor{[]
return; return;
}}; }};
#ifdef HAVE_CXXABI_H
struct __cxxabiv1::__cxa_eh_globals
{
__cxa_exception *caughtExceptions;
unsigned int uncaughtExceptions;
};
#endif
// //
// continuation // continuation
// //
@ -1025,7 +992,7 @@ ircd::ctx::continuation::continuation(const predicate &pred,
} }
,uncaught_exceptions ,uncaught_exceptions
{ {
uint(std::uncaught_exceptions()) exception_handler::uncaught_exceptions(0)
} }
{ {
assert(self != nullptr); assert(self != nullptr);
@ -1036,6 +1003,10 @@ ircd::ctx::continuation::continuation(const predicate &pred,
assert_critical(); assert_critical();
assert(!critical_asserted); assert(!critical_asserted);
// Confirming the uncaught exception count was saved and set to zero in the
// initializer list.
assert(!std::uncaught_exceptions());
// Note: Construct an instance of ctx::exception_handler to enable yielding // Note: Construct an instance of ctx::exception_handler to enable yielding
// in your catch block. // in your catch block.
// //
@ -1057,15 +1028,6 @@ ircd::ctx::continuation::continuation(const predicate &pred,
// its execution run and is now yielding. // its execution run and is now yielding.
mark(prof::event::YIELD); mark(prof::event::YIELD);
#ifdef HAVE_CXXABI_H
using __cxxabiv1::__cxa_get_globals_fast;
assert(__cxa_get_globals_fast());
assert(__cxa_get_globals_fast()->uncaughtExceptions == uncaught_exceptions);
__cxa_get_globals_fast()->uncaughtExceptions = 0;
#else
assert(!uncaught_exceptions);
#endif
// Check that we saved a valid context reference to this object for later. // Check that we saved a valid context reference to this object for later.
assert(self->yc); assert(self->yc);
@ -1097,16 +1059,9 @@ noexcept
// upon resuming execution. // upon resuming execution.
ircd::ctx::current = self; ircd::ctx::current = self;
#ifdef HAVE_CXXABI_H // Restore the uncaught exception count for this context to the cxxabi
using __cxxabiv1::__cxa_get_globals_fast;
assert(__cxa_get_globals_fast());
assert(__cxa_get_globals_fast()->uncaughtExceptions == 0);
__cxa_get_globals_fast()->uncaughtExceptions = uncaught_exceptions;
assert(uint(std::uncaught_exceptions()) == uncaught_exceptions);
#else
assert(std::uncaught_exceptions() == 0); assert(std::uncaught_exceptions() == 0);
assert(uncaught_exceptions == 0); exception_handler::uncaught_exceptions(uncaught_exceptions);
#endif
// Tell the profiler this is the point where the context is now resuming. // Tell the profiler this is the point where the context is now resuming.
// On some optimized builds this might lead nowhere. // On some optimized builds this might lead nowhere.

120
ircd/ctx_eh.cc Normal file
View file

@ -0,0 +1,120 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#include <RB_INC_CXXABI_H
#include <ircd/asio.h>
#include "ctx.h"
#ifdef HAVE_CXXABI_H
struct __cxxabiv1::__cxa_eh_globals
{
__cxa_exception *caughtExceptions;
unsigned int uncaughtExceptions;
};
#endif
//
// exception_handler
//
ircd::ctx::exception_handler::exception_handler()
noexcept
:std::exception_ptr
{
// capture a shared reference of the current exception before the catch
// block closes around it.
std::current_exception()
}
{
assert(bool(*this));
// close the catch block.
end_catch();
// We don't yet support more levels of exceptions; after ending this
// catch we can't still be in another one. This doesn't apply if we're
// not on any ctx currently.
assert(!current || !std::uncaught_exceptions());
}
//
// util
//
#ifdef HAVE_CXXABI_H
void
ircd::ctx::exception_handler::end_catch()
noexcept
{
if(likely(current))
__cxxabiv1::__cxa_end_catch();
}
#else
#warning "CXXABI not available. Context switch inside catch block may be unsafe!"
void
ircd::ctx::exception_handler::end_catch()
noexcept
{
}
#endif
#ifdef HAVE_CXXABI_H
uint
ircd::ctx::exception_handler::uncaught_exceptions()
noexcept
{
const auto &cxa_globals
{
__cxxabiv1::__cxa_get_globals_fast()
};
assert(cxa_globals);
return cxa_globals->uncaughtExceptions;
}
#else
#warning "CXXABI not available. Context switch with uncaught exceptions may be unsafe!"
uint
ircd::ctx::exception_handler::uncaught_exceptions()
noexcept
{
return std::uncaught_exceptions();
}
#endif
#ifdef HAVE_CXXABI_H
uint
ircd::ctx::exception_handler::uncaught_exceptions(const uint &val)
noexcept
{
const auto &cxa_globals
{
__cxxabiv1::__cxa_get_globals_fast()
};
assert(cxa_globals);
const auto ret
{
cxa_globals->uncaughtExceptions
};
assert(unsigned(ret) == unsigned(std::uncaught_exceptions()));
cxa_globals->uncaughtExceptions = val;
return ret;
}
#else
#warning "CXXABI not available. Context switch with uncaught exceptions may be unsafe!"
uint
ircd::ctx::exception_handler::uncaught_exceptions(const uint &val)
noexcept
{
assert(std::uncaught_exceptions() == val);
return std::uncaught_exceptions();
}
#endif