xref: /petsc/src/sys/error/adebug.c (revision d49bb8f946631d5470c2a737c5ecfe1ed81df0b7)
1 /*
2       Code to handle PETSc starting up in debuggers,etc.
3 */
4 
5 #include <petscsys.h>               /*I   "petscsys.h"   I*/
6 #include <signal.h>
7 #if defined(PETSC_HAVE_UNISTD_H)
8 #include <unistd.h>
9 #endif
10 
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 Xterm = PETSC_TRUE;
17 
18 /*@C
19    PetscSetDebugTerminal - Sets the terminal to use (instead of xterm) for debugging.
20 
21    Not Collective
22 
23    Input Parameters:
24 +  terminal - name of terminal and any flags required to execute a program.
25               For example "xterm -e", "urxvt -e", "gnome-terminal -x".
26 
27    Options Database Keys:
28    -debug_terminal terminal - use this terminal instead of xterm
29 
30    Level: developer
31 
32    Notes:
33    You can start the debugger for all processes in the same GNU screen session.
34 
35      mpiexec -n 4 ./myapp -start_in_debugger -debug_terminal "screen -X -S debug screen"
36 
37    will open 4 windows in the session named "debug".
38 
39    Fortran Note:
40    This routine is not supported in Fortran.
41 
42    Concepts: debugger^setting
43 
44 .seealso: PetscSetDebugger()
45 @*/
46 PetscErrorCode  PetscSetDebugTerminal(const char terminal[])
47 {
48   PetscErrorCode ierr;
49 
50   PetscFunctionBegin;
51   ierr = PetscStrcpy(DebugTerminal,terminal);CHKERRQ(ierr);
52   PetscFunctionReturn(0);
53 }
54 
55 /*@C
56    PetscSetDebugger - Sets options associated with the debugger.
57 
58    Not Collective
59 
60    Input Parameters:
61 +  debugger - name of debugger, which should be in your path,
62               usually "lldb", "dbx", "gdb", "idb", "xxgdb", "kdgb" or "ddd". Also, HP-UX
63               supports "xdb", and IBM rs6000 supports "xldb".
64 
65 -  xterm - flag to indicate debugger window, set to either PETSC_TRUE (to indicate
66             debugger should be started in a new xterm) or PETSC_FALSE (to start debugger
67             in initial window (the option PETSC_FALSE makes no sense when using more
68             than one MPI process.)
69 
70    Level: developer
71 
72    Fortran Note:
73    This routine is not supported in Fortran.
74 
75   Concepts: debugger^setting
76 
77 .seealso: PetscAttachDebugger(), PetscAttachDebuggerErrorHandler()
78 @*/
79 PetscErrorCode  PetscSetDebugger(const char debugger[],PetscBool xterm)
80 {
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   if (debugger) {
85     ierr = PetscStrcpy(PetscDebugger,debugger);CHKERRQ(ierr);
86   }
87   Xterm = xterm;
88   PetscFunctionReturn(0);
89 }
90 
91 /*@C
92     PetscSetDefaultDebugger - Causes PETSc to use its default  debugger.
93 
94    Not collective
95 
96     Level: developer
97 
98 .seealso: PetscSetDebugger(), PetscSetDebuggerFromString()
99 @*/
100 PetscErrorCode  PetscSetDefaultDebugger(void)
101 {
102   PetscErrorCode ierr;
103 
104   PetscFunctionBegin;
105 #if defined(PETSC_USE_LLDB_DEBUGGER)
106   ierr = PetscSetDebugger("lldb",PETSC_TRUE);CHKERRQ(ierr);
107 #elif defined(PETSC_USE_DBX_DEBUGGER)
108   ierr = PetscSetDebugger("dbx",PETSC_TRUE);CHKERRQ(ierr);
109 #elif defined(PETSC_USE_XDB_DEBUGGER)
110   ierr = PetscSetDebugger("xdb",PETSC_TRUE);CHKERRQ(ierr);
111 #elif defined(PETSC_USE_IDB_DEBUGGER)
112   ierr = PetscSetDebugger("idb",PETSC_TRUE);CHKERRQ(ierr);
113 #else  /* Default is gdb */
114   ierr = PetscSetDebugger("gdb",PETSC_TRUE);CHKERRQ(ierr);
115 #endif
116   ierr = PetscSetDebugTerminal("xterm -e");CHKERRQ(ierr);
117   PetscFunctionReturn(0);
118 }
119 
120 static PetscErrorCode PetscCheckDebugger_Private(const char defaultDbg[], const char string[], const char *debugger[])
121 {
122   PetscBool      exists;
123   char           *f;
124   PetscErrorCode ierr;
125 
126   PetscFunctionBegin;
127   ierr = PetscStrstr(string, defaultDbg, &f);CHKERRQ(ierr);
128   if (f) {
129     ierr = PetscTestFile(string, 'x', &exists);CHKERRQ(ierr);
130     if (exists) *debugger = string;
131     else        *debugger = defaultDbg;
132   }
133   PetscFunctionReturn(0);
134 }
135 
136 /*@C
137     PetscSetDebuggerFromString - Set the complete path for the
138        debugger for PETSc to use.
139 
140    Not collective
141 
142    Level: developer
143 
144 .seealso: PetscSetDebugger(), PetscSetDefaultDebugger()
145 @*/
146 PetscErrorCode  PetscSetDebuggerFromString(const char *string)
147 {
148   const char     *debugger = NULL;
149   PetscBool      xterm     = PETSC_TRUE;
150   char           *f;
151   PetscErrorCode ierr;
152 
153   PetscFunctionBegin;
154   ierr = PetscStrstr(string, "noxterm", &f);CHKERRQ(ierr);
155   if (f) xterm = PETSC_FALSE;
156   ierr = PetscStrstr(string, "ddd", &f);CHKERRQ(ierr);
157   if (f) xterm = PETSC_FALSE;
158   ierr = PetscCheckDebugger_Private("xdb",      string, &debugger);CHKERRQ(ierr);
159   ierr = PetscCheckDebugger_Private("dbx",      string, &debugger);CHKERRQ(ierr);
160   ierr = PetscCheckDebugger_Private("xldb",     string, &debugger);CHKERRQ(ierr);
161   ierr = PetscCheckDebugger_Private("gdb",      string, &debugger);CHKERRQ(ierr);
162   ierr = PetscCheckDebugger_Private("idb",      string, &debugger);CHKERRQ(ierr);
163   ierr = PetscCheckDebugger_Private("xxgdb",    string, &debugger);CHKERRQ(ierr);
164   ierr = PetscCheckDebugger_Private("ddd",      string, &debugger);CHKERRQ(ierr);
165   ierr = PetscCheckDebugger_Private("kdbg",     string, &debugger);CHKERRQ(ierr);
166   ierr = PetscCheckDebugger_Private("ups",      string, &debugger);CHKERRQ(ierr);
167   ierr = PetscCheckDebugger_Private("workshop", string, &debugger);CHKERRQ(ierr);
168   ierr = PetscCheckDebugger_Private("pgdbg",    string, &debugger);CHKERRQ(ierr);
169   ierr = PetscCheckDebugger_Private("pathdb",   string, &debugger);CHKERRQ(ierr);
170   ierr = PetscCheckDebugger_Private("lldb",     string, &debugger);CHKERRQ(ierr);
171 
172   ierr = PetscSetDebugger(debugger, xterm);CHKERRQ(ierr);
173   PetscFunctionReturn(0);
174 }
175 
176 
177 /*@
178    PetscAttachDebugger - Attaches the debugger to the running process.
179 
180    Not Collective
181 
182    Level: advanced
183 
184    Concepts: debugger^starting from program
185 
186    Developer Notes:
187     Since this can be called by the error handler should it be calling SETERRQ() and CHKERRQ()?
188 
189 .seealso: PetscSetDebugger()
190 @*/
191 PetscErrorCode  PetscAttachDebugger(void)
192 {
193 #if !defined(PETSC_CANNOT_START_DEBUGGER)
194   int            child    =0;
195   PetscReal      sleeptime=0;
196   PetscErrorCode ierr;
197   char           program[PETSC_MAX_PATH_LEN],display[256],hostname[64];
198 #endif
199 
200   PetscFunctionBegin;
201 #if defined(PETSC_CANNOT_START_DEBUGGER) || !defined(PETSC_HAVE_FORK)
202   (*PetscErrorPrintf)("System cannot start debugger\n");
203   (*PetscErrorPrintf)("On Cray run program in Totalview debugger\n");
204   (*PetscErrorPrintf)("On Windows use Developer Studio(MSDEV)\n");
205   MPI_Abort(PETSC_COMM_WORLD,1);
206 #else
207   ierr = PetscGetDisplay(display,128);CHKERRQ(ierr);
208   ierr = PetscGetProgramName(program,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
209   if (ierr) {
210     (*PetscErrorPrintf)("Cannot determine program name\n");
211     PetscFunctionReturn(1);
212   }
213   if (!program[0]) {
214     (*PetscErrorPrintf)("Cannot determine program name\n");
215     PetscFunctionReturn(1);
216   }
217   child = (int)fork();
218   if (child < 0) {
219     (*PetscErrorPrintf)("Error in fork() attaching debugger\n");
220     PetscFunctionReturn(1);
221   }
222 
223   /*
224       Swap role the parent and child. This is (I think) so that control c typed
225     in the debugger goes to the correct process.
226   */
227   if (child) child = 0;
228   else       child = (int)getppid();
229 
230   if (child) { /* I am the parent, will run the debugger */
231     const char *args[10];
232     char       pid[10];
233     PetscInt   j,jj;
234     PetscBool  isdbx,isidb,isxldb,isxxgdb,isups,isxdb,isworkshop,isddd,iskdbg,islldb;
235 
236     ierr = PetscGetHostName(hostname,64);CHKERRQ(ierr);
237     /*
238          We need to send a continue signal to the "child" process on the
239        alpha, otherwise it just stays off forever
240     */
241 #if defined(PETSC_NEED_KILL_FOR_DEBUGGER)
242     kill(child,SIGCONT);
243 #endif
244     sprintf(pid,"%d",child);
245 
246     ierr = PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);CHKERRQ(ierr);
247     ierr = PetscStrcmp(PetscDebugger,"ddd",&isddd);CHKERRQ(ierr);
248     ierr = PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);CHKERRQ(ierr);
249     ierr = PetscStrcmp(PetscDebugger,"ups",&isups);CHKERRQ(ierr);
250     ierr = PetscStrcmp(PetscDebugger,"xldb",&isxldb);CHKERRQ(ierr);
251     ierr = PetscStrcmp(PetscDebugger,"xdb",&isxdb);CHKERRQ(ierr);
252     ierr = PetscStrcmp(PetscDebugger,"dbx",&isdbx);CHKERRQ(ierr);
253     ierr = PetscStrcmp(PetscDebugger,"idb",&isidb);CHKERRQ(ierr);
254     ierr = PetscStrcmp(PetscDebugger,"workshop",&isworkshop);CHKERRQ(ierr);
255     ierr = PetscStrcmp(PetscDebugger,"lldb",&islldb);CHKERRQ(ierr);
256 
257     if (isxxgdb || isups || isddd) {
258       args[1] = program; args[2] = pid; args[3] = "-display";
259       args[0] = PetscDebugger; args[4] = display; args[5] = 0;
260       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
261       if (execvp(args[0],(char**)args)  < 0) {
262         perror("Unable to start debugger");
263         exit(0);
264       }
265     } else if (iskdbg) {
266       args[1] = "-p"; args[2] = pid; args[3] = program;  args[4] = "-display";
267       args[0] = PetscDebugger; args[5] = display; args[6] = 0;
268       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[3],pid,hostname);
269       if (execvp(args[0],(char**)args)  < 0) {
270         perror("Unable to start debugger");
271         exit(0);
272       }
273     } else if (isxldb) {
274       args[1] = "-a"; args[2] = pid; args[3] = program;  args[4] = "-display";
275       args[0] = PetscDebugger; args[5] = display; args[6] = 0;
276       printf("PETSC: Attaching %s to %s %s on %s\n",args[0],args[1],pid,hostname);
277       if (execvp(args[0],(char**)args)  < 0) {
278         perror("Unable to start debugger");
279         exit(0);
280       }
281     } else if (isworkshop) {
282       args[1] = "-s"; args[2] = pid; args[3] = "-D"; args[4] = "-";
283       args[0] = PetscDebugger; args[5] = pid; args[6] = "-display"; args[7] = display; args[8] = 0;
284       printf("PETSC: Attaching %s to %s on %s\n",args[0],pid,hostname);
285       if (execvp(args[0],(char**)args)  < 0) {
286         perror("Unable to start debugger");
287         exit(0);
288       }
289     } else {
290       j = 0;
291       if (Xterm) {
292         PetscBool cmp;
293         char      *tmp,*tmp1;
294         ierr = PetscStrncmp(DebugTerminal,"screen",6,&cmp);CHKERRQ(ierr);
295         if (!cmp) {ierr = PetscStrncmp(DebugTerminal,"gnome-terminal",6,&cmp);CHKERRQ(ierr);}
296         if (cmp) display[0] = 0; /* when using screen, we never pass -display */
297         args[j++] = tmp = DebugTerminal;
298         if (display[0]) {
299           args[j++] = "-display"; args[j++] = display;
300         }
301         while (*tmp) {
302           ierr = PetscStrchr(tmp,' ',&tmp1);CHKERRQ(ierr);
303           if (!tmp1) break;
304           *tmp1     = 0;
305           tmp       = tmp1+1;
306           args[j++] = tmp;
307         }
308       }
309       args[j++] = PetscDebugger;
310       jj = j;
311       args[j++] = program; args[j++] = pid; args[j++] = 0;
312 
313       if (isidb) {
314         j = jj;
315         args[j++] = "-pid";
316         args[j++] = pid;
317         args[j++] = "-gdb";
318         args[j++] = program;
319         args[j++] = 0;
320       }
321       if (islldb) {
322         j = jj;
323         args[j++] = "-p";
324         args[j++] = pid;
325         args[j++] = 0;
326       }
327       if (isdbx) {
328         j = jj;
329 #if defined(PETSC_USE_P_FOR_DEBUGGER)
330         args[j++] = "-p";
331         args[j++] = pid;
332         args[j++] = program;
333 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
334         args[j++] = "-l";
335         args[j++] = "ALL";
336         args[j++] = "-P";
337         args[j++] = pid;
338         args[j++] = program;
339 #elif defined(PETSC_USE_A_FOR_DEBUGGER)
340         args[j++] = "-a";
341         args[j++] = pid;
342 #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
343         args[j++] = "-pid";
344         args[j++] = pid;
345         args[j++] = program;
346 #else
347         args[j++] = program;
348         args[j++] = pid;
349 #endif
350         args[j++] = 0;
351       }
352       if (Xterm) {
353         if (display[0]) printf("PETSC: Attaching %s to %s of pid %s on display %s on machine %s\n",PetscDebugger,program,pid,display,hostname);
354         else            printf("PETSC: Attaching %s to %s on pid %s on %s\n",PetscDebugger,program,pid,hostname);
355 
356         if (execvp(args[0],(char**)args)  < 0) {
357           perror("Unable to start debugger in xterm");
358           exit(0);
359         }
360       } else {
361         printf("PETSC: Attaching %s to %s of pid %s on %s\n",PetscDebugger,program,pid,hostname);
362         if (execvp(args[0],(char**)args)  < 0) {
363           perror("Unable to start debugger");
364           exit(0);
365         }
366       }
367     }
368   } else {   /* I am the child, continue with user code */
369     sleeptime = 10; /* default to sleep waiting for debugger */
370     ierr = PetscOptionsGetReal(NULL,NULL,"-debugger_pause",&sleeptime,NULL);CHKERRQ(ierr);
371     if (sleeptime < 0) sleeptime = -sleeptime;
372 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
373     /*
374         HP cannot attach process to sleeping debugger, hence count instead
375     */
376     {
377       PetscReal x = 1.0;
378       int       i =10000000;
379       while (i--) x++;  /* cannot attach to sleeper */
380     }
381 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
382     /*
383         IBM sleep may return at anytime, hence must see if there is more time to sleep
384     */
385     {
386       int left = sleeptime;
387       while (left > 0) left = PetscSleep(left) - 1;
388     }
389 #else
390     PetscSleep(sleeptime);
391 #endif
392   }
393 #endif
394   PetscFunctionReturn(0);
395 }
396 
397 /*@C
398    PetscAttachDebuggerErrorHandler - Error handler that attaches
399    a debugger to a running process when an error is detected.
400    This routine is useful for examining variables, etc.
401 
402    Not Collective
403 
404    Input Parameters:
405 +  comm - communicator over which error occurred
406 .  line - the line number of the error (indicated by __LINE__)
407 .  file - the file in which the error was detected (indicated by __FILE__)
408 .  message - an error text string, usually just printed to the screen
409 .  number - the generic error number
410 .  p - PETSC_ERROR_INITIAL if error just detected, otherwise PETSC_ERROR_REPEAT
411 -  ctx - error handler context
412 
413    Options Database Keys:
414 .  -on_error_attach_debugger [noxterm,dbx,xxgdb,xdb,xldb,gdb] [-display name] - Activates
415    debugger attachment
416 
417    Level: developer
418 
419    Notes:
420    By default the GNU debugger, gdb, is used.  Alternatives are lldb, dbx and
421    xxgdb,xldb (on IBM rs6000), xdb (on HP-UX).
422 
423    Most users need not directly employ this routine and the other error
424    handlers, but can instead use the simplified interface SETERR, which has
425    the calling sequence
426 $     SETERRQ(PETSC_COMM_SELF,number,p,message)
427 
428    Notes for experienced users:
429    Use PetscPushErrorHandler() to set the desired error handler.  The
430    currently available PETSc error handlers are
431 $    PetscTraceBackErrorHandler()
432 $    PetscAttachDebuggerErrorHandler()
433 $    PetscAbortErrorHandler()
434    or you may write your own.
435 
436    Concepts: debugger^error handler
437    Concepts: error handler^attach debugger
438 
439 .seealso:  PetscPushErrorHandler(), PetscTraceBackErrorHandler(),
440            PetscAbortErrorHandler()
441 @*/
442 PetscErrorCode  PetscAttachDebuggerErrorHandler(MPI_Comm comm,int line,const char *fun,const char *file,PetscErrorCode num,PetscErrorType p,const char *mess,void *ctx)
443 {
444   PetscErrorCode ierr;
445 
446   PetscFunctionBegin;
447   if (!fun) fun = "User provided function";
448   if (!mess) mess = " ";
449 
450   (*PetscErrorPrintf)("%s() line %d in %s %s\n",fun,line,file,mess);
451 
452   ierr = PetscAttachDebugger();
453   if (ierr) abort(); /* call abort because don't want to kill other MPI processes that may successfully attach to debugger */
454   PetscFunctionReturn(0);
455 }
456 
457 /*@C
458    PetscStopForDebugger - Prints a message to the screen indicating how to
459          attach to the process with the debugger and then waits for the
460          debugger to attach.
461 
462    Not Collective
463 
464    Level: developer
465 
466    Notes:
467     This is likely never needed since PetscAttachDebugger() is easier to use and seems to always work.
468 
469    Developer Notes:
470     Since this can be called by the error handler, should it be calling SETERRQ() and CHKERRQ()?
471 
472    Concepts: debugger^waiting for attachment
473 
474 .seealso: PetscSetDebugger(), PetscAttachDebugger()
475 @*/
476 PetscErrorCode  PetscStopForDebugger(void)
477 {
478   PetscErrorCode ierr;
479   PetscInt       sleeptime=0;
480 #if !defined(PETSC_CANNOT_START_DEBUGGER)
481   int            ppid;
482   PetscMPIInt    rank;
483   char           program[PETSC_MAX_PATH_LEN],hostname[256];
484   PetscBool      isdbx,isxldb,isxxgdb,isddd,iskdbg,isups,isxdb,islldb;
485 #endif
486 
487   PetscFunctionBegin;
488 #if defined(PETSC_CANNOT_START_DEBUGGER)
489   (*PetscErrorPrintf)("System cannot start debugger; just continuing program\n");
490 #else
491   ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
492   if (ierr) rank = 0; /* ignore error since this may be already in error handler */
493   ierr = PetscGetHostName(hostname,256);
494   if (ierr) {
495     (*PetscErrorPrintf)("Cannot determine hostname; just continuing program\n");
496     PetscFunctionReturn(0);
497   }
498 
499   ierr = PetscGetProgramName(program,256);
500   if (ierr) {
501     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
502     PetscFunctionReturn(0);
503   }
504   if (!program[0]) {
505     (*PetscErrorPrintf)("Cannot determine program name; just continuing program\n");
506     PetscFunctionReturn(0);
507   }
508 
509   ppid = getpid();
510 
511   ierr = PetscStrcmp(PetscDebugger,"xxgdb",&isxxgdb);CHKERRQ(ierr);
512   ierr = PetscStrcmp(PetscDebugger,"ddd",&isddd);CHKERRQ(ierr);
513   ierr = PetscStrcmp(PetscDebugger,"kdbg",&iskdbg);CHKERRQ(ierr);
514   ierr = PetscStrcmp(PetscDebugger,"ups",&isups);CHKERRQ(ierr);
515   ierr = PetscStrcmp(PetscDebugger,"xldb",&isxldb);CHKERRQ(ierr);
516   ierr = PetscStrcmp(PetscDebugger,"xdb",&isxdb);CHKERRQ(ierr);
517   ierr = PetscStrcmp(PetscDebugger,"dbx",&isdbx);CHKERRQ(ierr);
518   ierr = PetscStrcmp(PetscDebugger,"lldb",&islldb);CHKERRQ(ierr);
519 
520   if (isxxgdb || isups || isddd || iskdbg) printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
521   else if (isxldb) printf("[%d]%s>>%s -a %d %s\n",rank,hostname,PetscDebugger,ppid,program);
522   else if (islldb) printf("[%d]%s>>%s -p %d\n",rank,hostname,PetscDebugger,ppid);
523   else if (isdbx) {
524 #if defined(PETSC_USE_P_FOR_DEBUGGER)
525      printf("[%d]%s>>%s -p %d %s\n",rank,hostname,PetscDebugger,ppid,program);
526 #elif defined(PETSC_USE_LARGEP_FOR_DEBUGGER)
527      printf("[%d]%s>>%s -l ALL -P %d %s\n",rank,hostname,PetscDebugger,ppid,program);
528 #elif defined(PETSC_USE_A_FOR_DEBUGGER)
529      printf("[%d]%s>>%s -a %d\n",rank,hostname,PetscDebugger,ppid);
530 #elif defined(PETSC_USE_PID_FOR_DEBUGGER)
531      printf("[%d]%s>>%s -pid %d %s\n",rank,hostname,PetscDebugger,ppid,program);
532 #else
533      printf("[%d]%s>>%s %s %d\n",rank,hostname,PetscDebugger,program,ppid);
534 #endif
535   }
536 #endif /* PETSC_CANNOT_START_DEBUGGER */
537 
538   fflush(stdout); /* ignore error because may already be in error handler */
539 
540   sleeptime = 25; /* default to sleep waiting for debugger */
541   PetscOptionsGetInt(NULL,NULL,"-debugger_pause",&sleeptime,NULL); /* ignore error because may already be in error handler */
542   if (sleeptime < 0) sleeptime = -sleeptime;
543 #if defined(PETSC_NEED_DEBUGGER_NO_SLEEP)
544   /*
545       HP cannot attach process to sleeping debugger, hence count instead
546   */
547   {
548     PetscReal x = 1.0;
549     int       i =10000000;
550     while (i--) x++;  /* cannot attach to sleeper */
551   }
552 #elif defined(PETSC_HAVE_SLEEP_RETURNS_EARLY)
553   /*
554       IBM sleep may return at anytime, hence must see if there is more time to sleep
555   */
556   {
557     int left = sleeptime;
558     while (left > 0) left = sleep(left) - 1;
559   }
560 #else
561   PetscSleep(sleeptime);
562 #endif
563   PetscFunctionReturn(0);
564 }
565 
566 
567 
568