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-2023 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 "UList.H"
35 #include "Switch.H"
36 #include <algorithm>
37 #include <limits>
38 
39 // File-local functions
40 #include "signalMacros.C"
41 
42 #if defined(__linux__) && defined(__GNUC__)
43  #ifndef __USE_GNU
44  #define __USE_GNU // To use feenableexcept()
45  #endif
46  #include <fenv.h>
47  #include <malloc.h>
48 #endif
49 
50 // Special handling for APPLE
51 #ifdef __APPLE__
52  #include "feexceptErsatz.H"
53 #endif
54 
55 
56 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
57 
58 bool Foam::sigFpe::switchFpe_(Foam::debug::optimisationSwitch("trapFpe", 0));
59 bool Foam::sigFpe::switchNan_(Foam::debug::optimisationSwitch("setNaN", 0));
60 
61 bool Foam::sigFpe::sigActive_ = false;
62 bool Foam::sigFpe::nanActive_ = false;
63 
64 
65 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
66 
67 // Can turn on/off via env variable containing a bool (true|false|on|off ...)
68 // or by the specified flag
69 static bool isTrue(const char* envName, bool deflt)
70 {
72 
73  if (sw.good())
74  {
75  return static_cast<bool>(sw);
76  }
77 
78  // Env was not set or did not contain a valid bool value
79  return deflt;
80 }
81 
82 
83 #ifdef __linux__
84 extern "C"
85 {
86  extern void* __libc_malloc(size_t size);
87 
88  // Override the GLIBC malloc to support filling with NaN
89  void* malloc(size_t size)
90  {
91  // Call the low-level GLIBC malloc function
92  void* ptr = __libc_malloc(size);
93 
95  {
96  // Fill with signaling_NaN
97  const auto val = std::numeric_limits<Foam::scalar>::signaling_NaN();
98 
99  // Can dispatch with
100  // - std::execution::parallel_unsequenced_policy
101  // - std::execution::unsequenced_policy
102  std::fill_n
103  (
104  reinterpret_cast<Foam::scalar*>(ptr),
105  (size/sizeof(Foam::scalar)),
106  val
107  );
108  }
109 
110  return ptr;
111  }
112 } // End extern C
113 
114 #endif // __linux__
115 
116 
117 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
118 
119 void Foam::sigFpe::sigHandler(int)
120 {
121  #if (defined(__linux__) && defined(__GNUC__)) || defined(__APPLE__)
122 
123  resetHandler("SIGFPE", SIGFPE);
124 
125  JobInfo::shutdown(); // From running -> finished
127  ::raise(SIGFPE); // Throw signal (to old handler)
129  #endif // (__linux__ && __GNUC__) || __APPLE__
130 }
131 
132 
133 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
134 
136 {
137  set(false); // false = non-verbose
138 }
139 
140 
141 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
142 
144 {
145  unset(false); // false = non-verbose
146 }
147 
148 
149 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
152 {
153  return isTrue("FOAM_SIGFPE", switchFpe_);
154 }
155 
156 
157 void Foam::sigFpe::set(bool verbose)
158 {
159  if (!sigActive_ && requested())
160  {
161  #if (defined(__linux__) && defined(__GNUC__)) || defined(__APPLE__)
162 
163  feenableexcept
164  (
165  FE_DIVBYZERO
166  | FE_INVALID
167  | FE_OVERFLOW
168  );
169 
170  setHandler("SIGFPE", SIGFPE, sigHandler);
171 
172  sigActive_ = true;
173  #endif
174 
175  if (verbose)
176  {
177  Info<< "trapFpe: Floating point exception trapping ";
178 
179  if (sigActive_)
180  {
181  Info<< "enabled (FOAM_SIGFPE)." << endl;
182  }
183  else
184  {
185  Info<< "- not supported on this platform" << endl;
186  }
187  }
188  }
189 
190 
191  nanActive_ = false;
192  if (isTrue("FOAM_SETNAN", switchNan_))
193  {
194  #ifdef __linux__
195  nanActive_ = true;
196  #endif
197 
198  if (verbose)
199  {
200  Info<< "setNaN : Fill allocated memory with NaN ";
201 
202  if (nanActive_)
203  {
204  Info<< "enabled (FOAM_SETNAN)." << endl;
205  }
206  else
207  {
208  Info<< " - not supported on this platform" << endl;
209  }
210  }
211  }
212 }
213 
214 
215 void Foam::sigFpe::unset(bool verbose)
216 {
217  #if (defined(__linux__) && defined(__GNUC__)) || defined(__APPLE__)
218  if (sigActive_)
219  {
220  if (verbose)
221  {
222  Info<< "sigFpe : Disabling floating point exception trapping"
223  << endl;
224  }
225 
226  resetHandler("SIGFPE", SIGFPE);
227 
228  // Reset exception raising
229  const int oldExcept = fedisableexcept
230  (
231  FE_DIVBYZERO
232  | FE_INVALID
233  | FE_OVERFLOW
234  );
235 
236  if (oldExcept == -1)
237  {
239  << "Cannot reset SIGFPE trapping"
240  << abort(FatalError);
241  }
242 
243  sigActive_ = false;
244  }
245  #endif
246 
247  nanActive_ = false;
248 }
249 
250 
251 void Foam::sigFpe::fillNan(char* buf, size_t count)
252 {
253  if (!buf || !count) return;
254 
255  // Fill with signaling_NaN
256  const auto val = std::numeric_limits<scalar>::signaling_NaN();
257 
258  // Can dispatch with
259  // - std::execution::parallel_unsequenced_policy
260  // - std::execution::unsequenced_policy
261  std::fill_n
262  (
263  reinterpret_cast<scalar*>(buf), (count/sizeof(scalar)), val
264  );
265 }
266 
267 
269 {
270  if (list.empty()) return;
271 
272  // Fill with signaling_NaN
273  const auto val = std::numeric_limits<scalar>::signaling_NaN();
274 
275  // Can dispatch with
276  // - std::execution::parallel_unsequenced_policy
277  // - std::execution::unsequenced_policy
278  std::fill_n
279  (
280  list.data(), list.size(), val
281  );
282 }
283 
284 
285 // ************************************************************************* //
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
bool good() const noexcept
True if the Switch represents a valid enumeration.
Definition: Switch.C:307
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:598
static void unset(bool verbose=false)
Deactivate SIGFPE handler and NaN memory initialisation.
Definition: sigFpe.C:208
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition: UListI.H:272
static void shutdown()
Simple shutdown (finalize) of JobInfo.
Definition: JobInfo.C:94
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
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:339
~sigFpe()
Destructor calls unset() to deactivate the FPE signal handler as required.
Definition: sigFpe.C:136
static bool isTrue(const char *envName, bool deflt)
Definition: sigFpe.C:62
static void set(bool verbose=false)
Activate SIGFPE handler when FOAM_SIGFPE is enabled. Activate fill memory with signaling_NaN when FOA...
Definition: sigFpe.C:150
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...
void unset(List< bool > &bools, const labelUList &locations)
Unset the listed locations (assign &#39;false&#39;).
Definition: BitOps.C:99
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
File-local code for setting/resetting signal handlers.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition: debug.C:234
static bool nanActive() noexcept
True if NaN memory initialisation is currently active.
Definition: sigFpe.H:143
static void fillNan(char *buf, size_t count)
Fill data block with signaling_NaN values.
Definition: sigFpe.C:244
static bool requested()
Check if SIGFPE signals handler is to be enabled.
Definition: sigFpe.C:144
messageStream Info
Information stream (stdout output on master, null elsewhere)
static void printStack(Ostream &os, int size=-1)
Helper function to print a stack, with optional upper limit.
sigFpe()
Constructor calls set() to activate the FPE signal handler if it was was not previously activate and ...
Definition: sigFpe.C:128
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