diff --git a/include/ircd/ircd.h b/include/ircd/ircd.h index c9ae6db1b..a7b5de085 100644 --- a/include/ircd/ircd.h +++ b/include/ircd/ircd.h @@ -21,7 +21,6 @@ #include "util/util.h" #include "exception.h" #include "run.h" -#include "fpe.h" #include "demangle.h" #include "localee.h" #include "date.h" diff --git a/include/ircd/fpe.h b/include/ircd/util/fpe.h similarity index 57% rename from include/ircd/fpe.h rename to include/ircd/util/fpe.h index f7d7bc4be..f8e0e2a9a 100644 --- a/include/ircd/fpe.h +++ b/include/ircd/util/fpe.h @@ -9,12 +9,11 @@ // full license for this software is available in the LICENSE file. #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_throw; string_view reflect_sicode(const int &); 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 /// of fpe::errors_handle. After each operation check the floating point /// 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; @@ -37,26 +36,3 @@ struct ircd::fpe::errors_handle errors_handle(); ~errors_handle() noexcept(false); }; - -// We don't include 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 their_sa; - long their_fenabled; - fexcept_t their_fe; - - public: - errors_throw(); - ~errors_throw() noexcept; -}; diff --git a/include/ircd/util/util.h b/include/ircd/util/util.h index 0bbde7a48..53571a5a1 100644 --- a/include/ircd/util/util.h +++ b/include/ircd/util/util.h @@ -57,6 +57,7 @@ namespace ircd #include "u2a.h" #include "pretty.h" #include "hash.h" +#include "fpe.h" // Unsorted section namespace ircd { diff --git a/ircd/Makefile.am b/ircd/Makefile.am index 8788f73eb..0e3141346 100644 --- a/ircd/Makefile.am +++ b/ircd/Makefile.am @@ -105,7 +105,6 @@ libircd_la_SOURCES = \ allocator.cc \ exception.cc \ util.cc \ - fpe.cc \ ios.cc \ lexical.cc \ tokens.cc \ diff --git a/ircd/fpe.cc b/ircd/fpe.cc deleted file mode 100644 index 1c3448cb2..000000000 --- a/ircd/fpe.cc +++ /dev/null @@ -1,225 +0,0 @@ -// Matrix Construct -// -// Copyright (C) Matrix Construct Developers, Authors & Contributors -// Copyright (C) 2016-2018 Jason Volk -// -// 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 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 "?????"; -} diff --git a/ircd/util.cc b/ircd/util.cc index 32a84d9bc..b953c7f03 100644 --- a/ircd/util.cc +++ b/ircd/util.cc @@ -23,6 +23,126 @@ ircd::util::size(std::ostream &s) 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