00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "config.h"
00019
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023
00024 #include <assert_pp.h>
00025
00026 #include <sys/time.h>
00027
00028 #include "childProcess.h"
00029
00030
00031
00032
00033 #if defined(linux)
00034 static char *PROC_STAT_FORMAT = "/proc/%d/stat";
00035 #elif defined(__FreeBSD__)
00036 static char *PROC_STAT_FORMAT = "/proc/%d/status";
00037 #endif
00038
00039
00040
00041
00042 static struct cpChildProcessData child_process_data;
00043
00044 int cpInitChildProcessData(void)
00045 {
00046 int retval = 1;
00047
00048 require(!(child_process_data.cpd_Flags & CPDF_INITIALIZED));
00049
00050 lnNewList(&child_process_data.cpd_Children);
00051 child_process_data.cpd_Flags |= CPDF_INITIALIZED;
00052 return( retval );
00053 }
00054
00055 void cpKillChildProcessData(void)
00056 {
00057 if( child_process_data.cpd_Flags & CPDF_INITIALIZED )
00058 {
00059 struct cpChildProcess *cp;
00060
00061 while( (cp = (struct cpChildProcess *)
00062 lnRemHead(&child_process_data.cpd_Children)) != NULL )
00063 {
00064 cp->cp_Link.ln_Succ = NULL;
00065 cpDeleteChildProcess(cp);
00066 }
00067 child_process_data.cpd_Flags &= ~CPDF_INITIALIZED;
00068 }
00069 }
00070
00071 struct cpChildProcess *cpFindChildProcess(pid_t child_pid)
00072 {
00073 struct cpChildProcess *curr, *retval = NULL;
00074
00075 require(child_process_data.cpd_Flags & CPDF_INITIALIZED);
00076 require(child_pid >= 0);
00077
00078 curr = (struct cpChildProcess *)child_process_data.cpd_Children.lh_Head;
00079 while( (curr->cp_Link.ln_Succ != NULL) && (retval == NULL) )
00080 {
00081 if( curr->cp_PID == child_pid )
00082 {
00083 retval = curr;
00084 }
00085 curr = (struct cpChildProcess *)curr->cp_Link.ln_Succ;
00086 }
00087 return( retval );
00088 }
00089
00090 struct cpChildProcess *cpCreateChildProcess(pid_t child_pid)
00091 {
00092 struct cpChildProcess *retval;
00093
00094 require(child_process_data.cpd_Flags & CPDF_INITIALIZED);
00095 require(child_pid >= 0);
00096 require(cpFindChildProcess(child_pid) == NULL);
00097
00098
00099 if( (retval = calloc(1,
00100 sizeof(struct cpChildProcess) +
00101 strlen(PROC_STAT_FORMAT) +
00102 16 +
00103 1)) != NULL )
00104 {
00105 retval->cp_PID = child_pid;
00106 snprintf((char *)(retval + 1),
00107 strlen(PROC_STAT_FORMAT) + 16 + 1,
00108 PROC_STAT_FORMAT,
00109 child_pid);
00110 retval->cp_ProcFileName = (const char *)(retval + 1);
00111
00112 lnAddTail(&child_process_data.cpd_Children, &retval->cp_Link);
00113
00114 ensure(cpFindChildProcess(child_pid) == retval);
00115 }
00116 return( retval );
00117 }
00118
00119 void cpDeleteChildProcess(struct cpChildProcess *cp)
00120 {
00121 require(child_process_data.cpd_Flags & CPDF_INITIALIZED);
00122
00123 if( cp != NULL )
00124 {
00125 {
00126 if( cp->cp_Link.ln_Succ != NULL )
00127 {
00128 lnRemove(&cp->cp_Link);
00129 }
00130 if( cp->cp_Output != NULL )
00131 {
00132 fclose(cp->cp_Output);
00133 cp->cp_Output = NULL;
00134 }
00135
00136 ensure(cpFindChildProcess(cp->cp_PID) == NULL);
00137 }
00138 free(cp);
00139 }
00140 }
00141
00142 int cpOpenOutput(struct cpChildProcess *cp,
00143 const char *base_name,
00144 struct timeval *start_time)
00145 {
00146 static char filename[1024];
00147
00148 int retval = 0;
00149
00150 require(child_process_data.cpd_Flags & CPDF_INITIALIZED);
00151 require(cp != NULL);
00152 require(cpFindChildProcess(cp->cp_PID) != NULL);
00153 require(base_name != NULL);
00154 require(strlen(base_name) > 0);
00155 require(start_time != NULL);
00156 require(start_time->tv_sec > 0);
00157 require(start_time->tv_usec > 0);
00158
00159 snprintf(filename, sizeof(filename), "%s-%d.out", base_name, cp->cp_PID);
00160 if( (cp->cp_Output = fopen(filename, "w")) != NULL )
00161 {
00162 fprintf(cp->cp_Output,
00163 "# start: %ld.%06ld\n",
00164 start_time->tv_sec,
00165 start_time->tv_usec);
00166 fprintf(cp->cp_Output, "0 0\n");
00167 retval = 1;
00168 }
00169 return( retval );
00170 }
00171
00172 #if defined(linux)
00173 static unsigned long long cpSampleUsageInternal(struct cpChildProcess *cp)
00174 {
00175 static char unused_string[1024];
00176
00177 unsigned long long retval = 0;
00178 FILE *file;
00179
00180 require(child_process_data.cpd_Flags & CPDF_INITIALIZED);
00181 require(cp != NULL);
00182
00183
00184
00185
00186
00187 if( (file = fopen(cp->cp_ProcFileName, "r")) != NULL )
00188 {
00189 struct timeval utime, stime, accum, usage;
00190 unsigned long unused_ulong;
00191 long unused_long;
00192 char unused_char;
00193 int unused_int;
00194
00195 memset(&utime, 0, sizeof(utime));
00196 memset(&stime, 0, sizeof(stime));
00197 fscanf(file,
00198 "%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %ld %ld %ld %ld",
00199 &unused_int,
00200 unused_string,
00201 &unused_char,
00202 &unused_int,
00203 &unused_int,
00204 &unused_int,
00205 &unused_int,
00206 &unused_int,
00207 &unused_ulong,
00208 &unused_ulong,
00209 &unused_ulong,
00210 &unused_ulong,
00211 &unused_ulong,
00212 &unused_ulong,
00213 &unused_ulong,
00214 &unused_long,
00215 &unused_long,
00216 &unused_long,
00217 &unused_long,
00218 &unused_long,
00219 &unused_long,
00220 &unused_ulong,
00221 &unused_ulong,
00222 &unused_long,
00223 &unused_ulong,
00224 &unused_ulong,
00225 &unused_ulong,
00226 &unused_ulong,
00227 &unused_ulong,
00228 &unused_ulong,
00229 &unused_ulong,
00230 &unused_ulong,
00231 &unused_ulong,
00232 &unused_ulong,
00233 &unused_ulong,
00234 &unused_ulong,
00235 &unused_ulong,
00236 &unused_int,
00237 &unused_int,
00238 &utime.tv_sec,
00239 &utime.tv_usec,
00240 &stime.tv_sec,
00241 &stime.tv_usec);
00242 timeradd(&utime, &stime, &accum);
00243 timersub(&accum, &cp->cp_LastUsage, &usage);
00244 cp->cp_LastUsage = accum;
00245 fprintf(cp->cp_Output,
00246 "%ld.%06ld",
00247 usage.tv_sec,
00248 usage.tv_usec);
00249 retval += (usage.tv_sec * 1000000) + usage.tv_usec;
00250 fclose(file);
00251 }
00252 else
00253 {
00254
00255 fprintf(cp->cp_Output, "0.0");
00256 }
00257 return( retval );
00258 }
00259 #endif
00260
00261 #if defined(__FreeBSD__)
00262 static unsigned long long cpSampleUsageInternal(struct cpChildProcess *cp)
00263 {
00264 static char unused_string[1024];
00265
00266 int retval = 0;
00267 FILE *file;
00268
00269 require(cp != NULL);
00270
00271 if( (file = fopen(cp->cp_ProcFileName, "r")) != NULL )
00272 {
00273 struct timeval utime, stime, accum, usage;
00274 int unused_int;
00275
00276 memset(&utime, 0, sizeof(struct timeval));
00277 memset(&stime, 0, sizeof(struct timeval));
00278 memset(&accum, 0, sizeof(struct timeval));
00279 fscanf(file,
00280 "%s %d %d %d %d %d,%d %s %d,%d %ld,%ld %ld,%ld",
00281 unused_string,
00282 &unused_int,
00283 &unused_int,
00284 &unused_int,
00285 &unused_int,
00286 &unused_int,
00287 &unused_int,
00288 unused_string,
00289 &unused_int,
00290 &unused_int,
00291 &utime.tv_sec,
00292 &utime.tv_usec,
00293 &stime.tv_sec,
00294 &stime.tv_usec);
00295 timeradd(&utime, &stime, &accum);
00296 timersub(&accum, &cp->cp_LastUsage, &usage);
00297 cp->cp_LastUsage = accum;
00298 fprintf(cp->cp_Output,
00299 "%ld.%06ld",
00300 usage.tv_sec, usage.tv_usec);
00301 fclose(file);
00302 }
00303 return( retval );
00304 }
00305 #endif
00306
00307 unsigned long long cpSampleUsage(struct cpChildProcess *cp,
00308 struct timeval *run_time)
00309 {
00310 unsigned long long retval = 0;
00311
00312 require(child_process_data.cpd_Flags & CPDF_INITIALIZED);
00313 require(cp != NULL);
00314 require(cpFindChildProcess(cp->cp_PID) != NULL);
00315 require(run_time != NULL);
00316 pp_block({
00317 static struct timeval last_run_time;
00318
00319 require(timercmp(&last_run_time, run_time, <=));
00320 last_run_time = *run_time;
00321 });
00322
00323 if( cp->cp_Output != NULL )
00324 {
00325 fprintf(cp->cp_Output,
00326 "%ld.%06ld ",
00327 run_time->tv_sec,
00328 run_time->tv_usec);
00329 retval += cpSampleUsageInternal(cp);
00330 fprintf(cp->cp_Output, "\n");
00331 }
00332 return( retval );
00333 }