Merge pull request #27854 from 3x380V/signal

Part: Use signal handlers based on OCC's implementation
This commit is contained in:
Benjamin Nauck
2026-02-28 13:58:19 +01:00
committed by GitHub
8 changed files with 587 additions and 169 deletions
+42 -169
View File
@@ -96,6 +96,7 @@
#include <Base/ProgressIndicatorPy.h>
#include <Base/RotationPy.h>
#include <Base/UniqueNameManager.h>
#include <Base/SystemHandler.h>
#include <Base/Tools.h>
#include <Base/Translate.h>
#include <Base/Type.h>
@@ -164,18 +165,6 @@
#include "SafeMode.h"
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
# pragma warning( disable : 4535 )
# if !defined(_DEBUG) && defined(HAVE_SEH)
# define FC_SE_TRANSLATOR
# endif
# include <new.h>
# include <eh.h> // VC exception handling
#else // Ansi C/C++ new handler
# include <new>
#endif
#ifdef FC_OS_WIN32
#include <windows.h>
#endif
@@ -1774,175 +1763,59 @@ void Application::destructObserver()
}
}
/** freecadNewHandler()
* prints an error message and throws an exception
*/
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
int __cdecl freecadNewHandler(size_t size )
namespace
{
// throw an exception
throw Base::MemoryException();
return 0;
}
#else // Ansi C/C++ new handler
static void freecadNewHandler ()
void initExceptions()
{
// throw an exception
throw Base::MemoryException();
// register exception producer types
// NOLINTBEGIN
new Base::ExceptionProducer<Base::AbortException>;
new Base::ExceptionProducer<Base::XMLBaseException>;
new Base::ExceptionProducer<Base::XMLParseException>;
new Base::ExceptionProducer<Base::XMLAttributeError>;
new Base::ExceptionProducer<Base::FileException>;
new Base::ExceptionProducer<Base::FileSystemError>;
new Base::ExceptionProducer<Base::BadFormatError>;
new Base::ExceptionProducer<Base::MemoryException>;
new Base::ExceptionProducer<Base::AccessViolation>;
new Base::ExceptionProducer<Base::AbnormalProgramTermination>;
new Base::ExceptionProducer<Base::UnknownProgramOption>;
new Base::ExceptionProducer<Base::ProgramInformation>;
new Base::ExceptionProducer<Base::TypeError>;
new Base::ExceptionProducer<Base::ValueError>;
new Base::ExceptionProducer<Base::IndexError>;
new Base::ExceptionProducer<Base::NameError>;
new Base::ExceptionProducer<Base::ImportError>;
new Base::ExceptionProducer<Base::AttributeError>;
new Base::ExceptionProducer<Base::RuntimeError>;
new Base::ExceptionProducer<Base::BadGraphError>;
new Base::ExceptionProducer<Base::NotImplementedError>;
new Base::ExceptionProducer<Base::ZeroDivisionError>;
new Base::ExceptionProducer<Base::ReferenceError>;
new Base::ExceptionProducer<Base::ExpressionError>;
new Base::ExceptionProducer<Base::ParserError>;
new Base::ExceptionProducer<Base::UnicodeError>;
new Base::ExceptionProducer<Base::OverflowError>;
new Base::ExceptionProducer<Base::UnderflowError>;
new Base::ExceptionProducer<Base::UnitsMismatchError>;
new Base::ExceptionProducer<Base::CADKernelError>;
new Base::ExceptionProducer<Base::RestoreError>;
new Base::ExceptionProducer<Base::PropertyError>;
// NOLINTEND
}
#endif
#if defined(FC_OS_LINUX)
#include <execinfo.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sstream>
#if HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
// This function produces a stack backtrace with demangled function & method names.
void printBacktrace(size_t skip=0)
{
#if defined HAVE_BACKTRACE_SYMBOLS
void *callstack[128];
size_t nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
size_t nFrames = backtrace(callstack, nMaxFrames);
char **symbols = backtrace_symbols(callstack, nFrames);
for (size_t i = skip; i < nFrames; i++) {
char *demangled = nullptr;
int status = -1;
Dl_info info;
if (dladdr(callstack[i], &info) && info.dli_sname && info.dli_fname) {
if (info.dli_sname[0] == '_') {
demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
}
}
std::stringstream str;
if (status == 0) {
void* offset = (void*)((char*)callstack[i] - (char*)info.dli_saddr);
str << "#" << (i-skip) << " " << callstack[i] << " in " << demangled << " from " << info.dli_fname << "+" << offset << '\n';
free(demangled);
}
else {
str << "#" << (i-skip) << " " << symbols[i] << '\n';
}
// cannot directly print to cerr when using --write-log
std::cerr << str.str();
}
free(symbols);
#else //HAVE_BACKTRACE_SYMBOLS
(void)skip;
std::cerr << "Cannot print the stacktrace because the C runtime library doesn't provide backtrace or backtrace_symbols\n";
#endif
}
#endif
void segmentation_fault_handler(int sig)
{
#if defined(FC_OS_LINUX)
(void)sig;
std::cerr << "Program received signal SIGSEGV, Segmentation fault.\n";
printBacktrace(2);
#if defined(FC_DEBUG)
abort();
#else
_exit(1);
#endif
#else
switch (sig) {
case SIGSEGV:
std::cerr << "Illegal storage access..." << '\n';
#if !defined(_DEBUG)
throw Base::AccessViolation("Illegal storage access! Please save your work under a new file name and restart the application!");
#endif
break;
case SIGABRT:
std::cerr << "Abnormal program termination..." << '\n';
#if !defined(_DEBUG)
throw Base::AbnormalProgramTermination("Break signal occurred");
#endif
break;
default:
std::cerr << "Unknown error occurred..." << '\n';
break;
}
#endif // FC_OS_LINUX
}
void unhandled_exception_handler()
{
std::cerr << "Terminating..." << '\n';
}
void unexpection_error_handler()
{
std::cerr << "Unexpected error occurred..." << '\n';
// try to throw an exception and give the user chance to save their work
#if !defined(_DEBUG)
throw Base::AbnormalProgramTermination("Unexpected error occurred! Please save your work under a new file name and restart the application!");
#else
terminate();
#endif
}
#if defined(FC_SE_TRANSLATOR) // Microsoft compiler
void my_se_translator_filter(unsigned int code, EXCEPTION_POINTERS* pExp)
{
Q_UNUSED(pExp)
switch (code)
{
case EXCEPTION_ACCESS_VIOLATION:
throw Base::AccessViolation();
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
Base::Console().error("SEH exception (%u): Division by zero\n", code);
return;
}
std::stringstream str;
str << "SEH exception of type: " << code;
// general C++ SEH exception for things we don't need to handle separately....
throw Base::RuntimeError(str.str());
}
#endif
void Application::init(int argc, char ** argv)
{
try {
// install our own new handler
#ifdef _MSC_VER // Microsoft compiler
_set_new_handler ( freecadNewHandler ); // Setup new handler
_set_new_mode( 1 ); // Re-route malloc failures to new handler !
#else // Ansi compiler
std::set_new_handler (freecadNewHandler); // ANSI new handler
#endif
// if an unexpected crash occurs we can install a handler function to
// write some additional information
#if defined (_MSC_VER) // Microsoft compiler
std::signal(SIGSEGV,segmentation_fault_handler);
std::signal(SIGABRT,segmentation_fault_handler);
std::set_terminate(unhandled_exception_handler);
::set_unexpected(unexpection_error_handler);
#elif defined(FC_OS_LINUX)
std::signal(SIGSEGV,segmentation_fault_handler);
#endif
#if defined(FC_SE_TRANSLATOR)
_set_se_translator(my_se_translator_filter);
#endif
Base::SystemHandler::installNewHandler();
Base::SystemHandler::installSegfaultHandler();
initTypes();
initConfig(argc,argv);
initApplication();
initExceptions();
}
catch (...) {
// force the log to flush
+6
View File
@@ -13,6 +13,10 @@ if(BUILD_TRACY_FRAME_PROFILER)
add_definitions(-DBUILD_TRACY_FRAME_PROFILER)
endif()
if(FREECAD_RELEASE_SEH)
add_definitions(-DHAVE_SEH)
endif(FREECAD_RELEASE_SEH)
target_include_directories(
FreeCADBase
PRIVATE
@@ -225,6 +229,7 @@ SET(FreeCADBase_CPP_SRCS
Stream.cpp
Swap.cpp
${SWIG_SRCS}
SystemHandler.cpp
Tools.cpp
Tools2D.cpp
Tools3D.cpp
@@ -291,6 +296,7 @@ SET(FreeCADBase_HPP_SRCS
Stream.h
Swap.h
${SWIG_HEADERS}
SystemHandler.h
TimeInfo.h
Tools.h
Tools2D.h
+222
View File
@@ -0,0 +1,222 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2025 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include <iostream>
#include <sstream>
#include "SystemHandler.h"
#include "Console.h"
#include "Exception.h"
#ifdef FC_OS_WIN32
# include <Windows.h>
#endif
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
# pragma warning(disable : 4535)
# if !defined(_DEBUG) && defined(HAVE_SEH)
# define FC_SE_TRANSLATOR
# endif
# include <new.h>
# include <eh.h> // VC exception handling
#else // Ansi C/C++ new handler
# include <new>
#endif
using namespace Base;
/** freecadNewHandler()
* prints an error message and throws an exception
*/
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
int __cdecl freecadNewHandler(size_t size)
{
// throw an exception
throw Base::MemoryException();
return 0;
}
#else // Ansi C/C++ new handler
static void freecadNewHandler()
{
// throw an exception
throw Base::MemoryException();
}
#endif
#if defined(FC_OS_LINUX)
# include <unistd.h>
# include <execinfo.h>
# include <dlfcn.h>
# include <cxxabi.h>
# include <cstdio>
# include <cstdlib>
# include <string>
# if HAVE_CONFIG_H
# include <config.h>
# endif // HAVE_CONFIG_H
// This function produces a stack backtrace with demangled function & method names.
static void printBacktrace([[maybe_unused]] size_t skip = 0)
{
# if defined HAVE_BACKTRACE_SYMBOLS
void* callstack[128];
size_t nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
size_t nFrames = backtrace(callstack, nMaxFrames);
char** symbols = backtrace_symbols(callstack, nFrames);
for (size_t i = skip; i < nFrames; i++) {
char* demangled = nullptr;
int status = -1;
Dl_info info;
if (dladdr(callstack[i], &info) && info.dli_sname && info.dli_fname) {
if (info.dli_sname[0] == '_') {
demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
}
}
std::stringstream str;
if (status == 0) {
void* offset = (void*)((char*)callstack[i] - (char*)info.dli_saddr);
str << "#" << (i - skip) << " " << callstack[i] << " in " << demangled << " from "
<< info.dli_fname << "+" << offset << '\n';
free(demangled);
}
else {
str << "#" << (i - skip) << " " << symbols[i] << '\n';
}
// cannot directly print to cerr when using --write-log
std::cerr << str.str();
}
free(symbols);
# else // HAVE_BACKTRACE_SYMBOLS
std::cerr << "Cannot print the stacktrace because the C runtime library doesn't provide "
"backtrace or backtrace_symbols\n";
# endif
}
#endif
void segmentation_fault_handler([[maybe_unused]] int sig)
{
#if defined(FC_OS_LINUX)
std::cerr << "Program received signal SIGSEGV, Segmentation fault.\n";
printBacktrace(2);
# if defined(FC_DEBUG)
abort();
# else
_exit(1);
# endif
#else
switch (sig) {
case SIGSEGV:
std::cerr << "Illegal storage access..." << '\n';
# if !defined(_DEBUG)
throw Base::AccessViolation(
"Illegal storage access! Please save your work under a new "
"file name and restart the application!"
);
# endif
break;
case SIGABRT:
std::cerr << "Abnormal program termination..." << '\n';
# if !defined(_DEBUG)
throw Base::AbnormalProgramTermination("Break signal occurred");
# endif
break;
default:
std::cerr << "Unknown error occurred..." << '\n';
break;
}
#endif // FC_OS_LINUX
}
#if defined(_MSC_VER)
static void unhandled_exception_handler()
{
std::cerr << "Terminating..." << '\n';
}
static void unexpection_error_handler()
{
std::cerr << "Unexpected error occurred..." << '\n';
// try to throw an exception and give the user chance to save their work
# if !defined(_DEBUG)
throw Base::AbnormalProgramTermination(
"Unexpected error occurred! Please save your work under "
"a new file name and restart the application!"
);
# else
terminate();
# endif
}
#endif
#if defined(FC_SE_TRANSLATOR) // Microsoft compiler
void my_se_translator_filter(unsigned int code, EXCEPTION_POINTERS* /*pExp*/)
{
switch (code) {
case EXCEPTION_ACCESS_VIOLATION:
throw Base::AccessViolation();
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
Base::Console().error("SEH exception (%u): Division by zero\n", code);
return;
}
std::stringstream str;
str << "SEH exception of type: " << code;
// general C++ SEH exception for things we don't need to handle separately....
throw Base::RuntimeError(str.str());
}
#endif
void SystemHandler::installNewHandler()
{
#ifdef _MSC_VER // Microsoft compiler
_set_new_handler(freecadNewHandler); // Setup new handler
_set_new_mode(1); // Re-route malloc failures to new handler !
#else // Ansi compiler
std::set_new_handler(freecadNewHandler); // ANSI new handler
#endif
}
void SystemHandler::installSegfaultHandler()
{
// if an unexpected crash occurs we can install a handler function to
// write some additional information
#if defined(_MSC_VER) // Microsoft compiler
std::signal(SIGSEGV, segmentation_fault_handler);
std::signal(SIGABRT, segmentation_fault_handler);
std::set_terminate(unhandled_exception_handler);
::set_unexpected(unexpection_error_handler);
#elif defined(FC_OS_LINUX)
std::signal(SIGSEGV, segmentation_fault_handler);
#endif
#if defined(FC_SE_TRANSLATOR)
_set_se_translator(my_se_translator_filter);
#endif
}
+38
View File
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2025 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#pragma once
#include <FCGlobal.h>
namespace Base
{
class BaseExport SystemHandler
{
public:
static void installNewHandler();
static void installSegfaultHandler();
};
} // namespace Base
+2
View File
@@ -569,6 +569,8 @@ SET(Part_SRCS
PreCompiled.h
Services.cpp
Services.h
SignalException.cpp
SignalException.h
TopoShape.cpp
TopoShape.h
TopoShapeCache.cpp
@@ -35,6 +35,7 @@
#include <TopoDS_Iterator.hxx>
#include <Precision.hxx>
#include <FuzzyHelper.h>
#include <SignalException.h>
#include <Base/Console.h>
FCBRepAlgoAPI_BooleanOperation::FCBRepAlgoAPI_BooleanOperation()
@@ -103,6 +104,7 @@ void FCBRepAlgoAPI_BooleanOperation::Build()
void FCBRepAlgoAPI_BooleanOperation::Build(const Message_ProgressRange& progressRange)
{
Part::SignalException sig;
if (progressRange.UserBreak()) {
Standard_ConstructionError::Raise("User aborted");
}
+229
View File
@@ -0,0 +1,229 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2025 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "SignalException.h"
#include <FCConfig.h>
#if defined(__GNUC__) && defined(FC_OS_LINUX)
# include <array>
# include <boost/stacktrace.hpp>
# include <stdexcept>
# include <iostream>
# include <csignal>
# include <OSD.hxx>
# include <OSD_WhoAmI.hxx>
# include <OSD_SIGHUP.hxx>
# include <OSD_SIGINT.hxx>
# include <OSD_SIGQUIT.hxx>
# include <OSD_SIGILL.hxx>
# include <OSD_SIGKILL.hxx>
# include <OSD_SIGBUS.hxx>
# include <OSD_SIGSEGV.hxx>
# include <OSD_SIGSYS.hxx>
# include <Standard.hxx>
# include <Standard_NumericError.hxx>
# include <Standard_ErrorHandler.hxx>
# include <Standard_Assert.hxx>
#endif
#include <Base/SystemHandler.h>
using namespace Part;
// NOLINTBEGIN(concurrency-mt-unsafe, cppcoreguidelines-pro-type-member-init)
#if defined(__GNUC__) && defined(FC_OS_LINUX)
static OSD_SignalMode OSD_WasSetSignal = OSD_SignalMode_AsIs; // NOLINT
static void SegvHandler(const int theSignal, siginfo_t* theSigInfo, const Standard_Address /*theContext*/)
{
std::cerr << "\nStacktrace:" << std::endl;
std::cerr << "SIGSEGV signal raised: " << theSignal << std::endl;
std::cerr << boost::stacktrace::stacktrace() << std::endl;
std::cerr << "\n" << std::endl;
if (theSigInfo != nullptr) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGSEGV);
sigprocmask(SIG_UNBLOCK, &set, nullptr);
OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
}
exit(SIGSEGV);
}
static void throw_exc(const int theSignal, siginfo_t* /*theSigInfo*/, const Standard_Address /*theContext*/)
{
struct sigaction oldact;
struct sigaction act;
// re-install the signal
if (!sigaction(theSignal, nullptr, &oldact)) {
if (sigaction(theSignal, &oldact, &act)) {
perror("sigaction");
}
}
else {
perror("sigaction");
}
sigset_t set;
sigemptyset(&set);
switch (theSignal) {
case SIGHUP:
OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
exit(SIGHUP);
break;
case SIGINT:
// For safe handling of Control-C as stop event, arm a variable but do not
// generate longjump (we are out of context anyway)
OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump();
exit(SIGINT);
break;
case SIGQUIT:
OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
exit(SIGQUIT);
break;
case SIGILL:
OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
exit(SIGILL);
break;
case SIGKILL:
OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
exit(SIGKILL);
break;
case SIGBUS:
sigaddset(&set, SIGBUS);
sigprocmask(SIG_UNBLOCK, &set, nullptr);
OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
exit(SIGBUS);
break;
case SIGSEGV:
OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
exit(SIGSEGV);
break;
# ifdef SIGSYS
case SIGSYS:
OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
exit(SIGSYS);
break;
# endif
case SIGFPE:
sigaddset(&set, SIGFPE);
sigprocmask(SIG_UNBLOCK, &set, nullptr);
OSD::SetFloatingSignal(Standard_True);
Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
break;
default:
break;
}
}
static void setSignal(OSD_SignalMode theSignalMode)
{
OSD_WasSetSignal = theSignalMode;
if (theSignalMode == OSD_SignalMode_AsIs) {
return; // nothing to be done with signal handlers
}
// Prepare signal descriptors
struct sigaction anActSet;
struct sigaction anActDfl;
struct sigaction anActOld;
sigemptyset(&anActSet.sa_mask);
sigemptyset(&anActDfl.sa_mask);
sigemptyset(&anActOld.sa_mask);
# ifdef SA_RESTART
anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = SA_RESTART;
# else
anActSet.sa_flags = anActDfl.sa_flags = anActOld.sa_flags = 0;
# endif
# ifdef SA_SIGINFO
anActSet.sa_flags = anActSet.sa_flags | SA_SIGINFO;
anActSet.sa_sigaction = throw_exc;
# else
anActSet.sa_handler = throw_exc;
# endif
anActDfl.sa_handler = SIG_DFL;
// Set signal handlers; NB: SIGSEGV must be the last one!
const int NBSIG = 8;
constexpr static std::array<int, NBSIG> aSignalTypes
= {SIGFPE, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSYS, SIGSEGV};
for (int aSignalType : aSignalTypes) {
// SIGSEGV has special handler
if (aSignalType == SIGSEGV) {
# ifdef SA_SIGINFO
anActSet.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
# else
anActSet.sa_handler = /*(SIG_PFV)*/ SegvHandler;
# endif
}
// set handler according to specified mode and current handler
int retcode = -1;
if (theSignalMode == OSD_SignalMode_Set || theSignalMode == OSD_SignalMode_SetUnhandled) {
retcode = sigaction(aSignalType, &anActSet, &anActOld);
}
else if (theSignalMode == OSD_SignalMode_Unset) {
retcode = sigaction(aSignalType, &anActDfl, &anActOld);
}
if (theSignalMode == OSD_SignalMode_SetUnhandled && retcode == 0
&& anActOld.sa_handler != SIG_DFL) {
struct sigaction anActOld2;
sigemptyset(&anActOld2.sa_mask);
retcode = sigaction(aSignalType, &anActOld, &anActOld2);
}
Standard_ASSERT(
retcode == 0,
"sigaction() failed",
std::cout << "OSD::SetSignal(): sigaction() failed for " << aSignalType << std::endl
);
}
}
#endif
// ----------------------------------------------------------------------------
#if defined(__GNUC__) && defined(FC_OS_LINUX)
static OSD_SignalMode currentSignalMode = OSD_SignalMode_Unset; // NOLINT
#endif
SignalException::SignalException()
{
#if defined(__GNUC__) && defined(FC_OS_LINUX)
if (currentSignalMode == OSD_SignalMode_Unset) {
currentSignalMode = OSD_SignalMode_Set;
setSignal(currentSignalMode);
enabled = true;
}
#endif
}
SignalException::~SignalException()
{
#if defined(__GNUC__) && defined(FC_OS_LINUX)
if (enabled && currentSignalMode == OSD_SignalMode_Set) {
currentSignalMode = OSD_SignalMode_Unset;
setSignal(currentSignalMode);
// this is the default handler
Base::SystemHandler::installSegfaultHandler();
}
#endif
}
// NOLINTEND(concurrency-mt-unsafe, cppcoreguidelines-pro-type-member-init)
+46
View File
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2025 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#pragma once
#include <Mod/Part/PartGlobal.h>
namespace Part
{
class PartExport SignalException
{
public:
SignalException();
~SignalException();
SignalException(const SignalException&) = default;
SignalException(SignalException&&) = default;
SignalException& operator=(const SignalException&) = default;
SignalException& operator=(SignalException&&) = default;
private:
bool enabled {false};
};
} // namespace Part