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