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; No Fortran Support

 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: .seealso: `PetscSetDebugger()`
 45: @*/
 46: PetscErrorCode PetscSetDebugTerminal(const char terminal[])
 47: {
 48:   PetscBool xterm;

 50:   PetscStrncpy(DebugTerminal, terminal, sizeof(DebugTerminal));
 51:   PetscStrcmp(terminal, "xterm", &xterm);
 52:   if (xterm) PetscStrlcat(DebugTerminal, " -e", sizeof(DebugTerminal));
 53:   return 0;
 54: }

 56: /*@C
 57:    PetscSetDebugger - Sets options associated with the debugger.

 59:    Not Collective; No Fortran Support

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

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

 71:    Level: developer

 73: .seealso: `PetscAttachDebugger()`, `PetscAttachDebuggerErrorHandler()`, `PetscSetDebugTerminal()`
 74: @*/
 75: PetscErrorCode PetscSetDebugger(const char debugger[], PetscBool usedebugterminal)
 76: {
 77:   if (debugger) PetscStrncpy(PetscDebugger, debugger, sizeof(PetscDebugger));
 78:   if (UseDebugTerminal) UseDebugTerminal = usedebugterminal;
 79:   return 0;
 80: }

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

 85:    Not collective

 87:     Level: developer

 89: .seealso: `PetscSetDebugger()`, `PetscSetDebuggerFromString()`
 90: @*/
 91: PetscErrorCode PetscSetDefaultDebugger(void)
 92: {
 93: #if defined(PETSC_USE_DEBUGGER)
 94:   PetscSetDebugger(PETSC_USE_DEBUGGER, PETSC_TRUE);
 95: #endif
 96: #if defined(__APPLE__)
 97:   PetscSetDebugTerminal("Terminal");
 98: #else
 99:   PetscSetDebugTerminal("xterm");
100: #endif
101:   return 0;
102: }

105: {
106:   PetscBool exists;
107:   char     *f;

109:   PetscStrstr(string, defaultDbg, &f);
110:   if (f) {
111:     PetscTestFile(string, 'x', &exists);
112:     if (exists) *debugger = string;
113:     else *debugger = defaultDbg;
114:   }
115:   return 0;
116: }

118: /*@C
119:     PetscSetDebuggerFromString - Set the complete path for the
120:        debugger for PETSc to use.

122:    Not collective

124:    Level: developer

126: .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`
127: @*/
128: PetscErrorCode PetscSetDebuggerFromString(const char *string)
129: {
130:   const char *debugger    = NULL;
131:   PetscBool   useterminal = PETSC_TRUE;
132:   char       *f;

134:   PetscStrstr(string, "noxterm", &f);
135:   if (f) useterminal = PETSC_FALSE;
136:   PetscStrstr(string, "ddd", &f);
137:   if (f) useterminal = PETSC_FALSE;
138:   PetscStrstr(string, "noterminal", &f);
139:   if (f) useterminal = PETSC_FALSE;
154:   PetscSetDebugger(debugger, useterminal);
155:   return 0;
156: }

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

162:    Not Collective

164:    Level: advanced

166:    Note:
167:       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
168:       killing the user's debugging sessions.

170: .seealso: `PetscSetDebugger()`, `PetscAttachDebugger()`
171: @*/
172: PetscErrorCode PetscWaitOnError(void)
173: {
174:   petscwaitonerrorflg = PETSC_TRUE;
175:   return 0;
176: }

178: /*@
179:    PetscAttachDebugger - Attaches the debugger to the running process.

181:    Not Collective

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

187:    Level: advanced

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

192: .seealso: `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscSetDebugTerminal()`, `PetscAttachDebuggerErrorHandler()`, `PetscStopForDebugger()`
193: @*/
194: PetscErrorCode PetscAttachDebugger(void)
195: {
196: #if !defined(PETSC_CANNOT_START_DEBUGGER) && defined(PETSC_HAVE_FORK)
197:   int       child     = 0;
198:   PetscReal sleeptime = 0;
199:   char      program[PETSC_MAX_PATH_LEN], display[256], hostname[64];
200: #endif

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

227:   /*
228:       Swap role the parent and child. This is (I think) so that control c typed
229:     in the debugger goes to the correct process.
230:   */
231:   #if !defined(PETSC_DO_NOT_SWAP_CHILD_FOR_DEBUGGER)
232:   child = child ? 0 : (int)getppid();
233:   #endif

235:   if (child) { /* I am the parent, will run the debugger */
236:     const char *args[10];
237:     char        pid[10];
238:     PetscInt    j, jj;
239:     PetscBool   isdbx, isidb, isxldb, isxxgdb, isups, isxdb, isworkshop, isddd, iskdbg, islldb;

241:     PetscGetHostName(hostname, sizeof(hostname));
242:     /*
243:          We need to send a continue signal to the "child" process on the
244:        alpha, otherwise it just stays off forever
245:     */
246:   #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
247:     kill(child, SIGCONT);
248:   #endif
249:     sprintf(pid, "%d", child);

251:     PetscStrcmp(PetscDebugger, "xxgdb", &isxxgdb);
252:     PetscStrcmp(PetscDebugger, "ddd", &isddd);
253:     PetscStrcmp(PetscDebugger, "kdbg", &iskdbg);
254:     PetscStrcmp(PetscDebugger, "ups", &isups);
255:     PetscStrcmp(PetscDebugger, "xldb", &isxldb);
256:     PetscStrcmp(PetscDebugger, "xdb", &isxdb);
257:     PetscStrcmp(PetscDebugger, "dbx", &isdbx);
258:     PetscStrcmp(PetscDebugger, "idb", &isidb);
259:     PetscStrcmp(PetscDebugger, "workshop", &isworkshop);
260:     PetscStrcmp(PetscDebugger, "lldb", &islldb);

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

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

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

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

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

445:    Not Collective

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

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

460:    Level: developer

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

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

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

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

483: .seealso: `PetscSetDebuggerFromString()`, `PetscSetDebugger()`, `PetscSetDefaultDebugger()`, `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`,
484:           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscEmacsClientErrorHandler()`, `PetscReturnErrorHandler()`, `PetscSetDebugTermainal()`
485: @*/
486: PetscErrorCode PetscAttachDebuggerErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode num, PetscErrorType p, const char *mess, void *ctx)
487: {
488:   if (!mess) mess = " ";

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

493:   PetscAttachDebugger();
494:   abort(); /* call abort because don't want to kill other MPI ranks that may successfully attach to debugger */
495:   return 0;
496: }

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

503:    Not Collective

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

508:    Level: developer

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

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

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

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

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

550:   ppid = getpid();

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

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

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

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