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