1 //---------------------------------------------------------------------------
2 //----Program to watch CPU usage of a process
3 //----TreeLimitedRun <CPU time limit> <WC time limit> <Memory limit> <Job>
4 //---------------------------------------------------------------------------
5 //----SUN or LINUX or OSX (OSX is very generic)
6 #if (!defined(SUN) && !defined(LINUX) && !defined(OSX))
9 //---------------------------------------------------------------------------
13 #include <sys/resource.h>
14 #include <sys/types.h>
25 //---------------------------------------------------------------------------
26 #define STRING_LENGTH 80
27 #define MAX_PROCESSES 1000
28 #define DEFAULT_DELAY_BETWEEN_CHECKS 10
29 #define NANOSECONDS 1E9
30 #define MICROSECONDS 1E6
36 typedef char String[STRING_LENGTH];
43 double AccumulatedCPUTime;
46 typedef ProcessData ProcessDataArray[MAX_PROCESSES];
48 int GlobalInterrupted;
49 int GlobalSignalReceived;
50 //---------------------------------------------------------------------------
51 void SIGCHLDHandler(int TheSignal) {
53 //DEBUG printf("Some child has died\n");
54 //----The child is reaped in WatchChildTree
57 //---------------------------------------------------------------------------
58 void SIGCHLDReaper(int TheSignal) {
63 while ((DeadPID = waitpid(-1,&Status,WNOHANG)) > 0) {
64 //DEBUG printf("!!! Child %d of TreeLimitedRun %d has died\n",DeadPID,getpid());fflush(stdout);
68 //---------------------------------------------------------------------------
69 //----Controllers in the CASC/SystemOnTPTP/SSCPA/etc hierarchy may send
70 //----SIGQUIT to stop things
71 void SIGQUITHandler(int TheSignal) {
73 //DEBUG printf("!!! TreeLimitedRun %d got a signal %d\n",getpid(),TheSignal);fflush(stdout);
74 GlobalInterrupted = 1;
75 GlobalSignalReceived = TheSignal;
78 //---------------------------------------------------------------------------
79 void SetCPUTimeLimit(rlim_t CPUTimeLimit) {
81 struct rlimit ResourceLimits;
83 //----Set the signal handler
84 //----No point - signals are reset on exec
85 //----For some reason this is still needed, or the signal doesn't work
86 if (signal(SIGXCPU,SIGQUITHandler) == SIG_ERR) {
87 perror("Setting signal handler");
91 //----Limit the CPU time. Need to get old one for hard limit field
92 if (getrlimit(RLIMIT_CPU,&ResourceLimits) == -1) {
93 perror("Getting CPU limit");
96 //----Set new CPU limit in ms (sent in secs)
97 ResourceLimits.rlim_cur = CPUTimeLimit;
98 if (setrlimit(RLIMIT_CPU,&ResourceLimits) == -1) {
99 perror("Setting CPU limit");
103 //-----------------------------------------------------------------------------
104 void SetMemoryLimit(rlim_t MemoryLimit) {
106 struct rlimit ResourceLimits;
109 #define THE_LIMIT RLIMIT_AS
111 #define THE_LIMIT RLIMIT_DATA
114 //----Limit the memory. Need to get old one for hard limit field
115 if (getrlimit(THE_LIMIT,&ResourceLimits) == -1) {
116 perror("Getting memory limit");
119 //----Set new memory limit
120 ResourceLimits.rlim_max = MemoryLimit;
121 ResourceLimits.rlim_cur = MemoryLimit;
122 if (setrlimit(THE_LIMIT,&ResourceLimits) == -1) {
123 perror("Setting memory limit");
127 //---------------------------------------------------------------------------
128 //----Prevent core dumps that occur on timeout
129 void SetNoCoreDump(void) {
131 struct rlimit ResourceLimits;
133 //----Get old resource limits
134 if (getrlimit(RLIMIT_CORE,&ResourceLimits) == -1) {
135 perror("Getting resource limit:");
138 //----Set new core limit to 0
139 ResourceLimits.rlim_cur = 0;
140 if (setrlimit(RLIMIT_CORE,&ResourceLimits) == -1) {
141 perror("Setting resource limit:");
145 //---------------------------------------------------------------------------
147 void GetProcessesOwnedByMe(uid_t MyRealUID,ProcessDataArray OwnedPIDs,
148 int *NumberOfOwnedPIDs) {
151 struct dirent *ProcessDir;
154 String ProcFileName,Line;
156 if ((ProcDir = opendir("/proc")) == NULL) {
157 perror("ERROR: Cannot opendir /proc\n");
160 //DEBUG printf("look for processes owned by %d\n",MyRealUID);
162 *NumberOfOwnedPIDs = 0;
163 while ((ProcessDir = readdir(ProcDir)) != NULL) {
164 if (isdigit(ProcessDir->d_name[0])) {
165 PID = (pid_t)atoi(ProcessDir->d_name);
166 sprintf(ProcFileName,"/proc/%d/status",PID);
167 if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
170 while ((PPID == -1 || UID == -1) &&
171 fgets(Line,STRING_LENGTH,ProcFile) != NULL) {
172 sscanf(Line,"PPid: %d",&PPID);
173 sscanf(Line,"Uid: %d",&UID);
176 //----Check that data was found
177 //DEBUG printf("PID = %d PPID = %d UID = %d\n",PID,PPID,UID);
178 if (PPID == -1 || UID == -1) {
179 fprintf(stderr,"Could not get process information\n");
182 //----Check if this process is owned by this user
183 if (UID == MyRealUID) {
184 //----Record the PIDs as potentially relevant
185 OwnedPIDs[*NumberOfOwnedPIDs].Active = 1;
186 OwnedPIDs[*NumberOfOwnedPIDs].PID = PID;
187 OwnedPIDs[*NumberOfOwnedPIDs].PPID = PPID;
188 (*NumberOfOwnedPIDs)++;
189 //DEBUG printf("%d I own PID = %d PPID = %d UID = %d\n",*NumberOfOwnedPIDs,PID,PPID,UID);
190 if (*NumberOfOwnedPIDs >= MAX_PROCESSES) {
191 fprintf(stderr,"ERROR: Out of save process space\n");
196 //----Bloody child just died
202 //---------------------------------------------------------------------------
203 float GetProcessTime(pid_t PID,int IncludeSelf,int IncludeChildren) {
207 float MyTime,ChildTime,ProcessTime;
208 int UserModeJiffies,SystemModeJiffies,ChildUserModeJiffies,
209 ChildSystemModeJiffies;
212 sprintf(ProcFileName,"/proc/%d/stat",PID);
213 if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
214 fscanf(ProcFile,"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %d %d %d %d",&UserModeJiffies,&SystemModeJiffies,&ChildUserModeJiffies,
215 &ChildSystemModeJiffies);
217 //DEBUG printf("%d: my jiffies = %d, dead child jiffies = %d\n",PID,UserModeJiffies+SystemModeJiffies,ChildUserModeJiffies+ChildSystemModeJiffies);
218 //----Time used by this process
219 MyTime = ((float)(UserModeJiffies + SystemModeJiffies))/JIFFIES;
220 //----Time used by this process's dead children (man pages are wrong - does
221 //----not include my jiffies)
222 ChildTime = ((float)(ChildUserModeJiffies + ChildSystemModeJiffies))/
225 ProcessTime += MyTime;
227 if (IncludeChildren) {
228 ProcessTime += ChildTime;
230 //DEBUG printf("Process time for %d is %f\n",PID,ProcessTime);
233 //----Bloody process died, return 0 and catch it in the parent next time
238 //---------------------------------------------------------------------------
240 void GetProcessesOwnedByMe(uid_t MyRealUID,ProcessDataArray OwnedPIDs,
241 int *NumberOfOwnedPIDs) {
244 struct dirent *ProcessDir;
246 struct psinfo ProcessRecord;
250 if ((ProcDir = opendir("/proc")) == NULL) {
251 perror("ERROR: Cannot opendir /proc\n");
255 //DEBUG printf("look for processes owned by %d\n",MyRealUID);
257 *NumberOfOwnedPIDs = 0;
258 while ((ProcessDir = readdir(ProcDir)) != NULL) {
259 if (isdigit((int)ProcessDir->d_name[0])) {
260 PID = (pid_t)atoi(ProcessDir->d_name);
261 sprintf(ProcFileName,"/proc/%d/psinfo",(int)PID);
262 if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
263 fread(&ProcessRecord,sizeof(ProcessRecord),1,ProcFile);
265 //----Check if this process is owned by this user
266 if (ProcessRecord.pr_uid == MyRealUID) {
267 //----Record the PIDs as potentially relevant
268 OwnedPIDs[*NumberOfOwnedPIDs].PID = PID;
269 OwnedPIDs[*NumberOfOwnedPIDs].PPID = ProcessRecord.pr_ppid;
270 (*NumberOfOwnedPIDs)++;
271 if (*NumberOfOwnedPIDs >= MAX_PROCESSES) {
272 fprintf(stderr,"ERROR: Out of save process space\n");
277 //----Bloody child just died
283 //---------------------------------------------------------------------------
284 float GetProcessTime(pid_t PID,int IncludeSelf,int IncludeChildren) {
288 pstatus_t StatusRecord;
292 sprintf(ProcFileName,"/proc/%d/status",(int)PID);
293 if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
294 fread(&StatusRecord,sizeof(StatusRecord),1,ProcFile);
297 ProcessTime += StatusRecord.pr_utime.tv_sec +
298 StatusRecord.pr_stime.tv_sec +
299 ((float)(StatusRecord.pr_utime.tv_nsec+StatusRecord.pr_stime.tv_nsec))/
302 if (IncludeChildren) {
303 ProcessTime += StatusRecord.pr_cutime.tv_sec +
304 StatusRecord.pr_cstime.tv_sec +
305 ((float)(StatusRecord.pr_cutime.tv_nsec+StatusRecord.pr_cstime.tv_nsec))/
308 //DEBUG printf("Process %d has used U %ld +n%ld + S %ld +n%ld + CU %ld +n%ld + CS %ld +n%ld = %.1f\n",
309 //DEBUG PID,StatusRecord.pr_utime.tv_sec,StatusRecord.pr_utime.tv_nsec,
310 //DEBUG StatusRecord.pr_stime.tv_sec,StatusRecord.pr_stime.tv_nsec,
311 //DEBUG StatusRecord.pr_cutime.tv_sec,StatusRecord.pr_cutime.tv_nsec,
312 //DEBUG StatusRecord.pr_cstime.tv_sec,StatusRecord.pr_cstime.tv_nsec,
313 //DEBUG ProcessTime);
316 //----Bloody child died, return 0 and catch it in the parent next time
321 //---------------------------------------------------------------------------
323 //----No looking in /proc for OSX
325 //---------------------------------------------------------------------------
326 int PIDInArray(pid_t PID,ProcessDataArray PIDs,int NumberOfPIDs) {
330 for (PIDIndex = 0;PIDIndex < NumberOfPIDs;PIDIndex++) {
331 if (PIDs[PIDIndex].PID == PID) {
337 //---------------------------------------------------------------------------
338 #if (defined(LINUX)||defined(SUN))
339 //----Only for systems that have /proc
341 int GetTreeTimes(uid_t MyRealUID,pid_t FirstBornPID,ProcessDataArray
344 ProcessDataArray OwnedPIDs;
345 int NumberOfOwnedPIDs;
346 int NumberOfTreeTimes;
347 int CurrentTreeIndex;
350 //----Get the list of processes owned by this user
351 GetProcessesOwnedByMe(MyRealUID,OwnedPIDs,&NumberOfOwnedPIDs);
353 //----Check that the root of the tree is still there
354 //DEBUG printf("Check if %d is alive\n",FirstBornPID);
355 if (!PIDInArray(FirstBornPID,OwnedPIDs,NumberOfOwnedPIDs)) {
356 //DEBUG printf("It is dead\n");
359 //DEBUG printf("It is alive\n");
361 //----Find those in the process tree, and get their times
362 CurrentTreeIndex = 0;
363 TreeTimes[0].Active = 1;
364 TreeTimes[0].PID = FirstBornPID;
365 TreeTimes[0].PPID = MyRealUID;
366 TreeTimes[0].CPUTime = GetProcessTime(TreeTimes[0].PID,1,1);
367 NumberOfTreeTimes = 1;
369 while (CurrentTreeIndex < NumberOfTreeTimes) {
370 //DEBUG printf("%d %d is in the tree\n",TreeTimes[CurrentTreeIndex].PID,TreeTimes[CurrentTreeIndex].PPID);
371 //----Scan for offspring
372 TreeTimes[CurrentTreeIndex].CPUTime =
373 GetProcessTime(TreeTimes[CurrentTreeIndex].PID,1,1);
374 for (OwnedIndex = 0; OwnedIndex < NumberOfOwnedPIDs; OwnedIndex++) {
375 if (OwnedPIDs[OwnedIndex].PPID == TreeTimes[CurrentTreeIndex].PID) {
376 TreeTimes[NumberOfTreeTimes].Active = 1;
377 TreeTimes[NumberOfTreeTimes].PID = OwnedPIDs[OwnedIndex].PID;
378 TreeTimes[NumberOfTreeTimes].PPID = OwnedPIDs[OwnedIndex].PPID;
382 //----Move on to the next process in the tree
386 return(NumberOfTreeTimes);
391 //----No /proc for OSX
393 //---------------------------------------------------------------------------
394 //----Send signals and reports if process is known to be gone
395 int SignalAndReport(int PID,int Signal,int RepeatUntilTerminated,
396 char * ProcessType) {
407 //DEBUG printf("!!! TreeLimitedRun %d sends signal %d to %s %d\n",getpid(),Signal,ProcessType,PID);fflush(stdout);
408 if (kill(PID,Signal) != 0) {
409 //DEBUG printf("The kill errno is %d\n",errno);
410 //----If process no longer exists record that to avoid killing again
411 if (errno == ESRCH) {
414 sprintf(ErrorMessage,
415 "!!! ERROR: TreeLimitedRun %d cannot signal %s %d with %d",getpid(),ProcessType,
417 perror(ErrorMessage);
420 //----Must do perror after errno, as perror clears errno
421 } while (RepeatUntilTerminated && !Terminated && NumberOfLoops < 10);
425 //---------------------------------------------------------------------------
426 void ChildKillTree(int TargetIndex,ProcessDataArray TreeTimes,
427 int NumberInTree,int Signal) {
431 //DEBUG printf("!!! TreeLimitedRun %d killing tree below PID %d with %d\n",getpid(),TreeTimes[TargetIndex].PID,Signal);fflush(stdout);
432 for (ChildIndex=0; ChildIndex < NumberInTree; ChildIndex++) {
433 if (TreeTimes[TargetIndex].PID == TreeTimes[ChildIndex].PPID) {
434 ChildKillTree(ChildIndex,TreeTimes,NumberInTree,Signal);
436 //TOO SLOW? usleep(100000);
438 if (TreeTimes[TargetIndex].Active) {
439 if (SignalAndReport(TreeTimes[TargetIndex].PID,Signal,
440 Signal == SIGKILL,"tree process")) {
441 TreeTimes[TargetIndex].Active = 0;
445 //---------------------------------------------------------------------------
446 int KillTree(uid_t MyRealUID,pid_t FirstBornPID,int Signal) {
448 int NumberOfTreeTimes;
451 #if (defined(LINUX)||defined(SUN))
452 ProcessDataArray TreeTimes;
454 if ((NumberOfTreeTimes = GetTreeTimes(MyRealUID,FirstBornPID,TreeTimes)) >
457 //----The first born gets it first so that it can curb its descendants nicely
458 if (TreeTimes[0].Active) {
459 //DEBUG printf("!!! TreeLimitedRun %d killing top process %d with %d\n",getpid(),TreeTimes[0].PID,Signal);fflush(stdout);
460 //----TreeTimes[0].PID is FirstBornPID
461 if (SignalAndReport(TreeTimes[0].PID,Signal,Signal == SIGKILL,
463 TreeTimes[0].Active = 0;
467 //----200000 is not enough - EP's eproof script gets killed before it can
470 //----Now gently from the bottom up
471 ChildKillTree(0,TreeTimes,NumberOfTreeTimes,Signal);
473 //----Now viciously from the bottom up
474 ChildKillTree(0,TreeTimes,NumberOfTreeTimes,SIGKILL);
481 //----The first born gets it first so that it can curb its descendants nicely
482 if (SignalAndReport(FirstBornPID,Signal,Signal == SIGKILL,"top process")) {
488 SignalAndReport(FirstBornPID,SIGKILL,1,"only process");
490 NumberOfTreeTimes = 1;
493 return(NumberOfTreeTimes);
495 //---------------------------------------------------------------------------
496 void KillOrphans(uid_t MyRealUID,ProcessDataArray SavePIDs,
497 int NumberOfSavePIDs) {
499 #if (defined(LINUX)||defined(SUN))
501 ProcessDataArray OwnedPIDs;
502 int NumberOfOwnedPIDs;
504 int NumberOfOrphansKilled;
508 //----Get the list of processes owned by this user
509 GetProcessesOwnedByMe(MyRealUID,OwnedPIDs,&NumberOfOwnedPIDs);
511 NumberOfOrphansKilled = 0;
512 for (OwnedIndex = 0; OwnedIndex < NumberOfOwnedPIDs; OwnedIndex++) {
513 //DEBUG printf("!!! TreeLimitedRun %d considers %d with parent %d\n",getpid(),OwnedPIDs[OwnedIndex].PID, OwnedPIDs[OwnedIndex].PPID);fflush(stdout);
514 if (OwnedPIDs[OwnedIndex].PPID == 1 &&
515 !PIDInArray(OwnedPIDs[OwnedIndex].PID,SavePIDs,NumberOfSavePIDs)) {
516 //DEBUG printf("!!! TreeLimitedRun %d kills orphan %d\n",getpid(),OwnedPIDs[OwnedIndex].PID);fflush(stdout);
517 if (SignalAndReport(OwnedPIDs[OwnedIndex].PID,SIGQUIT,0,
519 OwnedPIDs[OwnedIndex].Active = 0;
521 if (OwnedPIDs[OwnedIndex].Active) {
523 SignalAndReport(OwnedPIDs[OwnedIndex].PID,SIGKILL,1,
526 NumberOfOrphansKilled++;
529 if (NumberOfOrphansKilled > 0) {
530 printf("Killed %d orphans\n",NumberOfOrphansKilled);
532 } while (NumberOfOrphansKilled > 0);
536 //----No orphans known for OSX
539 //---------------------------------------------------------------------------
540 void PrintTimes(char* Tag,float TreeCPUTime,float WCTime) {
542 //----You can print times with more accuracy here
543 printf("%s: %.1f CPU %.1f WC\n",Tag,TreeCPUTime,WCTime);
546 //---------------------------------------------------------------------------
547 float WallClockSoFar(struct timeval WCStartTime) {
549 struct timeval WCEndTime;
551 gettimeofday(&WCEndTime,NULL);
552 //DEBUG printf("Started at %ld +%f and ended at %ld +%f\n",
553 //DEBUG WCStartTime.tv_sec,WCStartTime.tv_usec/MICROSECONDS,
554 //DEBUG WCEndTime.tv_sec,WCEndTime.tv_usec/MICROSECONDS);
556 return((WCEndTime.tv_sec - WCStartTime.tv_sec) +
557 (WCEndTime.tv_usec - WCStartTime.tv_usec)/MICROSECONDS);
560 //---------------------------------------------------------------------------
561 double AccumulateTreeTime(int TargetIndex,ProcessDataArray TreeTimes,
566 TreeTimes[TargetIndex].AccumulatedCPUTime = TreeTimes[TargetIndex].CPUTime;
567 for (ChildIndex=0; ChildIndex < NumberInTree; ChildIndex++) {
568 if (TreeTimes[TargetIndex].PID == TreeTimes[ChildIndex].PPID) {
569 TreeTimes[TargetIndex].AccumulatedCPUTime +=
570 AccumulateTreeTime(ChildIndex,TreeTimes,NumberInTree);
574 return(TreeTimes[TargetIndex].AccumulatedCPUTime);
576 //---------------------------------------------------------------------------
577 float WatchChildTree(int MyPID,int ChildPID,int CPUTimeLimit,
578 int DelayBetweenChecks,struct timeval WCStartTime,int PrintEachCheck) {
580 double TreeTime,LastTreeTime,LostTime;
585 #if (defined(LINUX)||defined(SUN))
586 ProcessDataArray TreeTimes;
589 struct rusage ResourceUsage;
595 //----Loop watching times taken. Order is important - get time before
596 //----checking for interrupt
598 #if (defined(LINUX)||defined(SUN))
599 //----Look at the tree
600 NumberInTree = GetTreeTimes(getuid(),ChildPID,TreeTimes);
601 TreeTime = AccumulateTreeTime(0,TreeTimes,NumberInTree);
602 //DEBUG fprintf(stderr,"now %5.2f limit %d\n",TreeTime,CPUTimeLimit);
603 //----For those with /proc, reap the children. Need to reap late so /proc
604 //----entries do not disappear
605 while ((DeadPID = waitpid(-1,&Status,WNOHANG)) > 0) {
607 //DEBUG fprintf(stderr,"The child %d has died\n",DeadPID);
611 //----Check if child is gone (-1 if no child, 0 if not dead, PID if dead)
612 DeadPID = waitpid(-1,&Status,WNOHANG);
613 if (DeadPID == ChildPID || DeadPID == -1) {
614 TreeTime = LastTreeTime;
617 //----Maybe more than 1, but we don't know in OSX version
620 if (getrusage(RUSAGE_CHILDREN,&ResourceUsage) != -1) {
621 TreeTime = ResourceUsage.ru_utime.tv_sec +
622 ResourceUsage.ru_utime.tv_usec / 1000000 + ResourceUsage.ru_stime.tv_sec +
623 ResourceUsage.ru_stime.tv_usec / 1000000;
625 printf("TreeLimitedRun could not getrusage\n");
626 TreeTime = LastTreeTime;
630 //DEBUG fprintf(stderr,"acc time is %.2f\n",TreeTime);
631 if (TreeTime < LastTreeTime) {
632 LostTime += LastTreeTime - TreeTime;
633 printf("WARNING: TreeLimitedRun lost %.2fs, total lost is %.2fs\n",
634 LastTreeTime - TreeTime,LostTime);
636 //DEBUG printf("lost time is %.2f\n",LostTime);
637 LastTreeTime = TreeTime;
638 TreeTime += LostTime;
640 //----Print each loop if requested
641 if (PrintEachCheck) {
642 PrintTimes("WATCH",TreeTime,WallClockSoFar(WCStartTime));
644 //----If we're going to loop, wait a bit first
645 //----DANGER - if the last descedantprocess dies between GetTreeTimes() and
646 //----here, it still waits.
647 if ((CPUTimeLimit == 0 || TreeTime <= CPUTimeLimit) &&
648 NumberInTree > 0 && !GlobalInterrupted) {
649 sleep(DelayBetweenChecks);
651 } while ((CPUTimeLimit == 0 || TreeTime <= CPUTimeLimit) &&
652 NumberInTree > 0 && !GlobalInterrupted);
654 //----From now on reap normally
655 if (signal(SIGCHLD,SIGCHLDReaper) == SIG_ERR) {
656 perror("ERROR: Could not set SIGCHLD handler");
659 //----Reap anyway in case I missed some
662 //----If over time limit, stop them all (XCPU to top guy first)
663 if (NumberInTree > 0 && TreeTime > CPUTimeLimit) {
664 KilledInTree = KillTree(getuid(),ChildPID,SIGXCPU);
665 //DEBUG printf("Killed %d in tree\n",KilledInTree);
668 //----If global interrupted, then send it on
669 if (NumberInTree > 0 && GlobalInterrupted) {
670 KilledInTree = KillTree(getuid(),ChildPID,GlobalSignalReceived);
671 //DEBUG printf("Killed %d in tree\n",KilledInTree);
676 //---------------------------------------------------------------------------
677 int main(int argc,char *argv[]) {
688 struct timeval WCStartTime;
689 int DelayBetweenChecks;
690 int PrintEachCheck = 0;
691 ProcessDataArray SavePIDs;
692 int NumberOfSavePIDs;
695 //----Check the quietness level
696 if (argc >= 2 && strstr(argv[1],"-q") == argv[1]) {
698 QuietnessLevel = atoi(&argv[ArgOffset][2]);
704 //----Look for time and print flags
705 if (argc >= ArgOffset+2 &&
706 strstr(argv[ArgOffset+1],"-t") == argv[ArgOffset+1]) {
708 DelayBetweenChecks = atoi(&argv[ArgOffset][2]);
710 if (argc >= ArgOffset+2 &&
711 strstr(argv[ArgOffset+1],"-p") == argv[ArgOffset+1]) {
714 DelayBetweenChecks = atoi(&argv[ArgOffset][2]);
716 DelayBetweenChecks = DEFAULT_DELAY_BETWEEN_CHECKS;
720 if (argc - ArgOffset >= 4) {
721 //----Redirect stderr to stdout
722 if (dup2(STDOUT,STDERR) == -1) {
723 perror("ERROR: Cannot dup STDERR to STDOUT");
726 //----Extract time limits
727 CPUTimeLimit = atoi(argv[ArgOffset+1]);
728 WCTimeLimit = atoi(argv[ArgOffset+2]);
729 if (isdigit((int)argv[ArgOffset+3][0])) {
730 MemoryLimit = atoi(argv[ArgOffset+3]);
736 if (QuietnessLevel == 0) {
738 "TreeLimitedRun: ----------------------------------------------------------\n");
739 printf("TreeLimitedRun: %s ",argv[ArgOffset+3]);
740 for (ArgNumber=ArgOffset+4;ArgNumber<argc;ArgNumber++)
741 printf("%s ",argv[ArgNumber]);
743 printf("TreeLimitedRun: CPU time limit is %ds\n",CPUTimeLimit);
744 printf("TreeLimitedRun: WC time limit is %ds\n",WCTimeLimit);
745 if (MemoryLimit > 0) {
746 printf("TreeLimitedRun: Memory limit is %dbytes\n",
749 //----Output the PID for possible later use
750 printf("TreeLimitedRun: PID is %d\n",(int)getpid());
752 "TreeLimitedRun: ----------------------------------------------------------\n");
757 //----Set handler for when child dies
758 if (signal(SIGCHLD,SIGCHLDHandler) == SIG_ERR) {
759 perror("ERROR: Could not set SIGCHLD handler");
762 //----Set handler for global interruptions and alarms
763 GlobalInterrupted = 0;
764 GlobalSignalReceived = 0;
765 if (signal(SIGQUIT,SIGQUITHandler) == SIG_ERR) {
766 perror("ERROR: Could not set SIGQUIT handler");
769 if (signal(SIGALRM,SIGQUITHandler) == SIG_ERR) {
770 perror("ERROR: Could not set SIGALRM handler");
774 #if (defined(LINUX)||defined(SUN))
775 //----Record running processes at start (xeyes, gnome, etc)
776 GetProcessesOwnedByMe(getuid(),SavePIDs,&NumberOfSavePIDs);
779 //----No recording processes for OSX
782 //----Fork for ATP process
783 if ((ChildPID = fork()) == -1) {
784 perror("ERROR: Cannot fork for ATP system process");
788 //----In child, set limits and execute the ATP system
790 if (setvbuf(stdout,NULL,_IONBF,0) != 0) {
791 perror("Setting unbuffered");
793 //DEBUG printf("The prover PID will be %d\n",getpid());
794 //----Set memory limit for child only
795 if (MemoryLimit > 0) {
796 SetMemoryLimit(MemoryLimit);
799 #if (defined(LINUX)||defined(SUN))
800 //----Systems with /proc are stopped by this program with kill
803 //----In OSX case, child must limit itself
804 if (CPUTimeLimit > 0) {
805 SetCPUTimeLimit(CPUTimeLimit);
809 execvp(argv[ArgOffset+3],argv+ArgOffset+3);
810 perror("Cannot exec");
813 //----In parent, set limits and watch the ATP system
815 if (WCTimeLimit > 0) {
818 //----Record start time
819 gettimeofday(&WCStartTime,NULL);
823 //----Watch the tree of processes
824 TreeCPUTime = WatchChildTree(getpid(),ChildPID,CPUTimeLimit,
825 DelayBetweenChecks,WCStartTime,PrintEachCheck);
827 //----Record end WC time
828 WCTime = WallClockSoFar(WCStartTime);
830 //----See if the time is increased by looking at my children
831 //----Not sure what this was for
832 // ChildTime = GetProcessTime(getpid(),0,1);
833 // if (ChildTime > TreeCPUTime) {
834 // TreeCPUTime = ChildTime;
837 PrintTimes("FINAL WATCH",TreeCPUTime,WCTime);
839 //----Sweep for orphans
840 KillOrphans(getuid(),SavePIDs,NumberOfSavePIDs);
841 //----Reap any remaining
842 while (wait(&Status) != -1) {
844 //DEBUG printf("!!! Waiting for children that havn't died\n");
848 printf("Usage: %s [-q<quietness>] [-t<check delay>|-p<print check delay>] <CPU limit> <WC limit> [<Memory limit>] <Job>\n",
854 //---------------------------------------------------------------------------