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