0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-29 17:04:03 +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
#define HAVE_IRCD_CTX_EXCEPTION_HANDLER_H
namespace ircd::ctx {
inline namespace this_ctx
namespace ircd::ctx
{
struct exception_handler;
}}
}
/// 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
@ -28,9 +27,14 @@ inline namespace this_ctx
///
/// 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
{
static uint uncaught_exceptions(const uint &) noexcept;
static uint uncaught_exceptions() noexcept;
static void end_catch() noexcept;
public:
exception_handler() noexcept;
exception_handler(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 += ios.cc
libircd_la_SOURCES += ctx.cc
libircd_la_SOURCES += ctx_eh.cc
libircd_la_SOURCES += ctx_ole.cc
if AIO
libircd_la_SOURCES += fs_aio.cc

View file

@ -8,7 +8,6 @@
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#include <cxxabi.h>
#include <ircd/asio.h>
#include "ctx.h"
@ -756,30 +755,6 @@ noexcept
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
//
@ -996,14 +971,6 @@ ircd::ctx::continuation::noop_interruptor{[]
return;
}};
#ifdef HAVE_CXXABI_H
struct __cxxabiv1::__cxa_eh_globals
{
__cxa_exception *caughtExceptions;
unsigned int uncaughtExceptions;
};
#endif
//
// continuation
//
@ -1025,7 +992,7 @@ ircd::ctx::continuation::continuation(const predicate &pred,
}
,uncaught_exceptions
{
uint(std::uncaught_exceptions())
exception_handler::uncaught_exceptions(0)
}
{
assert(self != nullptr);
@ -1036,6 +1003,10 @@ ircd::ctx::continuation::continuation(const predicate &pred,
assert_critical();
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
// in your catch block.
//
@ -1057,15 +1028,6 @@ ircd::ctx::continuation::continuation(const predicate &pred,
// its execution run and is now yielding.
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.
assert(self->yc);
@ -1097,16 +1059,9 @@ noexcept
// upon resuming execution.
ircd::ctx::current = self;
#ifdef HAVE_CXXABI_H
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
// Restore the uncaught exception count for this context to the cxxabi
assert(std::uncaught_exceptions() == 0);
assert(uncaught_exceptions == 0);
#endif
exception_handler::uncaught_exceptions(uncaught_exceptions);
// Tell the profiler this is the point where the context is now resuming.
// 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