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 -------------------------------------------------------------------------------
11 License
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 
57 bool Foam::sigFpe::switchFpe_(Foam::debug::optimisationSwitch("trapFpe", 0));
58 bool Foam::sigFpe::switchNan_(Foam::debug::optimisationSwitch("setNaN", 0));
59 
60 bool Foam::sigFpe::sigActive_ = false;
61 bool 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
68 static 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__
83 extern "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 
102 void* 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 
118 void 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)
128  #endif // (__linux__ && __GNUC__) || __APPLE__
129 }
130 
131 
132 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
135 {
136  set(false);
137 }
138 
139 
141 :
142  wasActive_(sigFpe::active())
143 {
144  if (wasActive_)
145  {
147  }
148 }
149 
150 
151 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
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 
178 {
179  return isTrue("FOAM_SIGFPE", switchFpe_);
180 }
181 
182 
183 void 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 
241 void 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 
277 void Foam::sigFpe::fillNan(UList<scalar>& list)
278 {
279  list = std::numeric_limits<scalar>::signaling_NaN();
280 }
281 
282 
283 // ************************************************************************* //
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
bool good() const noexcept
True if the Switch represents a valid enumeration.
Definition: Switch.C:296
static void setHandler(const char *what, int sigNum, void(*handler)(int))
Definition: signalMacros.C:54
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
static bool nanActive()
True if NaN memory initialisation is currently active.
Definition: sigFpe.H:145
static void unset(bool verbose=false)
Deactivate SIGFPE signal handler and NaN memory initialisation.
Definition: sigFpe.C:234
static void shutdown()
Simple shutdown (finalize) of JobInfo.
Definition: JobInfo.C:94
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, any/none. Also accepts 0/1 as a string and shortcuts t/f, y/n.
Definition: Switch.H:77
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:292
ignore()
Constructor deactivates any previously active SIGFPE handler.
Definition: sigFpe.C:133
~sigFpe()
Destructor calls unset() to deactivate the FPE signal handler as required.
Definition: sigFpe.C:146
static bool isTrue(const char *envName, bool deflt)
Definition: sigFpe.C:61
static void set(bool verbose=false)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:176
static void resetHandler(const char *what, int sigNum)
Definition: signalMacros.C:42
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Set up trapping for floating point exceptions (signal FPE).
Definition: sigFpe.H:69
static void printStack(Ostream &os)
Helper function to print a stack.
File-local code for setting/resetting signal handlers.
static void fillNan(UList< scalar > &list)
Fill data block with NaN values.
Definition: sigFpe.C:270
~ignore()
Destructor restores the original state of SIGFPE handler.
Definition: sigFpe.C:152
errorManip< error > abort(error &err)
Definition: errorManip.H:139
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition: debug.C:234
static bool requested()
Check if SIGFPE signals handler is to be enabled.
Definition: sigFpe.C:170
messageStream Info
Information stream (stdout output on master, null elsewhere)
sigFpe()
Constructor calls set() to activate the FPE signal handler if it was was not previously activate and ...
Definition: sigFpe.C:127
void restore()
Restore the original state of SIGFPE handler.
Definition: sigFpe.C:160
static Switch find(const std::string &str)
Find switchType for the given string, returning as a Switch that can be tested for good() or bad()...
Definition: Switch.C:147