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-2020 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 "Switch.H"
35 #include "UList.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.signalEnd(); // Update jobInfo file
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 
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 // ************************************************************************* //
Foam::sigFpe::set
static void set(bool verbose=false)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:148
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::Switch
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:76
Foam::error::printStack
static void printStack(Ostream &os)
Helper function to print a stack.
Definition: dummyPrintStack.C:36
IOstreams.H
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
feexceptErsatz.H
Foam::resetHandler
static void resetHandler(const char *what, int sigNum)
Definition: signalMacros.C:46
Foam::sigFpe::nanActive
static bool nanActive()
True if NaN memory initialisation is currently active.
Definition: sigFpe.H:126
Foam::sigFpe::ignore::ignore
ignore()
Constructor deactivates any previously active SIGFPE handler.
Definition: sigFpe.C:105
Foam::sigFpe::unset
static void unset(bool verbose=false)
Deactivate SIGFPE signal handler and NaN memory initialisation.
Definition: sigFpe.C:204
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::Switch::good
bool good() const noexcept
True if the Switch represents a valid enumeration.
Definition: Switch.C:300
Foam::Switch::find
static Switch find(const std::string &str)
Definition: Switch.C:151
Foam::getEnv
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: MSwindows.C:371
error.H
Foam::sigFpe::fillNan
static void fillNan(UList< scalar > &list)
Fill data block with NaN values.
Definition: sigFpe.C:225
isTrue
static bool isTrue(const char *envName, bool deflt)
Definition: sigFpe.C:68
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
signalMacros.C
File-local code for setting/resetting signal handlers.
Switch.H
Foam::sigFpe::ignore::~ignore
~ignore()
Destructor restores the original state of SIGFPE handler.
Definition: sigFpe.C:124
Foam::debug::optimisationSwitch
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition: debug.C:237
Foam::FatalError
error FatalError
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
sigFpe.H
Foam::sigFpe::requested
static bool requested()
Check if SIGFPE signals handler is to be enabled.
Definition: sigFpe.C:142
Foam::jobInfo
JobInfo jobInfo
Definition: JobInfo.C:49
Foam::Perr
prefixOSstream Perr
An Ostream wrapper for parallel output to std::cerr.
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::setHandler
static void setHandler(const char *what, int sigNum, void(*handler)(int))
Definition: signalMacros.C:61
UList.H
Foam::sigFpe::ignore::restore
void restore()
Restore the original state of SIGFPE handler.
Definition: sigFpe.C:132
JobInfo.H
Foam::JobInfo::signalEnd
void signalEnd() const
Update job info and relocate the file from running to finished.
Definition: JobInfo.C:184
Foam::sigFpe::sigFpe
sigFpe()
Definition: sigFpe.C:99
Foam::sigFpe::~sigFpe
~sigFpe()
Definition: sigFpe.C:118