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 Parameter:
 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 Key:
 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: {
 51:   PetscBool xterm;

 53:   PetscStrncpy(DebugTerminal, terminal, sizeof(DebugTerminal));
 54:   PetscStrcmp(terminal, "xterm", &xterm);
 55:   if (xterm) PetscStrlcat(DebugTerminal, " -e", sizeof(DebugTerminal));
 56:   return 0;
 57: }

 59: /*@C
 60:    PetscSetDebugger - Sets options associated with the debugger.

 62:    Not Collective

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

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

 74:    Level: developer

 76:    Fortran Note:
 77:    This routine is not supported in Fortran.

 79: .seealso: `PetscAttachDebugger()`, `PetscAttachDebuggerErrorHandler()`, `PetscSetDebugTerminal()`
 80: @*/
 81: PetscErrorCode PetscSetDebugger(const char debugger[], PetscBool usedebugterminal)
 82: {
 83:   if (debugger) PetscStrncpy(PetscDebugger, debugger, sizeof(PetscDebugger));
 84:   if (UseDebugTerminal) UseDebugTerminal = usedebugterminal;
 85:   return 0;
 86: }

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

 91:    Not collective

 93:     Level: developer

 95: .seealso: `PetscSetDebugger()`, `PetscSetDebuggerFromString()`
 96: @*/
 97: PetscErrorCode PetscSetDefaultDebugger(void)
 98: {
 99: #if defined(PETSC_USE_DEBUGGER)
100:   PetscSetDebugger(PETSC_USE_DEBUGGER, PETSC_TRUE);
101: #endif
102: #if defined(__APPLE__)
103:   PetscSetDebugTerminal("Terminal");
104: #else
105:   PetscSetDebugTerminal("xterm");
106: #endif
107:   return 0;
108: }

111: {
112:   PetscBool exists;
113:   char     *f;

115:   PetscStrstr(string, defaultDbg, &f);
116:   if (f) {
117:     PetscTestFile(string, 'x', &exists);
118:     if (exists) *debugger = string;
119:     else *debugger = defaultDbg;
120:   }
121:   return 0;
122: }

124: /*@C
125:     PetscSetDebuggerFromString - Set the complete path for the
126:        debugger for PETSc to use.

128:    Not collective

130:    Level: developer

132: .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`
133: @*/
134: PetscErrorCode PetscSetDebuggerFromString(const char *string)
135: {
136:   const char *debugger    = NULL;
137:   PetscBool   useterminal = PETSC_TRUE;
138:   char       *f;

140:   PetscStrstr(string, "noxterm", &f);
141:   if (f) useterminal = PETSC_FALSE;
142:   PetscStrstr(string, "ddd", &f);
143:   if (f) useterminal = PETSC_FALSE;
144:   PetscStrstr(string, "noterminal", &f);
145:   if (f) useterminal = PETSC_FALSE;
160:   PetscSetDebugger(debugger, useterminal);
161:   return 0;
162: }

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

168:    Not Collective

170:    Level: advanced

172:    Note:
173:       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
174:       killing the user's debugging sessions.

176: .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
177: @*/
178: PetscErrorCode PetscWaitOnError(void)
179: {
180:   petscwaitonerrorflg = PETSC_TRUE;
181:   return 0;
182: }

184: /*@
185:    PetscAttachDebugger - Attaches the debugger to the running process.

187:    Not Collective

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

193:    Level: advanced

195:    Developer Note:
196:     Since this can be called by the error handler should it be calling `SETERRQ()` and `PetscCall()`?

198: .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscSetDebugTerminal()`, `PetscAttachDebuggerErrorHandler()`, `PetscStopForDebugger()`
199: @*/
200: PetscErrorCode PetscAttachDebugger(void)
201: {
202: #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
203:   int       child     = 0;
204:   PetscReal sleeptime = 0;
205:   char      program[PETSC_MAX_PATH_LEN], display[256], hostname[64];
206: #endif

208: #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
209:   (*PetscErrorPrintf)("System cannot start debugger\n");
210:   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
211:   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
212:   PETSCABORT(PETSC_COMM_WORLD, PETSC_ERR_SUP_SYS);
213: #else
214:   if (PetscUnlikely(PetscGetDisplay(display, sizeof(display)))) {
215:     (*PetscErrorPrintf)("Cannot determine display\n");
216:     return PETSC_ERR_SYS;
217:   }
218:   if (PetscUnlikely(PetscGetProgramName(program, sizeof(program)))) {
219:     (*PetscErrorPrintf)("Cannot determine program name needed to attach debugger\n");
220:     return PETSC_ERR_SYS;
221:   }
222:   if (PetscUnlikely(!program[0])) {
223:     (*PetscErrorPrintf)("Cannot determine program name needed to attach debugger\n");
224:     return PETSC_ERR_SYS;
225:   }
226:   child = (int)fork();
227:   if (PetscUnlikely(child < 0)) {
228:     (*PetscErrorPrintf)("Error in fork() prior to attaching debugger\n");
229:     return PETSC_ERR_SYS;
230:   }
231:   petscindebugger = PETSC_TRUE;

233:   /*
234:       Swap role the parent and child. This is (I think) so that control c typed
235:     in the debugger goes to the correct process.
236:   */
237:   #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
238:   child = child ? 0 : (int)getppid();
239:   #endif

241:   if (child) { /* I am the parent, will run the debugger */
242:     const char *args[10];
243:     char        pid[10];
244:     PetscInt    j, jj;
245:     PetscBool   isdbx, isidb, isxldb, isxxgdb, isups, isxdb, isworkshop, isddd, iskdbg, islldb;

247:     PetscGetHostName(hostname, sizeof(hostname));
248:     /*
249:          We need to send a continue signal to the "child" process on the
250:        alpha, otherwise it just stays off forever
251:     */
252:   #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
253:     kill(child, SIGCONT);
254:   #endif
255:     sprintf(pid, "%d", child);

257:     PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb);
258:     PetscStrcmp(PetscDebugger, "ddd", &isddd);
259:     PetscStrcmp(PetscDebugger, "kdbg", &iskdbg);
260:     PetscStrcmp(PetscDebugger, "ups", &isups);
261:     PetscStrcmp(PetscDebugger, "xldb", &isxldb);
262:     PetscStrcmp(PetscDebugger, "xdb", &isxdb);
263:     PetscStrcmp(PetscDebugger, "dbx", &isdbx);
264:     PetscStrcmp(PetscDebugger, "idb", &isidb);
265:     PetscStrcmp(PetscDebugger, "workshop", &isworkshop);
266:     PetscStrcmp(PetscDebugger, "lldb", &islldb);

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

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

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

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

446: /*@C
447:    PetscAttachDebuggerErrorHandler - Error handler that attaches
448:    a debugger to a running process when an error is detected.
449:    This routine is useful for examining variables, etc.

451:    Not Collective

453:    Input Parameters:
454: +  comm - communicator over which error occurred
455: .  line - the line number of the error (indicated by __LINE__)
456: .  file - the file in which the error was detected (indicated by __FILE__)
457: .  message - an error text string, usually just printed to the screen
458: .  number - the generic error number
459: .  p - `PETSC_ERROR_INITIAL` if error just detected, otherwise `PETSC_ERROR_REPEAT`
460: -  ctx - error handler context

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

466:    Level: developer

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

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

477:    Notes for experienced users:
478:    Use `PetscPushErrorHandler()` to set the desired error handler.  The
479:    currently available PETSc error handlers are
480: $    PetscTraceBackErrorHandler()
481: $    PetscAttachDebuggerErrorHandler()
482: $    PetscAbortErrorHandler()
483:    or you may write your own.

485:    Developer Note:
486:      This routine calls abort instead of returning because if it returned then `MPI_Abort()` would get called which can generate an exception
487:      causing the debugger to be attached again in a cycle.

489: .seealso: `PetscSetDebuggerFromString()`, `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`,
490:           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscEmacsClientErrorHandler()`, `PetscReturnErrorHandler()`, `PetscSetDebugTermainal()`
491: @*/
492: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode num, PetscErrorType p, const char *mess, void *ctx)
493: {
494:   if (!mess) mess = " ";

496:   if (fun) (*PetscErrorPrintf)("%s() at %s:%d %s\n", fun, file, line, mess);
497:   else (*PetscErrorPrintf)("%s:%d %s\n", file, line, mess);

499:   PetscAttachDebugger();
500:   abort(); /* call abort because don't want to kill other MPI ranks that may successfully attach to debugger */
501:   return 0;
502: }

504: /*@C
505:    PetscStopForDebugger - Prints a message to the screen indicating how to
506:          attach to the process with the debugger and then waits for the
507:          debugger to attach.

509:    Not Collective

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

514:    Level: developer

516:    Note:
517:     This is likely never needed since `PetscAttachDebugger()` is easier to use and seems to always work.

519:    Developer Note:
520:     Since this can be called by the error handler, should it be calling `SETERRQ()` and `PetscCall()`?

522: .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
523: @*/
524: PetscErrorCode PetscStopForDebugger(void)
525: {
527:   PetscInt       sleeptime = 0;
528: #if !defined(PETSC_CANNOT_START_DEBUGGER)
529:   int         ppid;
530:   PetscMPIInt rank;
531:   char        program[PETSC_MAX_PATH_LEN], hostname[256];
532:   PetscBool   isdbx, isxldb, isxxgdb, isddd, iskdbg, isups, isxdb, islldb;
533: #endif

535: #if defined(PETSC_CANNOT_START_DEBUGGER)
536:   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
537: #else
538:   MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
539:   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
540:   PetscGetHostName(hostname, sizeof(hostname));
541:   if (ierr) {
542:     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
543:     return 0;
544:   }

546:   PetscGetProgramName(program, sizeof(program));
547:   if (ierr) {
548:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
549:     return 0;
550:   }
551:   if (!program[0]) {
552:     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
553:     return 0;
554:   }

556:   ppid = getpid();

558:   PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb);
559:   PetscStrcmp(PetscDebugger, "ddd", &isddd);
560:   PetscStrcmp(PetscDebugger, "kdbg", &iskdbg);
561:   PetscStrcmp(PetscDebugger, "ups", &isups);
562:   PetscStrcmp(PetscDebugger, "xldb", &isxldb);
563:   PetscStrcmp(PetscDebugger, "xdb", &isxdb);
564:   PetscStrcmp(PetscDebugger, "dbx", &isdbx);
565:   PetscStrcmp(PetscDebugger, "lldb", &islldb);

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

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

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