--- /dev/null
+//---------------------------------------------------------------------------
+//----Program to watch CPU usage of a process
+//----TreeLimitedRun <CPU time limit> <WC time limit> <Memory limit> <Job>
+//---------------------------------------------------------------------------
+//----SUN or LINUX or OSX (OSX is very generic)
+#if (!defined(SUN) && !defined(LINUX) && !defined(OSX))
+ #define LINUX
+#endif
+//---------------------------------------------------------------------------
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#ifdef SUN
+#include <procfs.h>
+#endif
+//---------------------------------------------------------------------------
+#define STRING_LENGTH 80
+#define MAX_PROCESSES 1000
+#define DEFAULT_DELAY_BETWEEN_CHECKS 10
+#define NANOSECONDS 1E9
+#define MICROSECONDS 1E6
+#define JIFFIES 100
+
+#define STDOUT 1
+#define STDERR 2
+
+typedef char String[STRING_LENGTH];
+
+typedef struct {
+ int Active;
+ pid_t PID;
+ pid_t PPID;
+ double CPUTime;
+ double AccumulatedCPUTime;
+} ProcessData;
+
+typedef ProcessData ProcessDataArray[MAX_PROCESSES];
+
+int GlobalInterrupted;
+int GlobalSignalReceived;
+//---------------------------------------------------------------------------
+void SIGCHLDHandler(int TheSignal) {
+
+//DEBUG printf("Some child has died\n");
+//----The child is reaped in WatchChildTree
+
+}
+//---------------------------------------------------------------------------
+void SIGCHLDReaper(int TheSignal) {
+
+ int DeadPID;
+ int Status;
+
+ while ((DeadPID = waitpid(-1,&Status,WNOHANG)) > 0) {
+//DEBUG printf("!!! Child %d of TreeLimitedRun %d has died\n",DeadPID,getpid());fflush(stdout);
+ }
+
+}
+//---------------------------------------------------------------------------
+//----Controllers in the CASC/SystemOnTPTP/SSCPA/etc hierarchy may send
+//----SIGQUIT to stop things
+void SIGQUITHandler(int TheSignal) {
+
+//DEBUG printf("!!! TreeLimitedRun %d got a signal %d\n",getpid(),TheSignal);fflush(stdout);
+ GlobalInterrupted = 1;
+ GlobalSignalReceived = TheSignal;
+
+}
+//---------------------------------------------------------------------------
+void SetCPUTimeLimit(rlim_t CPUTimeLimit) {
+
+ struct rlimit ResourceLimits;
+
+//----Set the signal handler
+//----No point - signals are reset on exec
+//----For some reason this is still needed, or the signal doesn't work
+ if (signal(SIGXCPU,SIGQUITHandler) == SIG_ERR) {
+ perror("Setting signal handler");
+ exit(EXIT_FAILURE);
+ }
+
+//----Limit the CPU time. Need to get old one for hard limit field
+ if (getrlimit(RLIMIT_CPU,&ResourceLimits) == -1) {
+ perror("Getting CPU limit");
+ exit(EXIT_FAILURE);
+ }
+//----Set new CPU limit in ms (sent in secs)
+ ResourceLimits.rlim_cur = CPUTimeLimit;
+ if (setrlimit(RLIMIT_CPU,&ResourceLimits) == -1) {
+ perror("Setting CPU limit");
+ exit(EXIT_FAILURE);
+ }
+}
+//-----------------------------------------------------------------------------
+void SetMemoryLimit(rlim_t MemoryLimit) {
+
+ struct rlimit ResourceLimits;
+
+#ifdef RLIMIT_AS
+#define THE_LIMIT RLIMIT_AS
+#else
+#define THE_LIMIT RLIMIT_DATA
+#endif
+
+//----Limit the memory. Need to get old one for hard limit field
+ if (getrlimit(THE_LIMIT,&ResourceLimits) == -1) {
+ perror("Getting memory limit");
+ exit(EXIT_FAILURE);
+ }
+//----Set new memory limit
+ ResourceLimits.rlim_max = MemoryLimit;
+ ResourceLimits.rlim_cur = MemoryLimit;
+ if (setrlimit(THE_LIMIT,&ResourceLimits) == -1) {
+ perror("Setting memory limit");
+ exit(EXIT_FAILURE);
+ }
+}
+//---------------------------------------------------------------------------
+//----Prevent core dumps that occur on timeout
+void SetNoCoreDump(void) {
+
+ struct rlimit ResourceLimits;
+
+//----Get old resource limits
+ if (getrlimit(RLIMIT_CORE,&ResourceLimits) == -1) {
+ perror("Getting resource limit:");
+ exit(EXIT_FAILURE);
+ }
+//----Set new core limit to 0
+ ResourceLimits.rlim_cur = 0;
+ if (setrlimit(RLIMIT_CORE,&ResourceLimits) == -1) {
+ perror("Setting resource limit:");
+ exit(EXIT_FAILURE);
+ }
+}
+//---------------------------------------------------------------------------
+#ifdef LINUX
+void GetProcessesOwnedByMe(uid_t MyRealUID,ProcessDataArray OwnedPIDs,
+int *NumberOfOwnedPIDs) {
+
+ DIR *ProcDir;
+ struct dirent *ProcessDir;
+ pid_t UID,PID,PPID;
+ FILE *ProcFile;
+ String ProcFileName,Line;
+
+ if ((ProcDir = opendir("/proc")) == NULL) {
+ perror("ERROR: Cannot opendir /proc\n");
+ exit(EXIT_FAILURE);
+ }
+//DEBUG printf("look for processes owned by %d\n",MyRealUID);
+
+ *NumberOfOwnedPIDs = 0;
+ while ((ProcessDir = readdir(ProcDir)) != NULL) {
+ if (isdigit(ProcessDir->d_name[0])) {
+ PID = (pid_t)atoi(ProcessDir->d_name);
+ sprintf(ProcFileName,"/proc/%d/status",PID);
+ if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
+ PPID = -1;
+ UID = -1;
+ while ((PPID == -1 || UID == -1) &&
+fgets(Line,STRING_LENGTH,ProcFile) != NULL) {
+ sscanf(Line,"PPid: %d",&PPID);
+ sscanf(Line,"Uid: %d",&UID);
+ }
+ fclose(ProcFile);
+//----Check that data was found
+//DEBUG printf("PID = %d PPID = %d UID = %d\n",PID,PPID,UID);
+ if (PPID == -1 || UID == -1) {
+ fprintf(stderr,"Could not get process information\n");
+ exit(EXIT_FAILURE);
+ }
+//----Check if this process is owned by this user
+ if (UID == MyRealUID) {
+//----Record the PIDs as potentially relevant
+ OwnedPIDs[*NumberOfOwnedPIDs].Active = 1;
+ OwnedPIDs[*NumberOfOwnedPIDs].PID = PID;
+ OwnedPIDs[*NumberOfOwnedPIDs].PPID = PPID;
+ (*NumberOfOwnedPIDs)++;
+//DEBUG printf("%d I own PID = %d PPID = %d UID = %d\n",*NumberOfOwnedPIDs,PID,PPID,UID);
+ if (*NumberOfOwnedPIDs >= MAX_PROCESSES) {
+ fprintf(stderr,"ERROR: Out of save process space\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ } else {
+//----Bloody child just died
+ }
+ }
+ }
+ closedir(ProcDir);
+}
+//---------------------------------------------------------------------------
+float GetProcessTime(pid_t PID,int IncludeSelf,int IncludeChildren) {
+
+ FILE *ProcFile;
+ String ProcFileName;
+ float MyTime,ChildTime,ProcessTime;
+ int UserModeJiffies,SystemModeJiffies,ChildUserModeJiffies,
+ChildSystemModeJiffies;
+
+ ProcessTime = 0;
+ sprintf(ProcFileName,"/proc/%d/stat",PID);
+ if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
+ fscanf(ProcFile,"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %d %d %d %d",&UserModeJiffies,&SystemModeJiffies,&ChildUserModeJiffies,
+&ChildSystemModeJiffies);
+ fclose(ProcFile);
+//DEBUG printf("%d: my jiffies = %d, dead child jiffies = %d\n",PID,UserModeJiffies+SystemModeJiffies,ChildUserModeJiffies+ChildSystemModeJiffies);
+//----Time used by this process
+ MyTime = ((float)(UserModeJiffies + SystemModeJiffies))/JIFFIES;
+//----Time used by this process's dead children (man pages are wrong - does
+//----not include my jiffies)
+ ChildTime = ((float)(ChildUserModeJiffies + ChildSystemModeJiffies))/
+JIFFIES;
+ if (IncludeSelf) {
+ ProcessTime += MyTime;
+ }
+ if (IncludeChildren) {
+ ProcessTime += ChildTime;
+ }
+//DEBUG printf("Process time for %d is %f\n",PID,ProcessTime);
+ return(ProcessTime);
+ } else {
+//----Bloody process died, return 0 and catch it in the parent next time
+ return(0);
+ }
+}
+#endif
+//---------------------------------------------------------------------------
+#ifdef SUN
+void GetProcessesOwnedByMe(uid_t MyRealUID,ProcessDataArray OwnedPIDs,
+int *NumberOfOwnedPIDs) {
+
+ DIR *ProcDir;
+ struct dirent *ProcessDir;
+ pid_t PID;
+ struct psinfo ProcessRecord;
+ FILE *ProcFile;
+ String ProcFileName;
+
+ if ((ProcDir = opendir("/proc")) == NULL) {
+ perror("ERROR: Cannot opendir /proc\n");
+ exit(EXIT_FAILURE);
+ }
+
+//DEBUG printf("look for processes owned by %d\n",MyRealUID);
+
+ *NumberOfOwnedPIDs = 0;
+ while ((ProcessDir = readdir(ProcDir)) != NULL) {
+ if (isdigit((int)ProcessDir->d_name[0])) {
+ PID = (pid_t)atoi(ProcessDir->d_name);
+ sprintf(ProcFileName,"/proc/%d/psinfo",(int)PID);
+ if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
+ fread(&ProcessRecord,sizeof(ProcessRecord),1,ProcFile);
+ fclose(ProcFile);
+//----Check if this process is owned by this user
+ if (ProcessRecord.pr_uid == MyRealUID) {
+//----Record the PIDs as potentially relevant
+ OwnedPIDs[*NumberOfOwnedPIDs].PID = PID;
+ OwnedPIDs[*NumberOfOwnedPIDs].PPID = ProcessRecord.pr_ppid;
+ (*NumberOfOwnedPIDs)++;
+ if (*NumberOfOwnedPIDs >= MAX_PROCESSES) {
+ fprintf(stderr,"ERROR: Out of save process space\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ } else {
+//----Bloody child just died
+ }
+ }
+ }
+ closedir(ProcDir);
+}
+//---------------------------------------------------------------------------
+float GetProcessTime(pid_t PID,int IncludeSelf,int IncludeChildren) {
+
+ FILE *ProcFile;
+ String ProcFileName;
+ pstatus_t StatusRecord;
+ float ProcessTime;
+
+ ProcessTime = 0;
+ sprintf(ProcFileName,"/proc/%d/status",(int)PID);
+ if ((ProcFile = fopen(ProcFileName,"r")) != NULL) {
+ fread(&StatusRecord,sizeof(StatusRecord),1,ProcFile);
+ fclose(ProcFile);
+ if (IncludeSelf) {
+ ProcessTime += StatusRecord.pr_utime.tv_sec +
+StatusRecord.pr_stime.tv_sec +
+((float)(StatusRecord.pr_utime.tv_nsec+StatusRecord.pr_stime.tv_nsec))/
+NANOSECONDS;
+ }
+ if (IncludeChildren) {
+ ProcessTime += StatusRecord.pr_cutime.tv_sec +
+StatusRecord.pr_cstime.tv_sec +
+((float)(StatusRecord.pr_cutime.tv_nsec+StatusRecord.pr_cstime.tv_nsec))/
+NANOSECONDS;
+ }
+//DEBUG printf("Process %d has used U %ld +n%ld + S %ld +n%ld + CU %ld +n%ld + CS %ld +n%ld = %.1f\n",
+//DEBUG PID,StatusRecord.pr_utime.tv_sec,StatusRecord.pr_utime.tv_nsec,
+//DEBUG StatusRecord.pr_stime.tv_sec,StatusRecord.pr_stime.tv_nsec,
+//DEBUG StatusRecord.pr_cutime.tv_sec,StatusRecord.pr_cutime.tv_nsec,
+//DEBUG StatusRecord.pr_cstime.tv_sec,StatusRecord.pr_cstime.tv_nsec,
+//DEBUG ProcessTime);
+ return(ProcessTime);
+ } else {
+//----Bloody child died, return 0 and catch it in the parent next time
+ return(0);
+ }
+}
+#endif //----SUN
+//---------------------------------------------------------------------------
+#ifdef OSX
+//----No looking in /proc for OSX
+#endif
+//---------------------------------------------------------------------------
+int PIDInArray(pid_t PID,ProcessDataArray PIDs,int NumberOfPIDs) {
+
+ int PIDIndex;
+
+ for (PIDIndex = 0;PIDIndex < NumberOfPIDs;PIDIndex++) {
+ if (PIDs[PIDIndex].PID == PID) {
+ return(1);
+ }
+ }
+ return(0);
+}
+//---------------------------------------------------------------------------
+#if (defined(LINUX)||defined(SUN))
+//----Only for systems that have /proc
+
+int GetTreeTimes(uid_t MyRealUID,pid_t FirstBornPID,ProcessDataArray
+TreeTimes) {
+
+ ProcessDataArray OwnedPIDs;
+ int NumberOfOwnedPIDs;
+ int NumberOfTreeTimes;
+ int CurrentTreeIndex;
+ int OwnedIndex;
+
+//----Get the list of processes owned by this user
+ GetProcessesOwnedByMe(MyRealUID,OwnedPIDs,&NumberOfOwnedPIDs);
+
+//----Check that the root of the tree is still there
+//DEBUG printf("Check if %d is alive\n",FirstBornPID);
+ if (!PIDInArray(FirstBornPID,OwnedPIDs,NumberOfOwnedPIDs)) {
+//DEBUG printf("It is dead\n");
+ return(0);
+ }
+//DEBUG printf("It is alive\n");
+
+//----Find those in the process tree, and get their times
+ CurrentTreeIndex = 0;
+ TreeTimes[0].Active = 1;
+ TreeTimes[0].PID = FirstBornPID;
+ TreeTimes[0].PPID = MyRealUID;
+ TreeTimes[0].CPUTime = GetProcessTime(TreeTimes[0].PID,1,1);
+ NumberOfTreeTimes = 1;
+
+ while (CurrentTreeIndex < NumberOfTreeTimes) {
+//DEBUG printf("%d %d is in the tree\n",TreeTimes[CurrentTreeIndex].PID,TreeTimes[CurrentTreeIndex].PPID);
+//----Scan for offspring
+ TreeTimes[CurrentTreeIndex].CPUTime =
+GetProcessTime(TreeTimes[CurrentTreeIndex].PID,1,1);
+ for (OwnedIndex = 0; OwnedIndex < NumberOfOwnedPIDs; OwnedIndex++) {
+ if (OwnedPIDs[OwnedIndex].PPID == TreeTimes[CurrentTreeIndex].PID) {
+ TreeTimes[NumberOfTreeTimes].Active = 1;
+ TreeTimes[NumberOfTreeTimes].PID = OwnedPIDs[OwnedIndex].PID;
+ TreeTimes[NumberOfTreeTimes].PPID = OwnedPIDs[OwnedIndex].PPID;
+ NumberOfTreeTimes++;
+ }
+ }
+//----Move on to the next process in the tree
+ CurrentTreeIndex++;
+ }
+
+ return(NumberOfTreeTimes);
+}
+
+#endif
+#ifdef OSX
+//----No /proc for OSX
+#endif
+//---------------------------------------------------------------------------
+//----Send signals and reports if process is known to be gone
+int SignalAndReport(int PID,int Signal,int RepeatUntilTerminated,
+char * ProcessType) {
+
+ String ErrorMessage;
+ extern int errno;
+ int Terminated;
+ int NumberOfLoops;
+
+ Terminated = 0;
+ NumberOfLoops = 0;
+ do {
+ NumberOfLoops++;
+//DEBUG printf("!!! TreeLimitedRun %d sends signal %d to %s %d\n",getpid(),Signal,ProcessType,PID);fflush(stdout);
+ if (kill(PID,Signal) != 0) {
+//DEBUG printf("The kill errno is %d\n",errno);
+//----If process no longer exists record that to avoid killing again
+ if (errno == ESRCH) {
+ Terminated = 1;
+ } else {
+ sprintf(ErrorMessage,
+"!!! ERROR: TreeLimitedRun %d cannot signal %s %d with %d",getpid(),ProcessType,
+PID,Signal);
+ perror(ErrorMessage);
+ }
+ }
+//----Must do perror after errno, as perror clears errno
+ } while (RepeatUntilTerminated && !Terminated && NumberOfLoops < 10);
+
+ return(Terminated);
+}
+//---------------------------------------------------------------------------
+void ChildKillTree(int TargetIndex,ProcessDataArray TreeTimes,
+int NumberInTree,int Signal) {
+
+ int ChildIndex;
+
+//DEBUG printf("!!! TreeLimitedRun %d killing tree below PID %d with %d\n",getpid(),TreeTimes[TargetIndex].PID,Signal);fflush(stdout);
+ for (ChildIndex=0; ChildIndex < NumberInTree; ChildIndex++) {
+ if (TreeTimes[TargetIndex].PID == TreeTimes[ChildIndex].PPID) {
+ ChildKillTree(ChildIndex,TreeTimes,NumberInTree,Signal);
+ }
+//TOO SLOW? usleep(100000);
+ }
+ if (TreeTimes[TargetIndex].Active) {
+ if (SignalAndReport(TreeTimes[TargetIndex].PID,Signal,
+Signal == SIGKILL,"tree process")) {
+ TreeTimes[TargetIndex].Active = 0;
+ }
+ }
+}
+//---------------------------------------------------------------------------
+int KillTree(uid_t MyRealUID,pid_t FirstBornPID,int Signal) {
+
+ int NumberOfTreeTimes;
+ extern int errno;
+
+#if (defined(LINUX)||defined(SUN))
+ ProcessDataArray TreeTimes;
+
+ if ((NumberOfTreeTimes = GetTreeTimes(MyRealUID,FirstBornPID,TreeTimes)) >
+0) {
+
+//----The first born gets it first so that it can curb its descendants nicely
+ if (TreeTimes[0].Active) {
+//DEBUG printf("!!! TreeLimitedRun %d killing top process %d with %d\n",getpid(),TreeTimes[0].PID,Signal);fflush(stdout);
+//----TreeTimes[0].PID is FirstBornPID
+ if (SignalAndReport(TreeTimes[0].PID,Signal,Signal == SIGKILL,
+"top process")) {
+ TreeTimes[0].Active = 0;
+ }
+ }
+
+//----200000 is not enough - EP's eproof script gets killed before it can
+//----kill eprover
+ usleep(500000);
+//----Now gently from the bottom up
+ ChildKillTree(0,TreeTimes,NumberOfTreeTimes,Signal);
+ usleep(100000);
+//----Now viciously from the bottom up
+ ChildKillTree(0,TreeTimes,NumberOfTreeTimes,SIGKILL);
+ }
+#endif
+#ifdef OSX
+ int Active;
+
+ Active = 1;
+//----The first born gets it first so that it can curb its descendants nicely
+ if (SignalAndReport(FirstBornPID,Signal,Signal == SIGKILL,"top process")) {
+ Active = 0;
+ }
+ if (Active) {
+ usleep(100000);
+//----Now viciously
+ SignalAndReport(FirstBornPID,SIGKILL,1,"only process");
+ }
+ NumberOfTreeTimes = 1;
+#endif
+
+ return(NumberOfTreeTimes);
+}
+//---------------------------------------------------------------------------
+void KillOrphans(uid_t MyRealUID,ProcessDataArray SavePIDs,
+int NumberOfSavePIDs) {
+
+#if (defined(LINUX)||defined(SUN))
+
+ ProcessDataArray OwnedPIDs;
+ int NumberOfOwnedPIDs;
+ int OwnedIndex;
+ int NumberOfOrphansKilled;
+ extern int errno;
+
+ do {
+//----Get the list of processes owned by this user
+ GetProcessesOwnedByMe(MyRealUID,OwnedPIDs,&NumberOfOwnedPIDs);
+
+ NumberOfOrphansKilled = 0;
+ for (OwnedIndex = 0; OwnedIndex < NumberOfOwnedPIDs; OwnedIndex++) {
+//DEBUG printf("!!! TreeLimitedRun %d considers %d with parent %d\n",getpid(),OwnedPIDs[OwnedIndex].PID, OwnedPIDs[OwnedIndex].PPID);fflush(stdout);
+ if (OwnedPIDs[OwnedIndex].PPID == 1 &&
+!PIDInArray(OwnedPIDs[OwnedIndex].PID,SavePIDs,NumberOfSavePIDs)) {
+//DEBUG printf("!!! TreeLimitedRun %d kills orphan %d\n",getpid(),OwnedPIDs[OwnedIndex].PID);fflush(stdout);
+ if (SignalAndReport(OwnedPIDs[OwnedIndex].PID,SIGQUIT,0,
+"orphan")) {
+ OwnedPIDs[OwnedIndex].Active = 0;
+ }
+ if (OwnedPIDs[OwnedIndex].Active) {
+ sleep(1);
+ SignalAndReport(OwnedPIDs[OwnedIndex].PID,SIGKILL,1,
+"orphan");
+ }
+ NumberOfOrphansKilled++;
+ }
+ }
+ if (NumberOfOrphansKilled > 0) {
+ printf("Killed %d orphans\n",NumberOfOrphansKilled);
+ }
+ } while (NumberOfOrphansKilled > 0);
+
+#endif
+#ifdef OSX
+//----No orphans known for OSX
+#endif
+}
+//---------------------------------------------------------------------------
+void PrintTimes(char* Tag,float TreeCPUTime,float WCTime) {
+
+//----You can print times with more accuracy here
+ printf("%s: %.1f CPU %.1f WC\n",Tag,TreeCPUTime,WCTime);
+ fflush(NULL);
+}
+//---------------------------------------------------------------------------
+float WallClockSoFar(struct timeval WCStartTime) {
+
+ struct timeval WCEndTime;
+
+ gettimeofday(&WCEndTime,NULL);
+//DEBUG printf("Started at %ld +%f and ended at %ld +%f\n",
+//DEBUG WCStartTime.tv_sec,WCStartTime.tv_usec/MICROSECONDS,
+//DEBUG WCEndTime.tv_sec,WCEndTime.tv_usec/MICROSECONDS);
+
+ return((WCEndTime.tv_sec - WCStartTime.tv_sec) +
+(WCEndTime.tv_usec - WCStartTime.tv_usec)/MICROSECONDS);
+
+}
+//---------------------------------------------------------------------------
+double AccumulateTreeTime(int TargetIndex,ProcessDataArray TreeTimes,
+int NumberInTree) {
+
+ int ChildIndex;
+
+ TreeTimes[TargetIndex].AccumulatedCPUTime = TreeTimes[TargetIndex].CPUTime;
+ for (ChildIndex=0; ChildIndex < NumberInTree; ChildIndex++) {
+ if (TreeTimes[TargetIndex].PID == TreeTimes[ChildIndex].PPID) {
+ TreeTimes[TargetIndex].AccumulatedCPUTime +=
+AccumulateTreeTime(ChildIndex,TreeTimes,NumberInTree);
+ }
+ }
+
+ return(TreeTimes[TargetIndex].AccumulatedCPUTime);
+}
+//---------------------------------------------------------------------------
+float WatchChildTree(int MyPID,int ChildPID,int CPUTimeLimit,
+int DelayBetweenChecks,struct timeval WCStartTime,int PrintEachCheck) {
+
+ double TreeTime,LastTreeTime,LostTime;
+ int NumberInTree;
+ int KilledInTree;
+ int Status;
+ int DeadPID;
+#if (defined(LINUX)||defined(SUN))
+ ProcessDataArray TreeTimes;
+#endif
+#ifdef OSX
+ struct rusage ResourceUsage;
+#endif
+
+ LastTreeTime = 0.0;
+ LostTime = 0.0;
+
+//----Loop watching times taken. Order is important - get time before
+//----checking for interrupt
+ do {
+#if (defined(LINUX)||defined(SUN))
+//----Look at the tree
+ NumberInTree = GetTreeTimes(getuid(),ChildPID,TreeTimes);
+ TreeTime = AccumulateTreeTime(0,TreeTimes,NumberInTree);
+//DEBUG fprintf(stderr,"now %5.2f limit %d\n",TreeTime,CPUTimeLimit);
+//----For those with /proc, reap the children. Need to reap late so /proc
+//----entries do not disappear
+ while ((DeadPID = waitpid(-1,&Status,WNOHANG)) > 0) {
+ NumberInTree--;
+//DEBUG fprintf(stderr,"The child %d has died\n",DeadPID);
+ }
+#endif
+#ifdef OSX
+//----Check if child is gone (-1 if no child, 0 if not dead, PID if dead)
+ DeadPID = waitpid(-1,&Status,WNOHANG);
+ if (DeadPID == ChildPID || DeadPID == -1) {
+ TreeTime = LastTreeTime;
+ NumberInTree = 0;
+ } else {
+//----Maybe more than 1, but we don't know in OSX version
+ NumberInTree = 1;
+ }
+ if (getrusage(RUSAGE_CHILDREN,&ResourceUsage) != -1) {
+ TreeTime = ResourceUsage.ru_utime.tv_sec +
+ResourceUsage.ru_utime.tv_usec / 1000000 + ResourceUsage.ru_stime.tv_sec +
+ResourceUsage.ru_stime.tv_usec / 1000000;
+ } else {
+ printf("TreeLimitedRun could not getrusage\n");
+ TreeTime = LastTreeTime;
+ }
+#endif
+
+//DEBUG fprintf(stderr,"acc time is %.2f\n",TreeTime);
+ if (TreeTime < LastTreeTime) {
+ LostTime += LastTreeTime - TreeTime;
+ printf("WARNING: TreeLimitedRun lost %.2fs, total lost is %.2fs\n",
+LastTreeTime - TreeTime,LostTime);
+ }
+//DEBUG printf("lost time is %.2f\n",LostTime);
+ LastTreeTime = TreeTime;
+ TreeTime += LostTime;
+
+//----Print each loop if requested
+ if (PrintEachCheck) {
+ PrintTimes("WATCH",TreeTime,WallClockSoFar(WCStartTime));
+ }
+//----If we're going to loop, wait a bit first
+//----DANGER - if the last descedantprocess dies between GetTreeTimes() and
+//----here, it still waits.
+ if ((CPUTimeLimit == 0 || TreeTime <= CPUTimeLimit) &&
+NumberInTree > 0 && !GlobalInterrupted) {
+ sleep(DelayBetweenChecks);
+ }
+ } while ((CPUTimeLimit == 0 || TreeTime <= CPUTimeLimit) &&
+NumberInTree > 0 && !GlobalInterrupted);
+
+//----From now on reap normally
+ if (signal(SIGCHLD,SIGCHLDReaper) == SIG_ERR) {
+ perror("ERROR: Could not set SIGCHLD handler");
+ exit(EXIT_FAILURE);
+ }
+//----Reap anyway in case I missed some
+ SIGCHLDReaper(0);
+
+//----If over time limit, stop them all (XCPU to top guy first)
+ if (NumberInTree > 0 && TreeTime > CPUTimeLimit) {
+ KilledInTree = KillTree(getuid(),ChildPID,SIGXCPU);
+//DEBUG printf("Killed %d in tree\n",KilledInTree);
+ }
+
+//----If global interrupted, then send it on
+ if (NumberInTree > 0 && GlobalInterrupted) {
+ KilledInTree = KillTree(getuid(),ChildPID,GlobalSignalReceived);
+//DEBUG printf("Killed %d in tree\n",KilledInTree);
+ }
+
+ return(TreeTime);
+}
+//---------------------------------------------------------------------------
+int main(int argc,char *argv[]) {
+
+ int CPUTimeLimit;
+ int WCTimeLimit;
+ int MemoryLimit;
+ int ArgNumber;
+ int QuietnessLevel;
+ int ArgOffset;
+ pid_t ChildPID;
+ float TreeCPUTime;
+ float WCTime;
+ struct timeval WCStartTime;
+ int DelayBetweenChecks;
+ int PrintEachCheck = 0;
+ ProcessDataArray SavePIDs;
+ int NumberOfSavePIDs;
+ int Status;
+
+//----Check the quietness level
+ if (argc >= 2 && strstr(argv[1],"-q") == argv[1]) {
+ ArgOffset = 1;
+ QuietnessLevel = atoi(&argv[ArgOffset][2]);
+ } else {
+ QuietnessLevel = 1;
+ ArgOffset = 0;
+ }
+
+//----Look for time and print flags
+ if (argc >= ArgOffset+2 &&
+strstr(argv[ArgOffset+1],"-t") == argv[ArgOffset+1]) {
+ ArgOffset++;
+ DelayBetweenChecks = atoi(&argv[ArgOffset][2]);
+ } else {
+ if (argc >= ArgOffset+2 &&
+strstr(argv[ArgOffset+1],"-p") == argv[ArgOffset+1]) {
+ PrintEachCheck = 1;
+ ArgOffset++;
+ DelayBetweenChecks = atoi(&argv[ArgOffset][2]);
+ } else {
+ DelayBetweenChecks = DEFAULT_DELAY_BETWEEN_CHECKS;
+ }
+ }
+
+ if (argc - ArgOffset >= 4) {
+//----Redirect stderr to stdout
+ if (dup2(STDOUT,STDERR) == -1) {
+ perror("ERROR: Cannot dup STDERR to STDOUT");
+ }
+
+//----Extract time limits
+ CPUTimeLimit = atoi(argv[ArgOffset+1]);
+ WCTimeLimit = atoi(argv[ArgOffset+2]);
+ if (isdigit((int)argv[ArgOffset+3][0])) {
+ MemoryLimit = atoi(argv[ArgOffset+3]);
+ ArgOffset++;
+ } else {
+ MemoryLimit = 0;
+ }
+
+ if (QuietnessLevel == 0) {
+ printf(
+"TreeLimitedRun: ----------------------------------------------------------\n");
+ printf("TreeLimitedRun: %s ",argv[ArgOffset+3]);
+ for (ArgNumber=ArgOffset+4;ArgNumber<argc;ArgNumber++)
+ printf("%s ",argv[ArgNumber]);
+ printf("\n");
+ printf("TreeLimitedRun: CPU time limit is %ds\n",CPUTimeLimit);
+ printf("TreeLimitedRun: WC time limit is %ds\n",WCTimeLimit);
+ if (MemoryLimit > 0) {
+ printf("TreeLimitedRun: Memory limit is %dbytes\n",
+MemoryLimit);
+ }
+//----Output the PID for possible later use
+ printf("TreeLimitedRun: PID is %d\n",(int)getpid());
+ printf(
+"TreeLimitedRun: ----------------------------------------------------------\n");
+ fflush(stdout);
+ }
+ SetNoCoreDump();
+
+//----Set handler for when child dies
+ if (signal(SIGCHLD,SIGCHLDHandler) == SIG_ERR) {
+ perror("ERROR: Could not set SIGCHLD handler");
+ exit(EXIT_FAILURE);
+ }
+//----Set handler for global interruptions and alarms
+ GlobalInterrupted = 0;
+ GlobalSignalReceived = 0;
+ if (signal(SIGQUIT,SIGQUITHandler) == SIG_ERR) {
+ perror("ERROR: Could not set SIGQUIT handler");
+ exit(EXIT_FAILURE);
+ }
+ if (signal(SIGALRM,SIGQUITHandler) == SIG_ERR) {
+ perror("ERROR: Could not set SIGALRM handler");
+ exit(EXIT_FAILURE);
+ }
+
+#if (defined(LINUX)||defined(SUN))
+//----Record running processes at start (xeyes, gnome, etc)
+ GetProcessesOwnedByMe(getuid(),SavePIDs,&NumberOfSavePIDs);
+#endif
+#ifdef OSX
+//----No recording processes for OSX
+#endif
+
+//----Fork for ATP process
+ if ((ChildPID = fork()) == -1) {
+ perror("ERROR: Cannot fork for ATP system process");
+ exit(EXIT_FAILURE);
+ }
+
+//----In child, set limits and execute the ATP system
+ if (ChildPID == 0) {
+ if (setvbuf(stdout,NULL,_IONBF,0) != 0) {
+ perror("Setting unbuffered");
+ }
+//DEBUG printf("The prover PID will be %d\n",getpid());
+//----Set memory limit for child only
+ if (MemoryLimit > 0) {
+ SetMemoryLimit(MemoryLimit);
+ }
+
+#if (defined(LINUX)||defined(SUN))
+//----Systems with /proc are stopped by this program with kill
+#endif
+#ifdef OSX
+//----In OSX case, child must limit itself
+ if (CPUTimeLimit > 0) {
+ SetCPUTimeLimit(CPUTimeLimit);
+ }
+#endif
+
+ execvp(argv[ArgOffset+3],argv+ArgOffset+3);
+ perror("Cannot exec");
+ exit(EXIT_FAILURE);
+
+//----In parent, set limits and watch the ATP system
+ } else {
+ if (WCTimeLimit > 0) {
+ alarm(WCTimeLimit);
+ }
+//----Record start time
+ gettimeofday(&WCStartTime,NULL);
+ TreeCPUTime = 0;
+ WCTime = 0;
+
+//----Watch the tree of processes
+ TreeCPUTime = WatchChildTree(getpid(),ChildPID,CPUTimeLimit,
+DelayBetweenChecks,WCStartTime,PrintEachCheck);
+
+//----Record end WC time
+ WCTime = WallClockSoFar(WCStartTime);
+
+//----See if the time is increased by looking at my children
+//----Not sure what this was for
+// ChildTime = GetProcessTime(getpid(),0,1);
+// if (ChildTime > TreeCPUTime) {
+// TreeCPUTime = ChildTime;
+// }
+
+ PrintTimes("FINAL WATCH",TreeCPUTime,WCTime);
+
+//----Sweep for orphans
+ KillOrphans(getuid(),SavePIDs,NumberOfSavePIDs);
+//----Reap any remaining
+ while (wait(&Status) != -1) {
+ sleep(1);
+//DEBUG printf("!!! Waiting for children that havn't died\n");
+ }
+ }
+ } else {
+ printf("Usage: %s [-q<quietness>] [-t<check delay>|-p<print check delay>] <CPU limit> <WC limit> [<Memory limit>] <Job>\n",
+argv[0]);
+ }
+
+ return(0);
+}
+//---------------------------------------------------------------------------