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 | Copyright (C) 2011-2016 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 #elif defined(sgiN32) || defined(sgiN32Gcc)
39  #include <sigfpe.h>
40 #endif
41 
42 #include <limits>
43 
44 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 
46 struct sigaction Foam::sigFpe::oldAction_;
47 
48 void Foam::sigFpe::fillNan(UList<scalar>& lst)
49 {
50  lst = std::numeric_limits<scalar>::signaling_NaN();
51 }
52 
54 
55 
56 #ifdef LINUX
57 extern "C"
58 {
59  extern void* __libc_malloc(size_t size);
60 
61  // Override the GLIBC malloc to support mallocNan
62  void* malloc(size_t size)
63  {
65  {
66  return Foam::sigFpe::mallocNan(size);
67  }
68  else
69  {
70  return __libc_malloc(size);
71  }
72  }
73 }
74 
75 void* Foam::sigFpe::mallocNan(size_t size)
76 {
77  // Call the low-level GLIBC malloc function
78  void * result = __libc_malloc(size);
79 
80  // Initialize to signalling NaN
81  UList<scalar> lst(reinterpret_cast<scalar*>(result), size/sizeof(scalar));
82  sigFpe::fillNan(lst);
83 
84  return result;
85 }
86 #endif
87 
88 
89 #ifdef LINUX_GNUC
90 void Foam::sigFpe::sigHandler(int)
91 {
92  // Reset old handling
93  if (sigaction(SIGFPE, &oldAction_, nullptr) < 0)
94  {
96  << "Cannot reset SIGFPE trapping"
97  << abort(FatalError);
98  }
99 
100  // Update jobInfo file
101  jobInfo.signalEnd();
102 
103  error::printStack(Perr);
104 
105  // Throw signal (to old handler)
106  raise(SIGFPE);
107 }
108 #endif
109 
110 
111 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
112 
114 {
115  oldAction_.sa_handler = nullptr;
116 }
117 
118 
119 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
120 
122 {
123  if (env("FOAM_SIGFPE"))
124  {
125  #ifdef LINUX_GNUC
126  // Reset signal
127  if
128  (
129  oldAction_.sa_handler
130  && sigaction(SIGFPE, &oldAction_, nullptr) < 0
131  )
132  {
134  << "Cannot reset SIGFPE trapping"
135  << abort(FatalError);
136  }
137  #endif
138  }
139 
140  if (env("FOAM_SETNAN"))
141  {
142  #ifdef LINUX
143  // Disable initialization to NaN
144  mallocNanActive_ = false;
145  #endif
146  }
147 }
148 
149 
150 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
151 
152 void Foam::sigFpe::set(const bool verbose)
153 {
154  if (oldAction_.sa_handler)
155  {
157  << "Cannot call sigFpe::set() more than once"
158  << abort(FatalError);
159  }
160 
161  if (env("FOAM_SIGFPE"))
162  {
163  bool supported = false;
164 
165  #ifdef LINUX_GNUC
166  supported = true;
167 
168  feenableexcept
169  (
170  FE_DIVBYZERO
171  | FE_INVALID
172  | FE_OVERFLOW
173  );
174 
175  struct sigaction newAction;
176  newAction.sa_handler = sigHandler;
177  newAction.sa_flags = SA_NODEFER;
178  sigemptyset(&newAction.sa_mask);
179  if (sigaction(SIGFPE, &newAction, &oldAction_) < 0)
180  {
182  << "Cannot set SIGFPE trapping"
183  << abort(FatalError);
184  }
185 
186 
187  #elif defined(sgiN32) || defined(sgiN32Gcc)
188  supported = true;
189 
190  sigfpe_[_DIVZERO].abort=1;
191  sigfpe_[_OVERFL].abort=1;
192  sigfpe_[_INVALID].abort=1;
193 
194  sigfpe_[_DIVZERO].trace=1;
195  sigfpe_[_OVERFL].trace=1;
196  sigfpe_[_INVALID].trace=1;
197 
198  handle_sigfpes
199  (
200  _ON,
201  _EN_DIVZERO
202  | _EN_INVALID
203  | _EN_OVERFL,
204  0,
205  _ABORT_ON_ERROR,
206  nullptr
207  );
208  #endif
209 
210 
211  if (verbose)
212  {
213  if (supported)
214  {
215  Info<< "sigFpe : Enabling floating point exception trapping"
216  << " (FOAM_SIGFPE)." << endl;
217  }
218  else
219  {
220  Info<< "sigFpe : Floating point exception trapping"
221  << " - not supported on this platform" << endl;
222  }
223  }
224  }
225 
226 
227  if (env("FOAM_SETNAN"))
228  {
229  #ifdef LINUX
230  mallocNanActive_ = true;
231  #endif
232 
233  if (verbose)
234  {
235  if (mallocNanActive_)
236  {
237  Info<< "SetNaN : Initialising allocated memory to NaN"
238  << " (FOAM_SETNAN)." << endl;
239  }
240  else
241  {
242  Info<< "SetNaN : Initialise allocated memory to NaN"
243  << " - not supported on this platform" << endl;
244  }
245  }
246  }
247 }
248 
249 
250 // ************************************************************************* //
void signalEnd() const
Definition: JobInfo.C:175
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
~sigFpe()
Destructor.
Definition: sigFpe.C:121
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 fillNan(UList< scalar > &)
Fill block of data with NaN.
Definition: sigFpe.C:48
errorManip< error > abort(error &err)
Definition: errorManip.H:131
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:61
prefixOSstream Perr(cerr, "Perr")
Definition: IOstreams.H:54
JobInfo jobInfo
Definition: JobInfo.C:35
void set(const bool verbose)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:152
messageStream Info
static bool mallocNanActive_
Flag to indicate mallocNan is enabled.
Definition: sigFpe.H:103
bool env(const word &)
Return true if environment variable of given name is defined.
Definition: POSIX.C:98
sigFpe()
Construct null.
Definition: sigFpe.C:113
Namespace for OpenFOAM.