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 defined(PETSC_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 !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

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 defined(PETSC_HAVE_CUDA)
147:   (void)(*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 !PetscDefined(HAVE_THREADSAFETY)
151:   (void)(*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
152:   (void)PetscStackView(PETSC_STDOUT);
153:   #endif
154: #else
155:   (void)(*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
156:   (void)(*PetscErrorPrintf)("to get more information on the crash.\n");
157: #endif
158: #if !defined(PETSC_MISSING_SIGBUS)
159:   if (sig == SIGSEGV || sig == SIGBUS) {
160: #else
161:   if (sig == SIGSEGV) {
162: #endif
163:     PetscBool debug;

165:     (void)PetscMallocGetDebug(&debug, NULL, NULL);
166:     if (debug) (void)PetscMallocValidate(__LINE__, PETSC_FUNCTION_NAME, __FILE__);
167:     else (void)(*PetscErrorPrintf)("Run with -malloc_debug to check if memory corruption is causing the crash.\n");
168:   }
169:   atexit(MyExit);
170:   PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_SIG);
171:   return PETSC_SUCCESS;
172: }

174: #if !defined(PETSC_SIGNAL_CAST)
175:   #define PETSC_SIGNAL_CAST
176: #endif

178: /*@C
179:   PetscPushSignalHandler - Catches the usual fatal errors and
180:   calls a user-provided routine.

182:   Not Collective, No Fortran Support

184:   Input Parameters:
185: + routine - routine to call when a signal is received
186: - ctx     - optional context needed by the routine

188:   Level: developer

190:   Note:
191:   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
192:   the loader. That information is lost with the first call to `PetscPushSignalHandler()`

194: .seealso: [](sec_errors), `PetscPopSignalHandler()`, `PetscSignalHandlerDefault()`, `PetscPushErrorHandler()`
195: @*/
196: PetscErrorCode PetscPushSignalHandler(PetscErrorCode (*routine)(int, void *), void *ctx)
197: {
198:   struct SH *newsh;

200:   PetscFunctionBegin;
201:   if (!SIGNAL_CLASSID) {
202:     /* PetscCall(PetscClassIdRegister("Signal",&SIGNAL_CLASSID)); */
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:         PetscCall(PetscInfo(NULL, "SIGHUP previously set to ignore, therefore not changing its signal handler\n"));
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:   #if !defined(PETSC_HAVE_OPENMPI)
250:     /* 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 */
251:     signal(SIGTERM, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
252:   #endif
253: #endif
254: #if !defined(PETSC_MISSING_SIGTRAP)
255:     signal(SIGTRAP, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
256: #endif
257: #if !defined(PETSC_MISSING_SIGTSTP)
258:     /* signal(SIGTSTP,  PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
259: #endif
260: #if !defined(PETSC_MISSING_SIGURG)
261:     signal(SIGURG, PETSC_SIGNAL_CAST PetscSignalHandler_Private);
262: #endif
263: #if !defined(PETSC_MISSING_SIGUSR1)
264:     /* signal(SIGUSR1, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
265: #endif
266: #if !defined(PETSC_MISSING_SIGUSR2)
267:     /* signal(SIGUSR2, PETSC_SIGNAL_CAST PetscSignalHandler_Private); */
268: #endif
269:     SignalSet = PETSC_TRUE;
270:   }
271:   if (!routine) {
272: #if !defined(PETSC_MISSING_SIGALRM)
273:     /* signal(SIGALRM, SIG_DFL); */
274: #endif
275: #if !defined(PETSC_MISSING_SIGBUS)
276:     signal(SIGBUS, SIG_DFL);
277: #endif
278: #if !defined(PETSC_MISSING_SIGCONT)
279:     /* signal(SIGCONT, SIG_DFL); */
280: #endif
281: #if !defined(PETSC_MISSING_SIGFPE)
282:     signal(SIGFPE, SIG_DFL);
283: #endif
284: #if !defined(PETSC_MISSING_SIGHUP)
285:     signal(SIGHUP, SIG_DFL);
286: #endif
287: #if !defined(PETSC_MISSING_SIGILL)
288:     signal(SIGILL, SIG_DFL);
289: #endif
290: #if !defined(PETSC_MISSING_SIGINT)
291:     /* signal(SIGINT,  SIG_DFL); */
292: #endif
293: #if !defined(PETSC_MISSING_SIGPIPE)
294:     signal(SIGPIPE, SIG_DFL);
295: #endif
296: #if !defined(PETSC_MISSING_SIGQUIT)
297:     signal(SIGQUIT, SIG_DFL);
298: #endif
299: #if !defined(PETSC_MISSING_SIGSEGV)
300:     signal(SIGSEGV, SIG_DFL);
301: #endif
302: #if !defined(PETSC_MISSING_SIGSYS)
303:     signal(SIGSYS, SIG_DFL);
304: #endif
305: #if !defined(PETSC_MISSING_SIGTERM)
306:     signal(SIGTERM, SIG_DFL);
307: #endif
308: #if !defined(PETSC_MISSING_SIGTRAP)
309:     signal(SIGTRAP, SIG_DFL);
310: #endif
311: #if !defined(PETSC_MISSING_SIGTSTP)
312:     /* signal(SIGTSTP, SIG_DFL); */
313: #endif
314: #if !defined(PETSC_MISSING_SIGURG)
315:     signal(SIGURG, SIG_DFL);
316: #endif
317: #if !defined(PETSC_MISSING_SIGUSR1)
318:     /* signal(SIGUSR1, SIG_DFL); */
319: #endif
320: #if !defined(PETSC_MISSING_SIGUSR2)
321:     /* signal(SIGUSR2, SIG_DFL); */
322: #endif
323:     SignalSet = PETSC_FALSE;
324:   }
325:   PetscCall(PetscNew(&newsh));
326:   if (sh) {
327:     PetscCheck(sh->classid == SIGNAL_CLASSID, PETSC_COMM_SELF, PETSC_ERR_COR, "Signal object has been corrupted");
328:     newsh->previous = sh;
329:   } else newsh->previous = NULL;
330:   newsh->handler = routine;
331:   newsh->ctx     = ctx;
332:   newsh->classid = SIGNAL_CLASSID;
333:   sh             = newsh;
334:   PetscFunctionReturn(PETSC_SUCCESS);
335: }

337: /*@
338:   PetscPopSignalHandler - Removes the last signal handler that was pushed.
339:   If no signal handlers are left on the stack it will remove the PETSc signal handler.
340:   (That is PETSc will no longer catch signals).

342:   Not Collective

344:   Level: developer

346:   Note:
347:   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
348:   the loader. That information is lost with the first call to `PetscPushSignalHandler()`

350: .seealso: [](sec_errors), `PetscPushSignalHandler()`
351: @*/
352: PetscErrorCode PetscPopSignalHandler(void)
353: {
354:   struct SH *tmp;

356:   PetscFunctionBegin;
357:   if (!sh) PetscFunctionReturn(PETSC_SUCCESS);
358:   PetscCheck(sh->classid == SIGNAL_CLASSID, PETSC_COMM_SELF, PETSC_ERR_COR, "Signal object has been corrupted");

360:   tmp = sh;
361:   sh  = sh->previous;
362:   PetscCall(PetscFree(tmp));
363:   if (!sh || !sh->handler) {
364: #if !defined(PETSC_MISSING_SIGALRM)
365:     /* signal(SIGALRM, SIG_DFL); */
366: #endif
367: #if !defined(PETSC_MISSING_SIGBUS)
368:     signal(SIGBUS, SIG_DFL);
369: #endif
370: #if !defined(PETSC_MISSING_SIGCONT)
371:     /* signal(SIGCONT, SIG_DFL); */
372: #endif
373: #if !defined(PETSC_MISSING_SIGFPE)
374:     signal(SIGFPE, SIG_DFL);
375: #endif
376: #if !defined(PETSC_MISSING_SIGHUP)
377:     signal(SIGHUP, SIG_DFL);
378: #endif
379: #if !defined(PETSC_MISSING_SIGILL)
380:     signal(SIGILL, SIG_DFL);
381: #endif
382: #if !defined(PETSC_MISSING_SIGINT)
383:     /* signal(SIGINT,  SIG_DFL); */
384: #endif
385: #if !defined(PETSC_MISSING_SIGPIPE)
386:     signal(SIGPIPE, SIG_DFL);
387: #endif
388: #if !defined(PETSC_MISSING_SIGQUIT)
389:     signal(SIGQUIT, SIG_DFL);
390: #endif
391: #if !defined(PETSC_MISSING_SIGSEGV)
392:     signal(SIGSEGV, SIG_DFL);
393: #endif
394: #if !defined(PETSC_MISSING_SIGSYS)
395:     signal(SIGSYS, SIG_DFL);
396: #endif
397: #if !defined(PETSC_MISSING_SIGTERM)
398:     signal(SIGTERM, SIG_DFL);
399: #endif
400: #if !defined(PETSC_MISSING_SIGTRAP)
401:     signal(SIGTRAP, SIG_DFL);
402: #endif
403: #if !defined(PETSC_MISSING_SIGTSTP)
404:     /* signal(SIGTSTP, SIG_DFL); */
405: #endif
406: #if !defined(PETSC_MISSING_SIGURG)
407:     signal(SIGURG, SIG_DFL);
408: #endif
409: #if !defined(PETSC_MISSING_SIGUSR1)
410:     /* signal(SIGUSR1, SIG_DFL); */
411: #endif
412: #if !defined(PETSC_MISSING_SIGUSR2)
413:     /* signal(SIGUSR2, SIG_DFL); */
414: #endif
415:     SignalSet = PETSC_FALSE;
416:   } else {
417:     SignalSet = PETSC_TRUE;
418:   }
419:   PetscFunctionReturn(PETSC_SUCCESS);
420: }