xref: /petsc/src/sys/error/signal.c (revision fbfcfee5110779e3d6a9465ca0a2e0f9a1a6e5e3)
1 
2 /*
3       Routines to handle signals the program will receive.
4     Usually this will call the error handlers.
5 */
6 #include <petsc/private/petscimpl.h>             /*I   "petscsys.h"   I*/
7 #include <signal.h>
8 
9 static PetscClassId SIGNAL_CLASSID = 0;
10 
11 struct SH {
12   PetscClassId   classid;
13   PetscErrorCode (*handler)(int,void*);
14   void           *ctx;
15   struct SH      *previous;
16 };
17 static struct SH *sh       = 0;
18 static PetscBool SignalSet = PETSC_FALSE;
19 
20 /*
21     PetscSignalHandler_Private - This is the signal handler called by the system. This calls
22              any signal handler set by PETSc or the application code.
23 
24    Input Parameters: (depends on system)
25 .    sig - integer code indicating the type of signal
26 .    code - ??
27 .    sigcontext - ??
28 .    addr - ??
29 
30     Note: this is declared extern "C" because it is passed to the system routine signal()
31           which is an extern "C" routine. The Solaris 2.7 OS compilers require that this be
32           extern "C".
33 
34 */
35 #if defined(PETSC_HAVE_4ARG_SIGNAL_HANDLER)
36 static void PetscSignalHandler_Private(int sig,int code,struct sigcontext * scp,char *addr)
37 #else
38 static void PetscSignalHandler_Private(int sig)
39 #endif
40 {
41   PetscErrorCode ierr;
42 
43   PetscFunctionBegin;
44   if (!sh || !sh->handler) ierr = PetscSignalHandlerDefault(sig,(void*)0);
45   else {
46     if (sh->classid != SIGNAL_CLASSID) SETERRABORT(PETSC_COMM_WORLD,PETSC_ERR_COR,"Signal object has been corrupted");
47     ierr = (*sh->handler)(sig,sh->ctx);
48   }
49   if (ierr) MPI_Abort(PETSC_COMM_WORLD,0);
50 }
51 
52 /*@
53    PetscSignalHandlerDefault - Default signal handler.
54 
55    Not Collective
56 
57    Level: advanced
58 
59    Input Parameters:
60 +  sig - signal value
61 -  ptr - unused pointer
62 
63    Concepts: signal handler^default
64 
65 @*/
66 PetscErrorCode  PetscSignalHandlerDefault(int sig,void *ptr)
67 {
68   PetscErrorCode ierr;
69   const char     *SIGNAME[64];
70 
71   PetscFunctionBegin;
72   SIGNAME[0]       = "Unknown signal";
73 #if !defined(PETSC_MISSING_SIGABRT)
74   SIGNAME[SIGABRT] = "Abort";
75 #endif
76 #if !defined(PETSC_MISSING_SIGALRM)
77   SIGNAME[SIGALRM] = "Alarm";
78 #endif
79 #if !defined(PETSC_MISSING_SIGBUS)
80   SIGNAME[SIGBUS]  = "BUS: Bus Error, possibly illegal memory access";
81 #endif
82 #if !defined(PETSC_MISSING_SIGCHLD)
83   SIGNAME[SIGCHLD] = "CHLD";
84 #endif
85 #if !defined(PETSC_MISSING_SIGCONT)
86   SIGNAME[SIGCONT] = "CONT";
87 #endif
88 #if !defined(PETSC_MISSING_SIGFPE)
89   SIGNAME[SIGFPE]  = "FPE: Floating Point Exception,probably divide by zero";
90 #endif
91 #if !defined(PETSC_MISSING_SIGHUP)
92   SIGNAME[SIGHUP]  = "Hang up: Some other process (or the batch system) has told this process to end";
93 #endif
94 #if !defined(PETSC_MISSING_SIGILL)
95   SIGNAME[SIGILL]  = "Illegal instruction: Likely due to memory corruption";
96 #endif
97 #if !defined(PETSC_MISSING_SIGINT)
98   SIGNAME[SIGINT]  = "Interrupt";
99 #endif
100 #if !defined(PETSC_MISSING_SIGKILL)
101   SIGNAME[SIGKILL] = "Kill: Some other process (or the batch system) has told this process to end";
102 #endif
103 #if !defined(PETSC_MISSING_SIGPIPE)
104   SIGNAME[SIGPIPE] = "Broken Pipe: Likely while reading or writing to a socket";
105 #endif
106 #if !defined(PETSC_MISSING_SIGQUIT)
107   SIGNAME[SIGQUIT] = "Quit: Some other process (or the batch system) has told this process to end";
108 #endif
109 #if !defined(PETSC_MISSING_SIGSEGV)
110   SIGNAME[SIGSEGV] = "SEGV: Segmentation Violation, probably memory access out of range";
111 #endif
112 #if !defined(PETSC_MISSING_SIGSYS)
113   SIGNAME[SIGSYS]  = "SYS";
114 #endif
115 #if !defined(PETSC_MISSING_SIGTERM)
116   SIGNAME[SIGTERM] = "Terminate: Some process (or the batch system) has told this process to end";
117 #endif
118 #if !defined(PETSC_MISSING_SIGTRAP)
119   SIGNAME[SIGTRAP] = "TRAP";
120 #endif
121 #if !defined(PETSC_MISSING_SIGTSTP)
122   SIGNAME[SIGTSTP] = "TSTP";
123 #endif
124 #if !defined(PETSC_MISSING_SIGURG)
125   SIGNAME[SIGURG]  = "URG";
126 #endif
127 #if !defined(PETSC_MISSING_SIGUSR1)
128   SIGNAME[SIGUSR1] = "User 1";
129 #endif
130 #if !defined(PETSC_MISSING_SIGUSR2)
131   SIGNAME[SIGUSR2] = "User 2";
132 #endif
133 
134   signal(sig,SIG_DFL);
135   (*PetscErrorPrintf)("------------------------------------------------------------------------\n");
136   if (sig >= 0 && sig <= 20) (*PetscErrorPrintf)("Caught signal number %d %s\n",sig,SIGNAME[sig]);
137   else (*PetscErrorPrintf)("Caught signal\n");
138 
139   (*PetscErrorPrintf)("Try option -start_in_debugger or -on_error_attach_debugger\n");
140   (*PetscErrorPrintf)("or see http://www.mcs.anl.gov/petsc/documentation/faq.html#valgrind\n");
141   (*PetscErrorPrintf)("or try http://valgrind.org on GNU/linux and Apple Mac OS X to find memory corruption errors\n");
142 #if defined(PETSC_USE_DEBUG)
143   if (!PetscStackActive()) (*PetscErrorPrintf)("  or try option -log_stack\n");
144   else {
145     PetscStackPop;  /* remove stack frames for error handlers */
146     PetscStackPop;
147     (*PetscErrorPrintf)("likely location of problem given in stack below\n");
148     (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
149     PetscStackView(PETSC_STDOUT);
150   }
151 #endif
152 #if !defined(PETSC_USE_DEBUG)
153   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
154   (*PetscErrorPrintf)("to get more information on the crash.\n");
155 #endif
156   ierr =  PetscError(PETSC_COMM_SELF,0,"User provided function"," unknown file",PETSC_ERR_SIG,PETSC_ERROR_INITIAL,NULL);
157   MPI_Abort(PETSC_COMM_WORLD,(int)ierr);
158   PetscFunctionReturn(0);
159 }
160 
161 #if !defined(PETSC_SIGNAL_CAST)
162 #define PETSC_SIGNAL_CAST
163 #endif
164 
165 /*@C
166    PetscPushSignalHandler - Catches the usual fatal errors and
167    calls a user-provided routine.
168 
169    Not Collective
170 
171     Input Parameter:
172 +  routine - routine to call when a signal is received
173 -  ctx - optional context needed by the routine
174 
175   Level: developer
176 
177    Concepts: signal handler^setting
178 
179 .seealso: PetscPopSignalHandler(), PetscSignalHandlerDefault(), PetscPushErrorHandler()
180 
181 @*/
182 PetscErrorCode  PetscPushSignalHandler(PetscErrorCode (*routine)(int,void*),void *ctx)
183 {
184   struct  SH     *newsh;
185   PetscErrorCode ierr;
186 
187   PetscFunctionBegin;
188   if (!SIGNAL_CLASSID) {
189     /* ierr = PetscClassIdRegister("Signal",&SIGNAL_CLASSID);CHKERRQ(ierr); */
190     SIGNAL_CLASSID = 19;
191   }
192   if (!SignalSet && routine) {
193     /* Do not catch ABRT, CHLD, KILL */
194 #if !defined(PETSC_MISSING_SIGALRM)
195     /* signal(SIGALRM, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
196 #endif
197 #if !defined(PETSC_MISSING_SIGBUS)
198     signal(SIGBUS, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
199 #endif
200 #if !defined(PETSC_MISSING_SIGCONT)
201     /*signal(SIGCONT, PETSC_SIGNAL_CAST PetscSignalHandler_Private);*/
202 #endif
203 #if !defined(PETSC_MISSING_SIGFPE)
204     signal(SIGFPE,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
205 #endif
206 #if !defined(PETSC_MISSING_SIGHUP)
207     signal(SIGHUP, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
208 #endif
209 #if !defined(PETSC_MISSING_SIGILL)
210     signal(SIGILL,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
211 #endif
212 #if !defined(PETSC_MISSING_SIGINT)
213     /* signal(SIGINT, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
214 #endif
215 #if !defined(PETSC_MISSING_SIGPIPE)
216     signal(SIGPIPE, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
217 #endif
218 #if !defined(PETSC_MISSING_SIGQUIT)
219     signal(SIGQUIT, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
220 #endif
221 #if !defined(PETSC_MISSING_SIGSEGV)
222     signal(SIGSEGV, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
223 #endif
224 #if !defined(PETSC_MISSING_SIGSYS)
225     signal(SIGSYS,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
226 #endif
227 #if !defined(PETSC_MISSING_SIGTERM)
228     signal(SIGTERM,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
229 #endif
230 #if !defined(PETSC_MISSING_SIGTRAP)
231     signal(SIGTRAP,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
232 #endif
233 #if !defined(PETSC_MISSING_SIGTSTP)
234     /* signal(SIGTSTP,  PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
235 #endif
236 #if !defined(PETSC_MISSING_SIGURG)
237     signal(SIGURG,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
238 #endif
239 #if !defined(PETSC_MISSING_SIGUSR1)
240     /*    signal(SIGUSR1, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
241 #endif
242 #if !defined(PETSC_MISSING_SIGUSR2)
243     /* signal(SIGUSR2, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
244 #endif
245     SignalSet = PETSC_TRUE;
246   }
247   if (!routine) {
248 #if !defined(PETSC_MISSING_SIGALRM)
249     /* signal(SIGALRM, 0); */
250 #endif
251 #if !defined(PETSC_MISSING_SIGBUS)
252     signal(SIGBUS,  0);
253 #endif
254 #if !defined(PETSC_MISSING_SIGCONT)
255     /* signal(SIGCONT, 0); */
256 #endif
257 #if !defined(PETSC_MISSING_SIGFPE)
258     signal(SIGFPE,  0);
259 #endif
260 #if !defined(PETSC_MISSING_SIGHUP)
261     signal(SIGHUP,  0);
262 #endif
263 #if !defined(PETSC_MISSING_SIGILL)
264     signal(SIGILL,  0);
265 #endif
266 #if !defined(PETSC_MISSING_SIGINT)
267     /* signal(SIGINT,  0); */
268 #endif
269 #if !defined(PETSC_MISSING_SIGPIPE)
270     signal(SIGPIPE, 0);
271 #endif
272 #if !defined(PETSC_MISSING_SIGQUIT)
273     signal(SIGQUIT, 0);
274 #endif
275 #if !defined(PETSC_MISSING_SIGSEGV)
276     signal(SIGSEGV, 0);
277 #endif
278 #if !defined(PETSC_MISSING_SIGSYS)
279     signal(SIGSYS,  0);
280 #endif
281 #if !defined(PETSC_MISSING_SIGTERM)
282     signal(SIGTERM, 0);
283 #endif
284 #if !defined(PETSC_MISSING_SIGTRAP)
285     signal(SIGTRAP, 0);
286 #endif
287 #if !defined(PETSC_MISSING_SIGTSTP)
288     /* signal(SIGTSTP, 0); */
289 #endif
290 #if !defined(PETSC_MISSING_SIGURG)
291     signal(SIGURG,  0);
292 #endif
293 #if !defined(PETSC_MISSING_SIGUSR1)
294     /*    signal(SIGUSR1, 0); */
295 #endif
296 #if !defined(PETSC_MISSING_SIGUSR2)
297     /* signal(SIGUSR2, 0); */
298 #endif
299     SignalSet = PETSC_FALSE;
300   }
301   ierr = PetscNew(&newsh);CHKERRQ(ierr);
302   if (sh) {
303     if (sh->classid != SIGNAL_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Signal object has been corrupted");
304     newsh->previous = sh;
305   }  else newsh->previous = 0;
306   newsh->handler = routine;
307   newsh->ctx     = ctx;
308   newsh->classid = SIGNAL_CLASSID;
309   sh             = newsh;
310   PetscFunctionReturn(0);
311 }
312 
313 /*@
314    PetscPopSignalHandler - Removes the most last signal handler that was pushed.
315        If no signal handlers are left on the stack it will remove the PETSc signal handler.
316        (That is PETSc will no longer catch signals).
317 
318    Not Collective
319 
320   Level: developer
321 
322    Concepts: signal handler^setting
323 
324 .seealso: PetscPushSignalHandler()
325 
326 @*/
327 PetscErrorCode  PetscPopSignalHandler(void)
328 {
329   struct SH *tmp;
330 
331   PetscFunctionBegin;
332   if (!sh) PetscFunctionReturn(0);
333   if (sh->classid != SIGNAL_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Signal object has been corrupted");
334 
335   tmp = sh;
336   sh  = sh->previous;
337   PetscFreeVoid(tmp);
338   if (!sh || !sh->handler) {
339 #if !defined(PETSC_MISSING_SIGALRM)
340     /* signal(SIGALRM, 0); */
341 #endif
342 #if !defined(PETSC_MISSING_SIGBUS)
343     signal(SIGBUS,  0);
344 #endif
345 #if !defined(PETSC_MISSING_SIGCONT)
346     /* signal(SIGCONT, 0); */
347 #endif
348 #if !defined(PETSC_MISSING_SIGFPE)
349     signal(SIGFPE,  0);
350 #endif
351 #if !defined(PETSC_MISSING_SIGHUP)
352     signal(SIGHUP,  0);
353 #endif
354 #if !defined(PETSC_MISSING_SIGILL)
355     signal(SIGILL,  0);
356 #endif
357 #if !defined(PETSC_MISSING_SIGINT)
358     /* signal(SIGINT,  0); */
359 #endif
360 #if !defined(PETSC_MISSING_SIGPIPE)
361     signal(SIGPIPE, 0);
362 #endif
363 #if !defined(PETSC_MISSING_SIGQUIT)
364     signal(SIGQUIT, 0);
365 #endif
366 #if !defined(PETSC_MISSING_SIGSEGV)
367     signal(SIGSEGV, 0);
368 #endif
369 #if !defined(PETSC_MISSING_SIGSYS)
370     signal(SIGSYS,  0);
371 #endif
372 #if !defined(PETSC_MISSING_SIGTERM)
373     signal(SIGTERM, 0);
374 #endif
375 #if !defined(PETSC_MISSING_SIGTRAP)
376     signal(SIGTRAP, 0);
377 #endif
378 #if !defined(PETSC_MISSING_SIGTSTP)
379     /* signal(SIGTSTP, 0); */
380 #endif
381 #if !defined(PETSC_MISSING_SIGURG)
382     signal(SIGURG,  0);
383 #endif
384 #if !defined(PETSC_MISSING_SIGUSR1)
385     /*    signal(SIGUSR1, 0); */
386 #endif
387 #if !defined(PETSC_MISSING_SIGUSR2)
388     /* signal(SIGUSR2, 0); */
389 #endif
390     SignalSet = PETSC_FALSE;
391   } else {
392     SignalSet = PETSC_TRUE;
393   }
394   PetscFunctionReturn(0);
395 }
396 
397 
398 #if defined(PETSC_HAVE_SETJMP_H) && defined(PETSC_HAVE_SIGINFO_T)
399 #include <setjmp.h>
400 PETSC_VISIBILITY_INTERNAL jmp_buf PetscSegvJumpBuf;
401 /*
402     This routine is called if a segmentation violation, i.e. inaccessible memory access
403     is triggered when PETSc is testing for a buggy pointer with PetscCheckPointer()
404 
405     It simply unrolls the UNIX signal and returns to the location where setjump(PetscSeqvJumpBuf) is declared.
406 */
407 PETSC_INTERN void PetscSegv_sigaction(int signal, siginfo_t *si, void *arg)
408 {
409   longjmp(PetscSegvJumpBuf,1);
410   return;
411 }
412 #endif
413 
414 
415