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/compute-sanitizer/ComputeSanitizer/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 *), PetscCtx 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: }