0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd: Move fpe into util.

This commit is contained in:
Jason Volk 2019-02-16 13:14:25 -08:00
parent 108e90702e
commit d8536ca9a9
6 changed files with 124 additions and 254 deletions

View file

@ -21,7 +21,6 @@
#include "util/util.h" #include "util/util.h"
#include "exception.h" #include "exception.h"
#include "run.h" #include "run.h"
#include "fpe.h"
#include "demangle.h" #include "demangle.h"
#include "localee.h" #include "localee.h"
#include "date.h" #include "date.h"

View file

@ -9,12 +9,11 @@
// full license for this software is available in the LICENSE file. // full license for this software is available in the LICENSE file.
#pragma once #pragma once
#define HAVE_IRCD_FPE_H #define HAVE_IRCD_UTIL_FPE_H
namespace ircd::fpe namespace ircd::util::fpe
{ {
struct errors_handle; struct errors_handle;
struct errors_throw;
string_view reflect_sicode(const int &); string_view reflect_sicode(const int &);
string_view reflect(const ushort &flag); string_view reflect(const ushort &flag);
@ -25,7 +24,7 @@ namespace ircd::fpe
/// Perform a single floating point operation at a time within the scope /// Perform a single floating point operation at a time within the scope
/// of fpe::errors_handle. After each operation check the floating point /// of fpe::errors_handle. After each operation check the floating point
/// unit for an error status flag and throw a C++ exception. /// unit for an error status flag and throw a C++ exception.
struct ircd::fpe::errors_handle struct ircd::util::fpe::errors_handle
{ {
fexcept_t theirs; fexcept_t theirs;
@ -37,26 +36,3 @@ struct ircd::fpe::errors_handle
errors_handle(); errors_handle();
~errors_handle() noexcept(false); ~errors_handle() noexcept(false);
}; };
// We don't include <signal.h> in IRCd's standard include list. Instead that
// is conditionally included in the appropriate .cc file. All we require here
// is a forward declaration.
extern "C"
{
struct sigaction;
};
/// Experimental floating-point error handling strategy which throws
/// a C++ exception directly from the instruction which faulted the FPU.
/// The stack will unwind directly from that point in the execution and
/// control will be transferred to the appropriate catch block.
struct ircd::fpe::errors_throw
{
custom_ptr<struct sigaction> their_sa;
long their_fenabled;
fexcept_t their_fe;
public:
errors_throw();
~errors_throw() noexcept;
};

View file

@ -57,6 +57,7 @@ namespace ircd
#include "u2a.h" #include "u2a.h"
#include "pretty.h" #include "pretty.h"
#include "hash.h" #include "hash.h"
#include "fpe.h"
// Unsorted section // Unsorted section
namespace ircd { namespace ircd {

View file

@ -105,7 +105,6 @@ libircd_la_SOURCES = \
allocator.cc \ allocator.cc \
exception.cc \ exception.cc \
util.cc \ util.cc \
fpe.cc \
ios.cc \ ios.cc \
lexical.cc \ lexical.cc \
tokens.cc \ tokens.cc \

View file

@ -1,225 +0,0 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 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_SIGNAL_H
#ifndef __GNUC__
#pragma STDC FENV_ACCESS on
#endif
//
// errors_throw
//
#if defined(IRCD_USE_ASYNC_EXCEPTIONS) \
&& defined(HAVE_SIGNAL_H) \
&& defined(__GNUC__) \
namespace ircd::fpe
{
/// The maximum number of sigactions we can maintain in our internal space.
constexpr const size_t &SA_HEAP_MAX {48};
/// This internal buffer is used for holding instances of struct sigaction
/// as our external interface only has a forward-declaration and our class
/// only maintains a pointer member for it.
thread_local allocator::fixed<struct sigaction, SA_HEAP_MAX> sa_heap;
extern "C" void ircd_fpe_handle_sigfpe(int signum, siginfo_t *const si, void *const uctx);
}
[[noreturn]] void
ircd::fpe::ircd_fpe_handle_sigfpe(int signum,
siginfo_t *const si,
void *const uctx)
{
assert(si);
assert(signum == SIGFPE);
//TODO: due to __cxa_allocate_exception() this still malloc()'s :/
// We can't have a floating point error within malloc() and family
// or this signal will cleave it at an intermediate state and reenter.
throw std::domain_error
{
reflect_sicode(si->si_code)
};
}
//
// errors_throw::errors_throw
//
ircd::fpe::errors_throw::errors_throw()
:their_sa
{
new (sa_heap().allocate(1)) struct sigaction,
[](auto *const ptr)
{
sa_heap().deallocate(ptr, 1);
}
}
,their_fenabled
{
syscall(::fegetexcept)
}
{
struct sigaction ours {0};
ours.sa_sigaction = ircd_fpe_handle_sigfpe;
ours.sa_flags |= SA_SIGINFO;
ours.sa_flags |= SA_NODEFER; // Required to throw out of the handler
syscall(std::fegetexceptflag, &their_fe, FE_ALL_EXCEPT);
syscall(std::feclearexcept, FE_ALL_EXCEPT);
syscall(::sigaction, SIGFPE, &ours, their_sa.get());
syscall(::feenableexcept, FE_ALL_EXCEPT);
}
ircd::fpe::errors_throw::~errors_throw()
noexcept
{
syscall(::fedisableexcept, FE_ALL_EXCEPT);
syscall(::sigaction, SIGFPE, their_sa.get(), nullptr);
syscall(::feenableexcept, their_fenabled);
syscall(std::fesetexceptflag, &their_fe, FE_ALL_EXCEPT);
}
#else // IRCD_USE_ASYNC_EXCEPTIONS
//
// errors_throw::errors_throw
//
[[noreturn]]
ircd::fpe::errors_throw::errors_throw()
{
throw panic
{
"Not implemented in this environment."
};
}
[[noreturn]]
ircd::fpe::errors_throw::~errors_throw()
noexcept
{
assert(0);
}
#endif // IRCD_USE_ASYNC_EXCEPTIONS
//
// errors_handle
//
ircd::fpe::errors_handle::errors_handle()
{
syscall(std::fegetexceptflag, &theirs, FE_ALL_EXCEPT);
clear_pending();
}
ircd::fpe::errors_handle::~errors_handle()
noexcept(false)
{
const auto pending(this->pending());
syscall(std::fesetexceptflag, &theirs, FE_ALL_EXCEPT);
throw_errors(pending);
}
void
ircd::fpe::errors_handle::clear_pending()
{
syscall(std::feclearexcept, FE_ALL_EXCEPT);
}
void
ircd::fpe::errors_handle::throw_pending()
const
{
throw_errors(pending());
}
ushort
ircd::fpe::errors_handle::pending()
const
{
return std::fetestexcept(FE_ALL_EXCEPT);
}
//
// util
//
void
ircd::fpe::throw_errors(const ushort &flags)
{
if(!flags)
return;
thread_local char buf[128];
throw std::domain_error
{
reflect(buf, flags)
};
}
ircd::string_view
ircd::fpe::reflect(const mutable_buffer &buf,
const ushort &flags)
{
window_buffer wb{buf};
const auto append{[&wb](const auto &flag)
{
wb([&flag](const mutable_buffer &buf)
{
return strlcpy(buf, reflect(flag));
});
}};
for(size_t i(0); i < sizeof(flags) * 8; ++i)
if(flags & (1 << i))
append(1 << i);
return wb.completed();
}
ircd::string_view
ircd::fpe::reflect(const ushort &flag)
{
switch(flag)
{
case 0: return "";
case FE_INVALID: return "INVALID";
case FE_DIVBYZERO: return "DIVBYZERO";
case FE_UNDERFLOW: return "UNDERFLOW";
case FE_OVERFLOW: return "OVERFLOW";
case FE_INEXACT: return "INEXACT";
}
return "?????";
}
ircd::string_view
ircd::fpe::reflect_sicode(const int &code)
{
switch(code)
{
#ifdef HAVE_SIGNAL_H
case FPE_INTDIV: return "INTDIV";
case FPE_INTOVF: return "INTOVF";
case FPE_FLTDIV: return "FLTDIV";
case FPE_FLTOVF: return "FLTOVF";
case FPE_FLTUND: return "FLTUND";
case FPE_FLTRES: return "FLTRES";
case FPE_FLTINV: return "FLTINV";
case FPE_FLTSUB: return "FLTSUB";
#endif // HAVE_SIGNAL_H
}
return "?????";
}

View file

@ -23,6 +23,126 @@ ircd::util::size(std::ostream &s)
return ret; return ret;
} }
///////////////////////////////////////////////////////////////////////////////
//
// util/fpe.h
//
#ifndef __GNUC__
#pragma STDC FENV_ACCESS on
#endif
void
ircd::util::fpe::throw_errors(const ushort &flags)
{
if(!flags)
return;
thread_local char buf[128];
throw std::domain_error
{
reflect(buf, flags)
};
}
ircd::string_view
ircd::util::fpe::reflect(const mutable_buffer &buf,
const ushort &flags)
{
window_buffer wb{buf};
const auto append{[&wb](const auto &flag)
{
wb([&flag](const mutable_buffer &buf)
{
return strlcpy(buf, reflect(flag));
});
}};
for(size_t i(0); i < sizeof(flags) * 8; ++i)
if(flags & (1 << i))
append(1 << i);
return wb.completed();
}
ircd::string_view
ircd::util::fpe::reflect(const ushort &flag)
{
switch(flag)
{
case 0: return "";
case FE_INVALID: return "INVALID";
case FE_DIVBYZERO: return "DIVBYZERO";
case FE_UNDERFLOW: return "UNDERFLOW";
case FE_OVERFLOW: return "OVERFLOW";
case FE_INEXACT: return "INEXACT";
}
return "?????";
}
ircd::string_view
ircd::util::fpe::reflect_sicode(const int &code)
{
switch(code)
{
#if defined(HAVE_SIGNAL_H) && defined(FPE_INTDIV)
case FPE_INTDIV: return "INTDIV";
case FPE_INTOVF: return "INTOVF";
case FPE_FLTDIV: return "FLTDIV";
case FPE_FLTOVF: return "FLTOVF";
case FPE_FLTUND: return "FLTUND";
case FPE_FLTRES: return "FLTRES";
case FPE_FLTINV: return "FLTINV";
case FPE_FLTSUB: return "FLTSUB";
#endif // HAVE_SIGNAL_H
}
return "?????";
}
//
// errors_handle
//
ircd::util::fpe::errors_handle::errors_handle()
{
syscall(std::fegetexceptflag, &theirs, FE_ALL_EXCEPT);
clear_pending();
}
ircd::util::fpe::errors_handle::~errors_handle()
noexcept(false)
{
const auto pending(this->pending());
syscall(std::fesetexceptflag, &theirs, FE_ALL_EXCEPT);
throw_errors(pending);
}
void
ircd::util::fpe::errors_handle::clear_pending()
{
syscall(std::feclearexcept, FE_ALL_EXCEPT);
}
void
ircd::util::fpe::errors_handle::throw_pending()
const
{
throw_errors(pending());
}
ushort
ircd::util::fpe::errors_handle::pending()
const
{
return std::fetestexcept(FE_ALL_EXCEPT);
}
#ifndef __GNUC__
#pragma STDC FENV_ACCESS off
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// util/env.h // util/env.h