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