xref: /petsc/src/sys/error/signal.c (revision 5b6bfdb9644f185dbf5e5a09b808ec241507e1e7)
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   PetscErrorCode ierr;
331 
332   PetscFunctionBegin;
333   if (!sh) PetscFunctionReturn(0);
334   if (sh->classid != SIGNAL_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Signal object has been corrupted");
335 
336   tmp = sh;
337   sh  = sh->previous;
338   ierr = PetscFree(tmp);CHKERRQ(ierr);
339   if (!sh || !sh->handler) {
340 #if !defined(PETSC_MISSING_SIGALRM)
341     /* signal(SIGALRM, 0); */
342 #endif
343 #if !defined(PETSC_MISSING_SIGBUS)
344     signal(SIGBUS,  0);
345 #endif
346 #if !defined(PETSC_MISSING_SIGCONT)
347     /* signal(SIGCONT, 0); */
348 #endif
349 #if !defined(PETSC_MISSING_SIGFPE)
350     signal(SIGFPE,  0);
351 #endif
352 #if !defined(PETSC_MISSING_SIGHUP)
353     signal(SIGHUP,  0);
354 #endif
355 #if !defined(PETSC_MISSING_SIGILL)
356     signal(SIGILL,  0);
357 #endif
358 #if !defined(PETSC_MISSING_SIGINT)
359     /* signal(SIGINT,  0); */
360 #endif
361 #if !defined(PETSC_MISSING_SIGPIPE)
362     signal(SIGPIPE, 0);
363 #endif
364 #if !defined(PETSC_MISSING_SIGQUIT)
365     signal(SIGQUIT, 0);
366 #endif
367 #if !defined(PETSC_MISSING_SIGSEGV)
368     signal(SIGSEGV, 0);
369 #endif
370 #if !defined(PETSC_MISSING_SIGSYS)
371     signal(SIGSYS,  0);
372 #endif
373 #if !defined(PETSC_MISSING_SIGTERM)
374     signal(SIGTERM, 0);
375 #endif
376 #if !defined(PETSC_MISSING_SIGTRAP)
377     signal(SIGTRAP, 0);
378 #endif
379 #if !defined(PETSC_MISSING_SIGTSTP)
380     /* signal(SIGTSTP, 0); */
381 #endif
382 #if !defined(PETSC_MISSING_SIGURG)
383     signal(SIGURG,  0);
384 #endif
385 #if !defined(PETSC_MISSING_SIGUSR1)
386     /*    signal(SIGUSR1, 0); */
387 #endif
388 #if !defined(PETSC_MISSING_SIGUSR2)
389     /* signal(SIGUSR2, 0); */
390 #endif
391     SignalSet = PETSC_FALSE;
392   } else {
393     SignalSet = PETSC_TRUE;
394   }
395   PetscFunctionReturn(0);
396 }
397 
398 
399 #if defined(PETSC_HAVE_SETJMP_H) && defined(PETSC_HAVE_SIGINFO_T)
400 #include <setjmp.h>
401 PETSC_VISIBILITY_INTERNAL jmp_buf PetscSegvJumpBuf;
402 /*
403     This routine is called if a segmentation violation, i.e. inaccessible memory access
404     is triggered when PETSc is testing for a buggy pointer with PetscCheckPointer()
405 
406     It simply unrolls the UNIX signal and returns to the location where setjump(PetscSeqvJumpBuf) is declared.
407 */
408 PETSC_INTERN void PetscSegv_sigaction(int signal, siginfo_t *si, void *arg)
409 {
410   longjmp(PetscSegvJumpBuf,1);
411   return;
412 }
413 #endif
414 
415 
416