xref: /petsc/src/sys/error/signal.c (revision 60d4fc614ff537ecd43db92193c85cc85809f93f)
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://petsc.org/release/faq/#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 defined(PETSC_HAVE_CUDA)
147   (*PetscErrorPrintf)("or try https://docs.nvidia.com/cuda/cuda-memcheck/index.html on NVIDIA CUDA systems  to find memory corruption errors\n");
148 #endif
149   if (PetscDefined(USE_DEBUG)) {
150     if (PetscStackActive()) {
151       PetscStackPop;  /* remove stack frames for error handlers */
152       PetscStackPop;
153       (*PetscErrorPrintf)("likely location of problem given in stack below\n");
154       (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
155       PetscStackView(PETSC_STDOUT);
156     }
157   } else {
158     (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
159     (*PetscErrorPrintf)("to get more information on the crash.\n");
160   }
161   ierr =  PetscError(PETSC_COMM_SELF,0,"User provided function","unknown file",PETSC_ERR_SIG,PETSC_ERROR_INITIAL,NULL);
162 #if !defined(PETSC_MISSING_SIGBUS)
163   if (sig == SIGSEGV || sig == SIGBUS) {
164 #else
165   if (sig == SIGSEGV) {
166 #endif
167     PetscBool debug;
168 
169     PetscMallocGetDebug(&debug,NULL,NULL);
170     if (debug) {
171       (*PetscErrorPrintf)("Checking the memory for corruption.\n");
172       PetscMallocValidate(__LINE__,PETSC_FUNCTION_NAME,__FILE__);
173     } else {
174       (*PetscErrorPrintf)("Run with -malloc_debug to check if memory corruption is causing the crash.\n");
175     }
176   }
177   atexit(MyExit);
178   PETSCABORT(PETSC_COMM_WORLD,(int)ierr);
179   PetscFunctionReturn(0);
180 }
181 
182 #if !defined(PETSC_SIGNAL_CAST)
183 #define PETSC_SIGNAL_CAST
184 #endif
185 
186 /*@C
187    PetscPushSignalHandler - Catches the usual fatal errors and
188    calls a user-provided routine.
189 
190    Not Collective
191 
192     Input Parameter:
193 +  routine - routine to call when a signal is received
194 -  ctx - optional context needed by the routine
195 
196   Level: developer
197 
198 .seealso: PetscPopSignalHandler(), PetscSignalHandlerDefault(), PetscPushErrorHandler()
199 
200 @*/
201 PetscErrorCode  PetscPushSignalHandler(PetscErrorCode (*routine)(int,void*),void *ctx)
202 {
203   struct  SH     *newsh;
204   PetscErrorCode ierr;
205 
206   PetscFunctionBegin;
207   if (!SIGNAL_CLASSID) {
208     /* ierr = PetscClassIdRegister("Signal",&SIGNAL_CLASSID);CHKERRQ(ierr); */
209     SIGNAL_CLASSID = 19;
210   }
211   if (!SignalSet && routine) {
212     /* Do not catch ABRT, CHLD, KILL */
213 #if !defined(PETSC_MISSING_SIGALRM)
214     /* signal(SIGALRM, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
215 #endif
216 #if !defined(PETSC_MISSING_SIGBUS)
217     signal(SIGBUS, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
218 #endif
219 #if !defined(PETSC_MISSING_SIGCONT)
220     /*signal(SIGCONT, PETSC_SIGNAL_CAST PetscSignalHandler_Private);*/
221 #endif
222 #if !defined(PETSC_MISSING_SIGFPE)
223     signal(SIGFPE,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
224 #endif
225 #if !defined(PETSC_MISSING_SIGHUP) && defined(PETSC_HAVE_STRUCT_SIGACTION)
226     {
227       struct  sigaction action;
228       sigaction(SIGHUP,NULL,&action);
229       if (action.sa_handler == SIG_IGN) {
230         ierr = PetscInfo(NULL,"SIGHUP previously set to ignore, therefor not changing its signal handler\n");CHKERRQ(ierr);
231       } else {
232         signal(SIGHUP, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
233       }
234     }
235 #endif
236 #if !defined(PETSC_MISSING_SIGILL)
237     signal(SIGILL,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
238 #endif
239 #if !defined(PETSC_MISSING_SIGINT)
240     /* signal(SIGINT, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
241 #endif
242 #if !defined(PETSC_MISSING_SIGPIPE)
243     signal(SIGPIPE, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
244 #endif
245 #if !defined(PETSC_MISSING_SIGQUIT)
246     signal(SIGQUIT, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
247 #endif
248 #if !defined(PETSC_MISSING_SIGSEGV)
249     signal(SIGSEGV, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
250 #endif
251 #if !defined(PETSC_MISSING_SIGSYS)
252     signal(SIGSYS,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
253 #endif
254 #if !defined(PETSC_MISSING_SIGTERM)
255 #if !defined(OMPI_MAJOR_VERSION)
256     /* OpenMPI may use SIGTERM to close down all its ranks; we don't want to generate many confusing PETSc error messages in that case */
257     signal(SIGTERM,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
258 #endif
259 #endif
260 #if !defined(PETSC_MISSING_SIGTRAP)
261     signal(SIGTRAP,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
262 #endif
263 #if !defined(PETSC_MISSING_SIGTSTP)
264     /* signal(SIGTSTP,  PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
265 #endif
266 #if !defined(PETSC_MISSING_SIGURG)
267     signal(SIGURG,  PETSC_SIGNAL_CAST PetscSignalHandler_Private);
268 #endif
269 #if !defined(PETSC_MISSING_SIGUSR1)
270     /* signal(SIGUSR1, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
271 #endif
272 #if !defined(PETSC_MISSING_SIGUSR2)
273     /* signal(SIGUSR2, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
274 #endif
275     SignalSet = PETSC_TRUE;
276   }
277   if (!routine) {
278 #if !defined(PETSC_MISSING_SIGALRM)
279     /* signal(SIGALRM, SIG_DFL); */
280 #endif
281 #if !defined(PETSC_MISSING_SIGBUS)
282     signal(SIGBUS,  SIG_DFL);
283 #endif
284 #if !defined(PETSC_MISSING_SIGCONT)
285     /* signal(SIGCONT, SIG_DFL); */
286 #endif
287 #if !defined(PETSC_MISSING_SIGFPE)
288     signal(SIGFPE,  SIG_DFL);
289 #endif
290 #if !defined(PETSC_MISSING_SIGHUP)
291     signal(SIGHUP,  SIG_DFL);
292 #endif
293 #if !defined(PETSC_MISSING_SIGILL)
294     signal(SIGILL,  SIG_DFL);
295 #endif
296 #if !defined(PETSC_MISSING_SIGINT)
297     /* signal(SIGINT,  SIG_DFL); */
298 #endif
299 #if !defined(PETSC_MISSING_SIGPIPE)
300     signal(SIGPIPE, SIG_DFL);
301 #endif
302 #if !defined(PETSC_MISSING_SIGQUIT)
303     signal(SIGQUIT, SIG_DFL);
304 #endif
305 #if !defined(PETSC_MISSING_SIGSEGV)
306     signal(SIGSEGV, SIG_DFL);
307 #endif
308 #if !defined(PETSC_MISSING_SIGSYS)
309     signal(SIGSYS,  SIG_DFL);
310 #endif
311 #if !defined(PETSC_MISSING_SIGTERM)
312     signal(SIGTERM, SIG_DFL);
313 #endif
314 #if !defined(PETSC_MISSING_SIGTRAP)
315     signal(SIGTRAP, SIG_DFL);
316 #endif
317 #if !defined(PETSC_MISSING_SIGTSTP)
318     /* signal(SIGTSTP, SIG_DFL); */
319 #endif
320 #if !defined(PETSC_MISSING_SIGURG)
321     signal(SIGURG,  SIG_DFL);
322 #endif
323 #if !defined(PETSC_MISSING_SIGUSR1)
324     /* signal(SIGUSR1, SIG_DFL); */
325 #endif
326 #if !defined(PETSC_MISSING_SIGUSR2)
327     /* signal(SIGUSR2, SIG_DFL); */
328 #endif
329     SignalSet = PETSC_FALSE;
330   }
331   ierr = PetscNew(&newsh);CHKERRQ(ierr);
332   if (sh) {
333     if (sh->classid != SIGNAL_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Signal object has been corrupted");
334     newsh->previous = sh;
335   }  else newsh->previous = NULL;
336   newsh->handler = routine;
337   newsh->ctx     = ctx;
338   newsh->classid = SIGNAL_CLASSID;
339   sh             = newsh;
340   PetscFunctionReturn(0);
341 }
342 
343 /*@
344    PetscPopSignalHandler - Removes the most last signal handler that was pushed.
345        If no signal handlers are left on the stack it will remove the PETSc signal handler.
346        (That is PETSc will no longer catch signals).
347 
348    Not Collective
349 
350   Level: developer
351 
352 .seealso: PetscPushSignalHandler()
353 
354 @*/
355 PetscErrorCode  PetscPopSignalHandler(void)
356 {
357   struct SH      *tmp;
358   PetscErrorCode ierr;
359 
360   PetscFunctionBegin;
361   if (!sh) PetscFunctionReturn(0);
362   if (sh->classid != SIGNAL_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Signal object has been corrupted");
363 
364   tmp = sh;
365   sh  = sh->previous;
366   ierr = PetscFree(tmp);CHKERRQ(ierr);
367   if (!sh || !sh->handler) {
368 #if !defined(PETSC_MISSING_SIGALRM)
369     /* signal(SIGALRM, SIG_DFL); */
370 #endif
371 #if !defined(PETSC_MISSING_SIGBUS)
372     signal(SIGBUS,  SIG_DFL);
373 #endif
374 #if !defined(PETSC_MISSING_SIGCONT)
375     /* signal(SIGCONT, SIG_DFL); */
376 #endif
377 #if !defined(PETSC_MISSING_SIGFPE)
378     signal(SIGFPE,  SIG_DFL);
379 #endif
380 #if !defined(PETSC_MISSING_SIGHUP)
381     signal(SIGHUP,  SIG_DFL);
382 #endif
383 #if !defined(PETSC_MISSING_SIGILL)
384     signal(SIGILL,  SIG_DFL);
385 #endif
386 #if !defined(PETSC_MISSING_SIGINT)
387     /* signal(SIGINT,  SIG_DFL); */
388 #endif
389 #if !defined(PETSC_MISSING_SIGPIPE)
390     signal(SIGPIPE, SIG_DFL);
391 #endif
392 #if !defined(PETSC_MISSING_SIGQUIT)
393     signal(SIGQUIT, SIG_DFL);
394 #endif
395 #if !defined(PETSC_MISSING_SIGSEGV)
396     signal(SIGSEGV, SIG_DFL);
397 #endif
398 #if !defined(PETSC_MISSING_SIGSYS)
399     signal(SIGSYS,  SIG_DFL);
400 #endif
401 #if !defined(PETSC_MISSING_SIGTERM)
402     signal(SIGTERM, SIG_DFL);
403 #endif
404 #if !defined(PETSC_MISSING_SIGTRAP)
405     signal(SIGTRAP, SIG_DFL);
406 #endif
407 #if !defined(PETSC_MISSING_SIGTSTP)
408     /* signal(SIGTSTP, SIG_DFL); */
409 #endif
410 #if !defined(PETSC_MISSING_SIGURG)
411     signal(SIGURG,  SIG_DFL);
412 #endif
413 #if !defined(PETSC_MISSING_SIGUSR1)
414     /* signal(SIGUSR1, SIG_DFL); */
415 #endif
416 #if !defined(PETSC_MISSING_SIGUSR2)
417     /* signal(SIGUSR2, SIG_DFL); */
418 #endif
419     SignalSet = PETSC_FALSE;
420   } else {
421     SignalSet = PETSC_TRUE;
422   }
423   PetscFunctionReturn(0);
424 }
425