sigFpe.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "sigFpe.H"
27 #include "error.H"
28 #include "jobInfo.H"
29 #include "OSspecific.H"
30 #include "IOstreams.H"
31 
32 #ifdef LINUX_GNUC
33  #ifndef __USE_GNU
34  #define __USE_GNU
35  #endif
36  #include <fenv.h>
37  #include <malloc.h>
38 #endif
39 
40 #include <limits>
41 
42 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 
44 struct sigaction Foam::sigFpe::oldAction_;
45 
46 void Foam::sigFpe::fillNan(UList<scalar>& lst)
47 {
48  lst = std::numeric_limits<scalar>::signaling_NaN();
49 }
50 
52 
53 
54 #ifdef LINUX
55 extern "C"
56 {
57  extern void* __libc_malloc(size_t size);
58 
59  // Override the GLIBC malloc to support mallocNan
60  void* malloc(size_t size)
61  {
63  {
64  return Foam::sigFpe::mallocNan(size);
65  }
66  else
67  {
68  return __libc_malloc(size);
69  }
70  }
71 }
72 
73 void* Foam::sigFpe::mallocNan(size_t size)
74 {
75  // Call the low-level GLIBC malloc function
76  void * result = __libc_malloc(size);
77 
78  // Initialise to signalling NaN
79  UList<scalar> lst(reinterpret_cast<scalar*>(result), size/sizeof(scalar));
80  sigFpe::fillNan(lst);
81 
82  return result;
83 }
84 #endif
85 
86 
87 #ifdef LINUX_GNUC
88 void Foam::sigFpe::sigHandler(int)
89 {
90  // Reset old handling
91  if (sigaction(SIGFPE, &oldAction_, nullptr) < 0)
92  {
94  << "Cannot reset SIGFPE trapping"
95  << abort(FatalError);
96  }
97 
98  // Update jobInfo file
100 
102 
103  // Throw signal (to old handler)
104  raise(SIGFPE);
105 }
106 #endif
107 
108 
109 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
110 
112 {
113  oldAction_.sa_handler = nullptr;
114 }
115 
116 
117 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
118 
120 {
121  if (env("FOAM_SIGFPE"))
122  {
123  #ifdef LINUX_GNUC
124  // Reset signal
125  if
126  (
127  oldAction_.sa_handler
128  && sigaction(SIGFPE, &oldAction_, nullptr) < 0
129  )
130  {
132  << "Cannot reset SIGFPE trapping"
133  << abort(FatalError);
134  }
135  #endif
136  }
137 
138  if (env("FOAM_SETNAN"))
139  {
140  #ifdef LINUX
141  // Disable initialisation to NaN
142  mallocNanActive_ = false;
143  #endif
144  }
145 }
146 
147 
148 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
149 
150 void Foam::sigFpe::set(const bool verbose)
151 {
152  if (oldAction_.sa_handler)
153  {
155  << "Cannot call sigFpe::set() more than once"
156  << abort(FatalError);
157  }
158 
159  if (env("FOAM_SIGFPE"))
160  {
161  bool supported = false;
162 
163  #ifdef LINUX_GNUC
164  supported = true;
165 
166  feenableexcept
167  (
168  FE_DIVBYZERO
169  | FE_INVALID
170  | FE_OVERFLOW
171  );
172 
173  struct sigaction newAction;
174  newAction.sa_handler = sigHandler;
175  newAction.sa_flags = SA_NODEFER;
176  sigemptyset(&newAction.sa_mask);
177  if (sigaction(SIGFPE, &newAction, &oldAction_) < 0)
178  {
180  << "Cannot set SIGFPE trapping"
181  << abort(FatalError);
182  }
183  #endif
184 
185  if (verbose)
186  {
187  if (supported)
188  {
189  Info<< "sigFpe : Enabling floating point exception trapping"
190  << " (FOAM_SIGFPE)." << endl;
191  }
192  else
193  {
194  Info<< "sigFpe : Floating point exception trapping"
195  << " - not supported on this platform" << endl;
196  }
197  }
198  }
199 
200 
201  if (env("FOAM_SETNAN"))
202  {
203  #ifdef LINUX
204  mallocNanActive_ = true;
205  #endif
206 
207  if (verbose)
208  {
209  if (mallocNanActive_)
210  {
211  Info<< "SetNaN : Initialising allocated memory to NaN"
212  << " (FOAM_SETNAN)." << endl;
213  }
214  else
215  {
216  Info<< "SetNaN : Initialise allocated memory to NaN"
217  << " - not supported on this platform" << endl;
218  }
219  }
220  }
221 }
222 
223 
224 // ************************************************************************* //
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...
static void printStack(Ostream &)
Helper function to print a stack.
void signalEnd() const
Definition: jobInfo.C:210
~sigFpe()
Destructor.
Definition: sigFpe.C:119
static bool mallocNanActive_
Flag to indicate mallocNan is enabled.
Definition: sigFpe.H:103
static void fillNan(UList< scalar > &)
Fill block of data with NaN.
Definition: sigFpe.C:46
sigFpe()
Construct null.
Definition: sigFpe.C:111
void set(const bool verbose)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:150
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
Namespace for OpenFOAM.
prefixOSstream Perr(cerr, "Perr")
Definition: IOstreams.H:54
bool env(const word &)
Return true if environment variable of given name is defined.
Definition: POSIX.C:91
jobInfo jobInfo_
Definition: jobInfo.C:44
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
errorManip< error > abort(error &err)
Definition: errorManip.H:131
messageStream Info
error FatalError