Actual source code: signal.c
1: /*
2: Routines to handle signals the program will receive.
3: Usually this will call the error handlers.
4: */
5: #include <petsc/private/petscimpl.h>
6: #include <signal.h>
7: #include <stdlib.h> /* for _Exit() */
9: static PetscClassId SIGNAL_CLASSID = 0;
11: struct SH {
12: PetscClassId classid;
13: PetscErrorCode (*handler)(int, void *);
14: void *ctx;
15: struct SH *previous;
16: };
17: static struct SH *sh = NULL;
18: static PetscBool SignalSet = PETSC_FALSE;
20: /* Called by MPI_Abort() to suppress user-registered atexit()/on_exit() functions.
21: See discussion at https://gitlab.com/petsc/petsc/-/merge_requests/2745.
22: */
23: static void MyExit(void)
24: {
25: _Exit(MPI_ERR_OTHER);
26: }
28: /*
29: PetscSignalHandler_Private - This is the signal handler called by the system. This calls
30: any signal handler set by PETSc or the application code.
32: Input Parameters: (depends on system)
33: . sig - integer code indicating the type of signal
34: . code - ??
35: . sigcontext - ??
36: . addr - ??
38: */
39: #if PetscDefined(HAVE_4ARG_SIGNAL_HANDLER)
40: static void PetscSignalHandler_Private(int sig, int code, struct sigcontext *scp, char *addr)
41: #else
42: static void PetscSignalHandler_Private(int sig)
43: #endif
44: {
45: PetscErrorCode ierr;
47: if (!sh || !sh->handler) ierr = PetscSignalHandlerDefault(sig, NULL);
48: else {
49: if (sh->classid != SIGNAL_CLASSID) SETERRABORT(PETSC_COMM_WORLD, PETSC_ERR_COR, "Signal object has been corrupted");
50: ierr = (*sh->handler)(sig, sh->ctx);
51: }
52: if (ierr) PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_COR);
53: }
55: /*@
56: PetscSignalHandlerDefault - Default signal handler.
58: Not Collective
60: Input Parameters:
61: + sig - signal value
62: - ptr - unused pointer
64: Level: advanced
66: Developer Note:
67: This does not call `PetscError()`, it handles the entire error process, including possibly printing the traceback, directly
69: .seealso: [](sec_errors), `PetscPushSignalHandler()`
70: @*/
71: PetscErrorCode PetscSignalHandlerDefault(int sig, void *ptr)
72: {
73: const char *SIGNAME[64];
75: if (sig == SIGSEGV) PetscSignalSegvCheckPointerOrMpi();
76: SIGNAME[0] = "Unknown signal";
77: #if !PetscDefined(MISSING_SIGABRT)
78: SIGNAME[SIGABRT] = "Abort";
79: #endif
80: #if !PetscDefined(MISSING_SIGALRM)
81: SIGNAME[SIGALRM] = "Alarm";
82: #endif
83: #if !PetscDefined(MISSING_SIGBUS)
84: SIGNAME[SIGBUS] = "BUS: Bus Error, possibly illegal memory access";
85: #endif
86: #if !PetscDefined(MISSING_SIGCHLD)
87: SIGNAME[SIGCHLD] = "CHLD";
88: #endif
89: #if !PetscDefined(MISSING_SIGCONT)
90: SIGNAME[SIGCONT] = "CONT";
91: #endif
92: #if !PetscDefined(MISSING_SIGFPE)
93: SIGNAME[SIGFPE] = "FPE: Floating Point Exception,probably divide by zero";
94: #endif
95: #if !PetscDefined(MISSING_SIGHUP)
96: SIGNAME[SIGHUP] = "Hang up: Some other process (or the batch system) has told this process to end";
97: #endif
98: #if !PetscDefined(MISSING_SIGILL)
99: SIGNAME[SIGILL] = "Illegal instruction: Likely due to memory corruption";
100: #endif
101: #if !PetscDefined(MISSING_SIGINT)
102: SIGNAME[SIGINT] = "Interrupt";
103: #endif
104: #if !PetscDefined(MISSING_SIGKILL)
105: SIGNAME[SIGKILL] = "Kill: Some other process (or the batch system) has told this process to end";
106: #endif
107: #if !PetscDefined(MISSING_SIGPIPE)
108: SIGNAME[SIGPIPE] = "Broken Pipe: Likely while reading or writing to a socket";
109: #endif
110: #if !PetscDefined(MISSING_SIGQUIT)
111: SIGNAME[SIGQUIT] = "Quit: Some other process (or the batch system) has told this process to end";
112: #endif
113: #if !PetscDefined(MISSING_SIGSEGV)
114: SIGNAME[SIGSEGV] = "SEGV: Segmentation Violation, probably memory access out of range";
115: #endif
116: #if !PetscDefined(MISSING_SIGSYS)
117: SIGNAME[SIGSYS] = "SYS";
118: #endif
119: #if !PetscDefined(MISSING_SIGTERM)
120: SIGNAME[SIGTERM] = "Terminate: Some process (or the batch system) has told this process to end";
121: #endif
122: #if !PetscDefined(MISSING_SIGTRAP)
123: SIGNAME[SIGTRAP] = "TRAP";
124: #endif
125: #if !PetscDefined(MISSING_SIGTSTP)
126: SIGNAME[SIGTSTP] = "TSTP";
127: #endif
128: #if !PetscDefined(MISSING_SIGURG)
129: SIGNAME[SIGURG] = "URG";
130: #endif
131: #if !PetscDefined(MISSING_SIGUSR1)
132: SIGNAME[SIGUSR1] = "User 1";
133: #endif
134: #if !PetscDefined(MISSING_SIGUSR2)
135: SIGNAME[SIGUSR2] = "User 2";
136: #endif
138: signal(sig, SIG_DFL);
139: (void)PetscSleep(PetscGlobalRank % 4); /* prevent some jumbling of error messages from different ranks */
140: (void)(*PetscErrorPrintf)("------------------------------------------------------------------------\n");
141: if (sig >= 0 && sig <= 20) (void)(*PetscErrorPrintf)("Caught signal number %d %s\n", sig, SIGNAME[sig]);
142: else (void)(*PetscErrorPrintf)("Caught signal\n");
144: (void)(*PetscErrorPrintf)("Try option -start_in_debugger or -on_error_attach_debugger\n");
145: (void)(*PetscErrorPrintf)("or see https://petsc.org/release/faq/#valgrind and https://petsc.org/release/faq/\n");
146: if (PetscDefined(HAVE_CUDA)) (void)(*PetscErrorPrintf)("or try https://docs.nvidia.com/compute-sanitizer/ComputeSanitizer/index.html on NVIDIA CUDA systems to find memory corruption errors\n");
147: if (PetscDefined(USE_DEBUG)) {
148: (void)(*PetscErrorPrintf)("--------------------- Stack Frames ------------------------------------\n");
149: (void)PetscStackView(PETSC_STDOUT);
150: } else {
151: (void)(*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
152: (void)(*PetscErrorPrintf)("to get more information on the crash.\n");
153: }
154: #if !PetscDefined(MISSING_SIGBUS)
155: if (sig == SIGSEGV || sig == SIGBUS) {
156: #else
157: if (sig == SIGSEGV) {
158: #endif
159: PetscBool debug;
161: (void)PetscMallocGetDebug(&debug, NULL, NULL);
162: if (debug) (void)PetscMallocValidate(__LINE__, PETSC_FUNCTION_NAME, __FILE__);
163: else (void)(*PetscErrorPrintf)("Run with -malloc_debug to check if memory corruption is causing the crash.\n");
164: }
165: atexit(MyExit);
166: PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_SIG);
167: return PETSC_SUCCESS;
168: }
170: #if !defined(PETSC_SIGNAL_CAST)
171: #define PETSC_SIGNAL_CAST
172: #endif
174: /*@
175: PetscPushSignalHandler - Catches the usual fatal errors and
176: calls a user-provided routine.
178: Not Collective, No Fortran Support
180: Input Parameters:
181: + routine - routine to call when a signal is received
182: - ctx - optional context needed by the routine
184: Level: developer
186: Note:
187: There is no way to return to a signal handler that was set directly by the user with the UNIX signal handler API or by
188: the loader. That information is lost with the first call to `PetscPushSignalHandler()`
190: .seealso: [](sec_errors), `PetscPopSignalHandler()`, `PetscSignalHandlerDefault()`, `PetscPushErrorHandler()`
191: @*/
192: PetscErrorCode PetscPushSignalHandler(PetscErrorCode (*routine)(int, void *), PetscCtx ctx)
193: {
194: struct SH *newsh;
196: PetscFunctionBegin;
197: if (!SIGNAL_CLASSID) {
198: /* PetscCall(PetscClassIdRegister("Signal",&SIGNAL_CLASSID)); */
199: SIGNAL_CLASSID = 19;
200: }
201: if (!SignalSet && routine) {
202: /* Do not catch ABRT, CHLD, KILL */
203: #if !PetscDefined(MISSING_SIGALRM)
204: /* signal(SIGALRM, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
205: #endif
206: #if !PetscDefined(MISSING_SIGBUS)
207: signal(SIGBUS, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
208: #endif
209: #if !PetscDefined(MISSING_SIGCONT)
210: /*signal(SIGCONT, PETSC_SIGNAL_CAST PetscSignalHandler_Private);*/
211: #endif
212: #if !PetscDefined(MISSING_SIGFPE)
213: signal(SIGFPE, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
214: #endif
215: #if !PetscDefined(MISSING_SIGHUP) && PetscDefined(HAVE_STRUCT_SIGACTION)
216: {
217: struct sigaction action;
218: sigaction(SIGHUP, NULL, &action);
219: if (action.sa_handler == SIG_IGN) {
220: PetscCall(PetscInfo(NULL, "SIGHUP previously set to ignore, therefore not changing its signal handler\n"));
221: } else {
222: signal(SIGHUP, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
223: }
224: }
225: #endif
226: #if !PetscDefined(MISSING_SIGILL)
227: signal(SIGILL, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
228: #endif
229: #if !PetscDefined(MISSING_SIGINT)
230: /* signal(SIGINT, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
231: #endif
232: #if !PetscDefined(MISSING_SIGPIPE)
233: signal(SIGPIPE, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
234: #endif
235: #if !PetscDefined(MISSING_SIGQUIT)
236: signal(SIGQUIT, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
237: #endif
238: #if !PetscDefined(MISSING_SIGSEGV)
239: signal(SIGSEGV, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
240: #endif
241: #if !PetscDefined(MISSING_SIGSYS)
242: signal(SIGSYS, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
243: #endif
244: #if !PetscDefined(MISSING_SIGTERM)
245: #if !PetscDefined(HAVE_OPENMPI)
246: /* Open MPI may use SIGTERM to close down all its ranks; we don't want to generate many confusing PETSc error messages in that case */
247: signal(SIGTERM, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
248: #endif
249: #endif
250: #if !PetscDefined(MISSING_SIGTRAP)
251: signal(SIGTRAP, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
252: #endif
253: #if !PetscDefined(MISSING_SIGTSTP)
254: /* signal(SIGTSTP, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
255: #endif
256: #if !PetscDefined(MISSING_SIGURG)
257: signal(SIGURG, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
258: #endif
259: #if !PetscDefined(MISSING_SIGUSR1)
260: /* signal(SIGUSR1, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
261: #endif
262: #if !PetscDefined(MISSING_SIGUSR2)
263: /* signal(SIGUSR2, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
264: #endif
265: SignalSet = PETSC_TRUE;
266: }
267: if (!routine) {
268: #if !PetscDefined(MISSING_SIGALRM)
269: /* signal(SIGALRM, SIG_DFL); */
270: #endif
271: #if !PetscDefined(MISSING_SIGBUS)
272: signal(SIGBUS, SIG_DFL);
273: #endif
274: #if !PetscDefined(MISSING_SIGCONT)
275: /* signal(SIGCONT, SIG_DFL); */
276: #endif
277: #if !PetscDefined(MISSING_SIGFPE)
278: signal(SIGFPE, SIG_DFL);
279: #endif
280: #if !PetscDefined(MISSING_SIGHUP)
281: signal(SIGHUP, SIG_DFL);
282: #endif
283: #if !PetscDefined(MISSING_SIGILL)
284: signal(SIGILL, SIG_DFL);
285: #endif
286: #if !PetscDefined(MISSING_SIGINT)
287: /* signal(SIGINT, SIG_DFL); */
288: #endif
289: #if !PetscDefined(MISSING_SIGPIPE)
290: signal(SIGPIPE, SIG_DFL);
291: #endif
292: #if !PetscDefined(MISSING_SIGQUIT)
293: signal(SIGQUIT, SIG_DFL);
294: #endif
295: #if !PetscDefined(MISSING_SIGSEGV)
296: signal(SIGSEGV, SIG_DFL);
297: #endif
298: #if !PetscDefined(MISSING_SIGSYS)
299: signal(SIGSYS, SIG_DFL);
300: #endif
301: #if !PetscDefined(MISSING_SIGTERM)
302: signal(SIGTERM, SIG_DFL);
303: #endif
304: #if !PetscDefined(MISSING_SIGTRAP)
305: signal(SIGTRAP, SIG_DFL);
306: #endif
307: #if !PetscDefined(MISSING_SIGTSTP)
308: /* signal(SIGTSTP, SIG_DFL); */
309: #endif
310: #if !PetscDefined(MISSING_SIGURG)
311: signal(SIGURG, SIG_DFL);
312: #endif
313: #if !PetscDefined(MISSING_SIGUSR1)
314: /* signal(SIGUSR1, SIG_DFL); */
315: #endif
316: #if !PetscDefined(MISSING_SIGUSR2)
317: /* signal(SIGUSR2, SIG_DFL); */
318: #endif
319: SignalSet = PETSC_FALSE;
320: }
321: PetscCall(PetscNew(&newsh));
322: if (sh) {
323: PetscCheck(sh->classid == SIGNAL_CLASSID, PETSC_COMM_SELF, PETSC_ERR_COR, "Signal object has been corrupted");
324: newsh->previous = sh;
325: } else newsh->previous = NULL;
326: newsh->handler = routine;
327: newsh->ctx = ctx;
328: newsh->classid = SIGNAL_CLASSID;
329: sh = newsh;
330: PetscFunctionReturn(PETSC_SUCCESS);
331: }
333: /*@
334: PetscPopSignalHandler - Removes the last signal handler that was pushed.
335: If no signal handlers are left on the stack it will remove the PETSc signal handler.
336: (That is PETSc will no longer catch signals).
338: Not Collective
340: Level: developer
342: Note:
343: There is no way to return to a signal handler that was set directly by the user with the UNIX signal handler API or by
344: the loader. That information is lost with the first call to `PetscPushSignalHandler()`
346: .seealso: [](sec_errors), `PetscPushSignalHandler()`
347: @*/
348: PetscErrorCode PetscPopSignalHandler(void)
349: {
350: struct SH *tmp;
352: PetscFunctionBegin;
353: if (!sh) PetscFunctionReturn(PETSC_SUCCESS);
354: PetscCheck(sh->classid == SIGNAL_CLASSID, PETSC_COMM_SELF, PETSC_ERR_COR, "Signal object has been corrupted");
356: tmp = sh;
357: sh = sh->previous;
358: PetscCall(PetscFree(tmp));
359: if (!sh || !sh->handler) {
360: #if !PetscDefined(MISSING_SIGALRM)
361: /* signal(SIGALRM, SIG_DFL); */
362: #endif
363: #if !PetscDefined(MISSING_SIGBUS)
364: signal(SIGBUS, SIG_DFL);
365: #endif
366: #if !PetscDefined(MISSING_SIGCONT)
367: /* signal(SIGCONT, SIG_DFL); */
368: #endif
369: #if !PetscDefined(MISSING_SIGFPE)
370: signal(SIGFPE, SIG_DFL);
371: #endif
372: #if !PetscDefined(MISSING_SIGHUP)
373: signal(SIGHUP, SIG_DFL);
374: #endif
375: #if !PetscDefined(MISSING_SIGILL)
376: signal(SIGILL, SIG_DFL);
377: #endif
378: #if !PetscDefined(MISSING_SIGINT)
379: /* signal(SIGINT, SIG_DFL); */
380: #endif
381: #if !PetscDefined(MISSING_SIGPIPE)
382: signal(SIGPIPE, SIG_DFL);
383: #endif
384: #if !PetscDefined(MISSING_SIGQUIT)
385: signal(SIGQUIT, SIG_DFL);
386: #endif
387: #if !PetscDefined(MISSING_SIGSEGV)
388: signal(SIGSEGV, SIG_DFL);
389: #endif
390: #if !PetscDefined(MISSING_SIGSYS)
391: signal(SIGSYS, SIG_DFL);
392: #endif
393: #if !PetscDefined(MISSING_SIGTERM)
394: signal(SIGTERM, SIG_DFL);
395: #endif
396: #if !PetscDefined(MISSING_SIGTRAP)
397: signal(SIGTRAP, SIG_DFL);
398: #endif
399: #if !PetscDefined(MISSING_SIGTSTP)
400: /* signal(SIGTSTP, SIG_DFL); */
401: #endif
402: #if !PetscDefined(MISSING_SIGURG)
403: signal(SIGURG, SIG_DFL);
404: #endif
405: #if !PetscDefined(MISSING_SIGUSR1)
406: /* signal(SIGUSR1, SIG_DFL); */
407: #endif
408: #if !PetscDefined(MISSING_SIGUSR2)
409: /* signal(SIGUSR2, SIG_DFL); */
410: #endif
411: SignalSet = PETSC_FALSE;
412: } else {
413: SignalSet = PETSC_TRUE;
414: }
415: PetscFunctionReturn(PETSC_SUCCESS);
416: }