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