Actual source code: adebug.c

      1: /*
      2:       Code to handle PETSc starting up in debuggers,etc.
      3: */

      5: #include <petscsys.h>
      6: #include <signal.h>
      7: #if defined(PETSC_HAVE_UNISTD_H)
      8: #include <unistd.h>
      9: #endif

     11: /*
     12:       These are the debugger and display used if the debugger is started up
     13: */
     14: static char      PetscDebugger[PETSC_MAX_PATH_LEN];
     15: static char      DebugTerminal[PETSC_MAX_PATH_LEN];
     16: static PetscBool UseDebugTerminal = PETSC_TRUE;
     17: PetscBool        petscwaitonerrorflg = PETSC_FALSE;
     18: PetscBool        petscindebugger  = PETSC_FALSE;

     20: /*@C
     21:    PetscSetDebugTerminal - Sets the terminal to use for debugging.

     23:    Not Collective

     25:    Input Parameters:
     26: .  terminal - name of terminal and any flags required to execute a program.
     27:               For example xterm, "urxvt -e", "gnome-terminal -x".
     28:               On Apple MacOS you can use Terminal (note the capital T)

     30:    Options Database Keys:
     31:    -debug_terminal terminal - use this terminal instead of the default

     33:    Level: developer

     35:    Notes:
     36:    You can start the debugger for all processes in the same GNU screen session.

     38:      mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"

     40:    will open 4 windows in the session named "debug".

     42:    The default on Apple is Terminal, on other systems the default is xterm

     44:    Fortran Note:
     45:    This routine is not supported in Fortran.

     47: .seealso: PetscSetDebugger()
     48: @*/
     49: PetscErrorCode  PetscSetDebugTerminal(const char terminal[])
     50: {
     52:   PetscBool      xterm;

     55:   PetscStrncpy(DebugTerminal,terminal,sizeof(DebugTerminal));
     56:   PetscStrcmp(terminal,"xterm",&xterm);
     57:   if (xterm) {
     58:     PetscStrlcat(DebugTerminal," -e",sizeof(DebugTerminal));
     59:   }
     60:   return(0);
     61: }

     63: /*@C
     64:    PetscSetDebugger - Sets options associated with the debugger.

     66:    Not Collective

     68:    Input Parameters:
     69: +  debugger - name of debugger, which should be in your path,
     70:               usually "lldb", "dbx", "gdb", "cuda-gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
     71:               supports "xdb", and IBM rs6000 supports "xldb".

     73: -  usedebugterminal - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
     74:             debugger should be started in a new terminal window) or PETSC_FALSE (to start debugger
     75:             in initial window (the option PETSC_FALSE makes no sense when using more
     76:             than one MPI process.)

     78:    Level: developer

     80:    Fortran Note:
     81:    This routine is not supported in Fortran.

     83: .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler(), PetscSetDebugTerminal()
     84: @*/
     85: PetscErrorCode  PetscSetDebugger(const char debugger[],PetscBool usedebugterminal)
     86: {

     90:   if (debugger) {
     91:     PetscStrncpy(PetscDebugger,debugger,sizeof(PetscDebugger));
     92:   }
     93:   if (UseDebugTerminal) UseDebugTerminal = usedebugterminal;
     94:   return(0);
     95: }

     97: /*@C
     98:     PetscSetDefaultDebugger - Causes PETSc to use its default debugger and output terminal

    100:    Not collective

    102:     Level: developer

    104: .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
    105: @*/
    106: PetscErrorCode  PetscSetDefaultDebugger(void)
    107: {

    111: #if defined(PETSC_USE_DEBUGGER)
    112:   PetscSetDebugger(PETSC_USE_DEBUGGER,PETSC_TRUE);
    113: #endif
    114: #if defined(__APPLE__)
    115:   PetscSetDebugTerminal("Terminal");
    116: #else
    117:   PetscSetDebugTerminal("xterm");
    118: #endif
    119:   return(0);
    120: }

    123: {
    124:   PetscBool      exists;
    125:   char           *f;

    129:   PetscStrstr(string, defaultDbg, &f);
    130:   if (f) {
    131:     PetscTestFile(string, 'x', &exists);
    132:     if (exists) *debugger = string;
    133:     else        *debugger = defaultDbg;
    134:   }
    135:   return(0);
    136: }

    138: /*@C
    139:     PetscSetDebuggerFromString - Set the complete path for the
    140:        debugger for PETSc to use.

    142:    Not collective

    144:    Level: developer

    146: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
    147: @*/
    148: PetscErrorCode  PetscSetDebuggerFromString(const char *string)
    149: {
    150:   const char     *debugger = NULL;
    151:   PetscBool      useterminal     = PETSC_TRUE;
    152:   char           *f;

    156:   PetscStrstr(string, "noxterm", &f);
    157:   if (f) useterminal = PETSC_FALSE;
    158:   PetscStrstr(string, "ddd", &f);
    159:   if (f) useterminal = PETSC_FALSE;
    160:   PetscStrstr(string, "noterminal", &f);
    161:   if (f) useterminal = PETSC_FALSE;

    177:   PetscSetDebugger(debugger, useterminal);
    178:   return(0);
    179: }

    181: /*@
    182:    PetscWaitOnError - If an error is detected and the process would normally exit the main program with MPI_Abort() sleep instead
    183:                       of exiting.

    185:    Not Collective

    187:    Level: advanced

    189:    Notes:
    190:       When -start_in_debugger -debugger_ranks x,y,z is used this prevents the processes NOT listed in x,y,z from calling MPI_Abort and
    191:       killing the user's debugging sessions.

    194: .seealso: PetscSetDebugger(), PetscAttachDebugger()
    195: @*/
    196: PetscErrorCode  PetscWaitOnError()
    197: {
    198:   petscwaitonerrorflg  = PETSC_TRUE;
    199:   return 0;
    200: }

    202: /*@
    203:    PetscAttachDebugger - Attaches the debugger to the running process.

    205:    Not Collective

    207:    Options Database Keys:
    208: -  -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n] -debug_terminal xterm or Terminal (for Apple)
    209: .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment

    211:    Level: advanced

    213:    Developer Notes:
    214:     Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?

    216: .seealso: PetscSetDebugger(), PetscSetDefaultDebugger(), PetscSetDebugTerminal(), PetscAttachDebuggerErrorHandler(), PetscStopForDebugger()
    217: @*/
    218: PetscErrorCode  PetscAttachDebugger(void)
    219: {
    220: #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
    221:   int            child    =0;
    222:   PetscReal      sleeptime=0;
    224:   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
    225: #endif

    228: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
    229:   (*PetscErrorPrintf)("System cannot start debugger\n");
    230:   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
    231:   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
    232:   PETSCABORT(PETSC_COMM_WORLD,PETSC_ERR_SUP_SYS);
    233: #else
    234:   PetscGetDisplay(display,sizeof(display));
    235:   PetscGetProgramName(program,sizeof(program));
    236:   if (ierr) {
    237:     (*PetscErrorPrintf)("Cannot determine program name\n");
    238:     PetscFunctionReturn(PETSC_ERR_SYS);
    239:   }
    240:   if (!program[0]) {
    241:     (*PetscErrorPrintf)("Cannot determine program name\n");
    242:     PetscFunctionReturn(PETSC_ERR_SYS);
    243:   }
    244:   child = (int)fork();
    245:   if (child < 0) {
    246:     (*PetscErrorPrintf)("Error in fork() prior to attaching debugger\n");
    247:     PetscFunctionReturn(PETSC_ERR_SYS);
    248:   }
    249:   petscindebugger = PETSC_TRUE;

    251:   /*
    252:       Swap role the parent and child. This is (I think) so that control c typed
    253:     in the debugger goes to the correct process.
    254:   */
    255: #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
    256:   if (child) child = 0;
    257:   else       child = (int)getppid();
    258: #endif

    260:   if (child) { /* I am the parent, will run the debugger */
    261:     const char *args[10];
    262:     char       pid[10];
    263:     PetscInt   j,jj;
    264:     PetscBool  isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;

    266:     PetscGetHostName(hostname,sizeof(hostname));
    267:     /*
    268:          We need to send a continue signal to the "child" process on the
    269:        alpha, otherwise it just stays off forever
    270:     */
    271: #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
    272:     kill(child,SIGCONT);
    273: #endif
    274:     sprintf(pid,"%d",child);

    276:     PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
    277:     PetscStrcmp(PetscDebugger,"ddd",&isddd);
    278:     PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
    279:     PetscStrcmp(PetscDebugger,"ups",&isups);
    280:     PetscStrcmp(PetscDebugger,"xldb",&isxldb);
    281:     PetscStrcmp(PetscDebugger,"xdb",&isxdb);
    282:     PetscStrcmp(PetscDebugger,"dbx",&isdbx);
    283:     PetscStrcmp(PetscDebugger,"idb",&isidb);
    284:     PetscStrcmp(PetscDebugger,"workshop",&isworkshop);
    285:     PetscStrcmp(PetscDebugger,"lldb",&islldb);

    287:     if (isxxgdb || isups || isddd) {
    288:       args[1] = program; args[2] = pid; args[3] = "-display";
    289:       args[0] = PetscDebugger; args[4] = display; args[5] = NULL;
    290:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
    291:       if (execvp(args[0],(char**)args)  < 0) {
    292:         perror("Unable to start debugger");
    293:         exit(0);
    294:       }
    295:     } else if (iskdbg) {
    296:       args[1] = "-p"; args[2] = pid; args[3] = program;  args[4] = "-display";
    297:       args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
    298:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
    299:       if (execvp(args[0],(char**)args)  < 0) {
    300:         perror("Unable to start debugger");
    301:         exit(0);
    302:       }
    303:     } else if (isxldb) {
    304:       args[1] = "-a"; args[2] = pid; args[3] = program;  args[4] = "-display";
    305:       args[0] = PetscDebugger; args[5] = display; args[6] = NULL;
    306:       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
    307:       if (execvp(args[0],(char**)args)  < 0) {
    308:         perror("Unable to start debugger");
    309:         exit(0);
    310:       }
    311:     } else if (isworkshop) {
    312:       args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
    313:       args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = NULL;
    314:       printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
    315:       if (execvp(args[0],(char**)args)  < 0) {
    316:         perror("Unable to start debugger");
    317:         exit(0);
    318:       }
    319:     } else {
    320:       j = 0;
    321:       if (UseDebugTerminal) {
    322:         PetscBool cmp;
    323:         char      *tmp,*tmp1;
    324:         PetscStrncmp(DebugTerminal,"Terminal",8,&cmp);
    325:         if (cmp) {
    326:           char command[1024];
    327:           PetscSNPrintf(command,sizeof(command),"osascript -e 'tell app \"Terminal\" to do script \"lldb  -p %s  %s \"'\n",pid,program);
    328:           PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",NULL);
    329:           exit(0);
    330:         }

    332:         PetscStrncmp(DebugTerminal,"screen",6,&cmp);
    333:         if (!cmp) {PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);}
    334:         if (cmp) display[0] = 0; /* when using screen, we never pass -display */
    335:         args[j++] = tmp = DebugTerminal;
    336:         if (display[0]) {
    337:           args[j++] = "-display"; args[j++] = display;
    338:         }
    339:         while (*tmp) {
    340:           PetscStrchr(tmp,' ',&tmp1);
    341:           if (!tmp1) break;
    342:           *tmp1     = 0;
    343:           tmp       = tmp1+1;
    344:           args[j++] = tmp;
    345:         }
    346:       }
    347:       args[j++] = PetscDebugger;
    348:       jj = j;
    349:       /* this is for default gdb */
    350:       args[j++] = program;
    351:       args[j++] = pid;
    352:       args[j++] = NULL;

    354:       if (isidb) {
    355:         j = jj;
    356:         args[j++] = "-pid";
    357:         args[j++] = pid;
    358:         args[j++] = "-gdb";
    359:         args[j++] = program;
    360:         args[j++] = NULL;
    361:       }
    362:       if (islldb) {
    363:         j = jj;
    364:         args[j++] = "-p";
    365:         args[j++] = pid;
    366:         args[j++] = NULL;
    367:       }
    368:       if (isdbx) {
    369:         j = jj;
    370: #if defined(PETSC_USE_P_FOR_DEBUGGER)
    371:         args[j++] = "-p";
    372:         args[j++] = pid;
    373:         args[j++] = program;
    374: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
    375:         args[j++] = "-l";
    376:         args[j++] = "ALL";
    377:         args[j++] = "-P";
    378:         args[j++] = pid;
    379:         args[j++] = program;
    380: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
    381:         args[j++] = "-a";
    382:         args[j++] = pid;
    383: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
    384:         args[j++] = "-pid";
    385:         args[j++] = pid;
    386:         args[j++] = program;
    387: #else
    388:         args[j++] = program;
    389:         args[j++] = pid;
    390: #endif
    391:         args[j++] = NULL;
    392:       }
    393:       if (UseDebugTerminal) {
    394:         if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
    395:         else            printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);

    397:         if (execvp(args[0],(char**)args)  < 0) {
    398:           perror("Unable to start debugger in xterm");
    399:           exit(0);
    400:         }
    401:       } else {
    402:         printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
    403:         if (execvp(args[0],(char**)args)  < 0) {
    404:           perror("Unable to start debugger");
    405:           exit(0);
    406:         }
    407:       }
    408:     }
    409:   } else {   /* I am the child, continue with user code */
    410:     sleeptime = 10; /* default to sleep waiting for debugger */
    411:     PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);
    412:     if (sleeptime < 0) sleeptime = -sleeptime;
    413: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
    414:     /*
    415:         HP cannot attach process to sleeping debugger, hence count instead
    416:     */
    417:     {
    418:       PetscReal x = 1.0;
    419:       int       i =10000000;
    420:       while (i--) x++;  /* cannot attach to sleeper */
    421:     }
    422: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
    423:     /*
    424:         IBM sleep may return at anytime, hence must see if there is more time to sleep
    425:     */
    426:     {
    427:       int left = sleeptime;
    428:       while (left > 0) left = PetscSleep(left) - 1;
    429:     }
    430: #else
    431:     PetscSleep(sleeptime);
    432: #endif
    433:   }
    434: #endif
    435:   return(0);
    436: }

    438: /*@C
    439:    PetscAttachDebuggerErrorHandler - Error handler that attaches
    440:    a debugger to a running process when an error is detected.
    441:    This routine is useful for examining variables, etc.

    443:    Not Collective

    445:    Input Parameters:
    446: +  comm - communicator over which error occurred
    447: .  line - the line number of the error (indicated by __LINE__)
    448: .  file - the file in which the error was detected (indicated by __FILE__)
    449: .  message - an error text string, usually just printed to the screen
    450: .  number - the generic error number
    451: .  p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
    452: -  ctx - error handler context

    454:    Options Database Keys:
    455: +  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates debugger attachment
    456: -  -start_in_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] [-debugger_ranks m,n]

    458:    Level: developer

    460:    Notes:
    461:    By default the GNU debugger, gdb, is used.  Alternatives are cuda-gdb, lldb, dbx and
    462:    xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).

    464:    Most users need not directly employ this routine and the other error
    465:    handlers, but can instead use the simplified interface SETERR, which has
    466:    the calling sequence
    467: $     SETERRQ(PETSC_COMM_SELF,number,p,message)

    469:    Notes for experienced users:
    470:    Use PetscPushErrorHandler() to set the desired error handler.  The
    471:    currently available PETSc error handlers are
    472: $    PetscTraceBackErrorHandler()
    473: $    PetscAttachDebuggerErrorHandler()
    474: $    PetscAbortErrorHandler()
    475:    or you may write your own.

    478: .seealso:  PetscSetDebuggerFromString(), PetscSetDebugger(), PetscSetDefaultDebugger(), PetscError(), PetscPushErrorHandler(), PetscPopErrorHandler(), PetscTraceBackErrorHandler(),
    479:            PetscAbortErrorHandler(), PetscMPIAbortErrorHandler(), PetscEmacsClientErrorHandler(), PetscReturnErrorHandler(), PetscSetDebugTermainal()
    480: @*/
    481: PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
    482: {

    486:   if (!fun) fun = "User provided function";
    487:   if (!mess) mess = " ";

    489:   (*PetscErrorPrintf)("%s() at %s:%d %s\n",fun,file,line,mess);

    491:   PetscAttachDebugger();
    492:   if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
    493:   return(0);
    494: }

    496: /*@C
    497:    PetscStopForDebugger - Prints a message to the screen indicating how to
    498:          attach to the process with the debugger and then waits for the
    499:          debugger to attach.

    501:    Not Collective

    503:    Options Database:
    504: .   -stop_for_debugger - will stop for you to attach the debugger when PetscInitialize() is called

    506:    Level: developer

    508:    Notes:
    509:     This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.

    511:    Developer Notes:
    512:     Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()?

    514: .seealso: PetscSetDebugger(), PetscAttachDebugger()
    515: @*/
    516: PetscErrorCode  PetscStopForDebugger(void)
    517: {
    519:   PetscInt       sleeptime=0;
    520: #if !defined(PETSC_CANNOT_START_DEBUGGER)
    521:   int            ppid;
    522:   PetscMPIInt    rank;
    523:   char           program[PETSC_MAX_PATH_LEN],hostname[256];
    524:   PetscBool      isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
    525: #endif

    528: #if defined(PETSC_CANNOT_START_DEBUGGER)
    529:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
    530: #else
    531:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
    532:   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
    533:   PetscGetHostName(hostname,sizeof(hostname));
    534:   if (ierr) {
    535:     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
    536:     return(0);
    537:   }

    539:   PetscGetProgramName(program,sizeof(program));
    540:   if (ierr) {
    541:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
    542:     return(0);
    543:   }
    544:   if (!program[0]) {
    545:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
    546:     return(0);
    547:   }

    549:   ppid = getpid();

    551:   PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);
    552:   PetscStrcmp(PetscDebugger,"ddd",&isddd);
    553:   PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);
    554:   PetscStrcmp(PetscDebugger,"ups",&isups);
    555:   PetscStrcmp(PetscDebugger,"xldb",&isxldb);
    556:   PetscStrcmp(PetscDebugger,"xdb",&isxdb);
    557:   PetscStrcmp(PetscDebugger,"dbx",&isdbx);
    558:   PetscStrcmp(PetscDebugger,"lldb",&islldb);

    560:   if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
    561:   else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
    562:   else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
    563:   else if (isdbx) {
    564: #if defined(PETSC_USE_P_FOR_DEBUGGER)
    565:      printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
    566: #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
    567:      printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
    568: #elif defined(PETSC_USE_A_FOR_DEBUGGER)
    569:      printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
    570: #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
    571:      printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
    572: #else
    573:      printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
    574: #endif
    575:   }
    576: #endif /* PETSC_CANNOT_START_DEBUGGER */

    578:   fflush(stdout); /* ignore error because may already be in error handler */

    580:   sleeptime = 25; /* default to sleep waiting for debugger */
    581:   PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
    582:   if (sleeptime < 0) sleeptime = -sleeptime;
    583: #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
    584:   /*
    585:       HP cannot attach process to sleeping debugger, hence count instead
    586:   */
    587:   {
    588:     PetscReal x = 1.0;
    589:     int       i =10000000;
    590:     while (i--) x++;  /* cannot attach to sleeper */
    591:   }
    592: #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
    593:   /*
    594:       IBM sleep may return at anytime, hence must see if there is more time to sleep
    595:   */
    596:   {
    597:     int left = sleeptime;
    598:     while (left > 0) left = sleep(left) - 1;
    599:   }
    600: #else
    601:   PetscSleep(sleeptime);
    602: #endif
    603:   return(0);
    604: }