sigFpe.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2015 OpenFOAM Foundation
9 Copyright (C) 2016-2021 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "sigFpe.H"
30#include "error.H"
31#include "JobInfo.H"
32#include "OSspecific.H"
33#include "IOstreams.H"
34#include "List.H"
35#include "Switch.H"
36
37#include <limits>
38
39#if defined(__linux__) && defined(__GNUC__)
40 #ifndef __USE_GNU
41 #define __USE_GNU // To use feenableexcept()
42 #endif
43 #include <fenv.h>
44 #include <malloc.h>
45#endif
46
47#ifdef __APPLE__
48 #include "feexceptErsatz.H"
49#endif
50
51// File-local functions
52#include "signalMacros.C"
53
54
55// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
56
57bool Foam::sigFpe::switchFpe_(Foam::debug::optimisationSwitch("trapFpe", 0));
58bool Foam::sigFpe::switchNan_(Foam::debug::optimisationSwitch("setNaN", 0));
59
60bool Foam::sigFpe::sigActive_ = false;
61bool Foam::sigFpe::nanActive_ = false;
62
63
64// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
65
66// Can turn on/off via env variable containing a bool (true|false|on|off ...)
67// or by the specified flag
68static bool isTrue(const char* envName, bool deflt)
69{
71
72 if (sw.good())
73 {
74 return static_cast<bool>(sw);
75 }
76
77 // Env was not set or did not contain a valid bool value
78 return deflt;
79}
80
81
82#ifdef __linux__
83extern "C"
84{
85 extern void* __libc_malloc(size_t size);
86
87 // Override the GLIBC malloc to support mallocNan
88 void* malloc(size_t size)
89 {
91 {
92 return Foam::sigFpe::mallocNan(size);
93 }
94 else
95 {
96 return __libc_malloc(size);
97 }
98 }
99}
100
101
102void* Foam::sigFpe::mallocNan(size_t size)
103{
104 // Call the low-level GLIBC malloc function
105 void* result = __libc_malloc(size);
106
107 // Initialize to signalling NaN
108 UList<scalar> list(reinterpret_cast<scalar*>(result), size/sizeof(scalar));
109 sigFpe::fillNan(list);
110
111 return result;
112}
113#endif // __linux__
114
115
116// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
117
118void Foam::sigFpe::sigHandler(int)
119{
120 #if (defined(__linux__) && defined(__GNUC__)) || defined(__APPLE__)
121
122 resetHandler("SIGFPE", SIGFPE);
123
124 JobInfo::shutdown(); // From running -> finished
126 ::raise(SIGFPE); // Throw signal (to old handler)
127
128 #endif // (__linux__ && __GNUC__) || __APPLE__
129}
130
131
132// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
133
135{
136 set(false);
137}
138
139
141:
142 wasActive_(sigFpe::active())
143{
144 if (wasActive_)
145 {
146 sigFpe::unset();
147 }
148}
149
150
151// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
152
154{
155 unset(false);
156}
157
158
160{
161 restore();
162}
163
164
165// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
166
168{
169 if (wasActive_)
170 {
171 sigFpe::set();
172 }
173 wasActive_ = false;
174}
175
176
178{
179 return isTrue("FOAM_SIGFPE", switchFpe_);
180}
181
182
183void Foam::sigFpe::set(bool verbose)
184{
185 if (!sigActive_ && requested())
186 {
187 #if (defined(__linux__) && defined(__GNUC__)) || defined(__APPLE__)
188
189 feenableexcept
190 (
191 FE_DIVBYZERO
192 | FE_INVALID
193 | FE_OVERFLOW
194 );
195
196 setHandler("SIGFPE", SIGFPE, sigHandler);
197
198 sigActive_ = true;
199 #endif
200
201 if (verbose)
202 {
203 Info<< "trapFpe: Floating point exception trapping ";
204
205 if (sigActive_)
206 {
207 Info<< "enabled (FOAM_SIGFPE)." << endl;
208 }
209 else
210 {
211 Info<< "- not supported on this platform" << endl;
212 }
213 }
214 }
215
216
217 nanActive_ = false;
218 if (isTrue("FOAM_SETNAN", switchNan_))
219 {
220 #ifdef __linux__
221 nanActive_ = true;
222 #endif
223
224 if (verbose)
225 {
226 Info<< "setNaN : Initialise allocated memory to NaN ";
227
228 if (nanActive_)
229 {
230 Info<< "enabled (FOAM_SETNAN)." << endl;
231 }
232 else
233 {
234 Info<< " - not supported on this platform" << endl;
235 }
236 }
237 }
238}
239
240
241void Foam::sigFpe::unset(bool verbose)
242{
243 #if (defined(__linux__) && defined(__GNUC__)) || defined(__APPLE__)
244 if (sigActive_)
245 {
246 if (verbose)
247 {
248 Info<< "sigFpe : Disabling floating point exception trapping"
249 << endl;
250 }
251
252 resetHandler("SIGFPE", SIGFPE);
253
254 // Reset exception raising
255 const int oldExcept = fedisableexcept
256 (
257 FE_DIVBYZERO
258 | FE_INVALID
259 | FE_OVERFLOW
260 );
261
262 if (oldExcept == -1)
263 {
265 << "Cannot reset SIGFPE trapping"
266 << abort(FatalError);
267 }
268
269 sigActive_ = false;
270 }
271 #endif
272
273 nanActive_ = false;
274}
275
276
277void Foam::sigFpe::fillNan(UList<scalar>& list)
278{
279 list = std::numeric_limits<scalar>::signaling_NaN();
280}
281
282
283// ************************************************************************* //
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
static bool isTrue(const char *envName, bool deflt)
Definition: sigFpe.C:70
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
static bool isTrue(const char *envName, bool deflt)
Definition: sigFpe.C:68
File-local code for setting/resetting signal handlers.
static void shutdown()
Simple shutdown (finalize) of JobInfo.
Definition: JobInfo.C:98
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:78
bool good() const noexcept
True if the Switch represents a valid enumeration.
Definition: Switch.C:300
static Switch find(const std::string &str)
Definition: Switch.C:151
static void printStack(Ostream &os)
Helper function to print a stack.
ignore()
Constructor deactivates any previously active SIGFPE handler.
Definition: sigFpe.C:105
~ignore()
Destructor restores the original state of SIGFPE handler.
Definition: sigFpe.C:124
void restore()
Restore the original state of SIGFPE handler.
Definition: sigFpe.C:132
static void fillNan(UList< scalar > &list)
Fill data block with NaN values.
Definition: sigFpe.C:225
static bool nanActive()
True if NaN memory initialisation is currently active.
Definition: sigFpe.H:126
static void unset(bool verbose=false)
Deactivate SIGFPE signal handler and NaN memory initialisation.
Definition: sigFpe.C:204
static bool requested()
Check if SIGFPE signals handler is to be enabled.
Definition: sigFpe.C:142
static const triad unset
Definition: triad.H:97
bool set() const
Are all the vector set.
Definition: triadI.H:76
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
void set(List< bool > &bools, const labelUList &locations)
Set the listed locations (assign 'true').
Definition: BitOps.C:38
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition: debug.C:237
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: MSwindows.C:371
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
static void setHandler(const char *what, int sigNum, void(*handler)(int))
Definition: signalMacros.C:61
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
errorManip< error > abort(error &err)
Definition: errorManip.H:144
error FatalError
static void resetHandler(const char *what, int sigNum)
Definition: signalMacros.C:46