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 if( (file = fopen(cp->cp_ProcFileName, "r")) != NULL )
00185 {
00186 struct timeval utime, stime, accum, usage;
00187 unsigned long unused_ulong;
00188 long unused_long;
00189 char unused_char;
00190 int unused_int;
00191
00192 memset(&utime, 0, sizeof(utime));
00193 memset(&stime, 0, sizeof(stime));
00194 fscanf(file,
00195 "%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",
00196 &unused_int,
00197 unused_string,
00198 &unused_char,
00199 &unused_int,
00200 &unused_int,
00201 &unused_int,
00202 &unused_int,
00203 &unused_int,
00204 &unused_ulong,
00205 &unused_ulong,
00206 &unused_ulong,
00207 &unused_ulong,
00208 &unused_ulong,
00209 &unused_ulong,
00210 &unused_ulong,
00211 &unused_long,
00212 &unused_long,
00213 &unused_long,
00214 &unused_long,
00215 &unused_long,
00216 &unused_long,
00217 &unused_ulong,
00218 &unused_ulong,
00219 &unused_long,
00220 &unused_ulong,
00221 &unused_ulong,
00222 &unused_ulong,
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_int,
00234 &unused_int,
00235 &utime.tv_sec,
00236 &utime.tv_usec,
00237 &stime.tv_sec,
00238 &stime.tv_usec);
00239 timeradd(&utime, &stime, &accum);
00240 timersub(&accum, &cp->cp_LastUsage, &usage);
00241 cp->cp_LastUsage = accum;
00242 fprintf(cp->cp_Output,
00243 "%ld.%06ld",
00244 usage.tv_sec,
00245 usage.tv_usec);
00246 retval += (usage.tv_sec * 1000000) + usage.tv_usec;
00247 fclose(file);
00248 }
00249 else
00250 {
00251
00252 fprintf(cp->cp_Output, "0.0");
00253 }
00254 return( retval );
00255 }
00256 #endif
00257
00258 #if defined(__FreeBSD__)
00259 static unsigned long long cpSampleUsageInternal(struct cpChildProcess *cp)
00260 {
00261 static char unused_string[1024];
00262
00263 int retval = 0;
00264 FILE *file;
00265
00266 require(cp != NULL);
00267
00268 if( (file = fopen(cp->cp_ProcFileName, "r")) != NULL )
00269 {
00270 struct timeval utime, stime, accum, usage;
00271 int unused_int;
00272
00273 memset(&utime, 0, sizeof(struct timeval));
00274 memset(&stime, 0, sizeof(struct timeval));
00275 memset(&accum, 0, sizeof(struct timeval));
00276 fscanf(file,
00277 "%s %d %d %d %d %d,%d %s %d,%d %ld,%ld %ld,%ld",
00278 unused_string,
00279 &unused_int,
00280 &unused_int,
00281 &unused_int,
00282 &unused_int,
00283 &unused_int,
00284 &unused_int,
00285 unused_string,
00286 &unused_int,
00287 &unused_int,
00288 &utime.tv_sec,
00289 &utime.tv_usec,
00290 &stime.tv_sec,
00291 &stime.tv_usec);
00292 timeradd(&utime, &stime, &accum);
00293 timersub(&accum, &cp->cp_LastUsage, &usage);
00294 cp->cp_LastUsage = accum;
00295 fprintf(cp->cp_Output,
00296 "%ld.%06ld",
00297 usage.tv_sec, usage.tv_usec);
00298 fclose(file);
00299 }
00300 return( retval );
00301 }
00302 #endif
00303
00304 unsigned long long cpSampleUsage(struct cpChildProcess *cp,
00305 struct timeval *run_time)
00306 {
00307 unsigned long long retval = 0;
00308
00309 require(child_process_data.cpd_Flags & CPDF_INITIALIZED);
00310 require(cp != NULL);
00311 require(cpFindChildProcess(cp->cp_PID) != NULL);
00312 require(run_time != NULL);
00313 pp_block({
00314 static struct timeval last_run_time;
00315
00316 require(timercmp(&last_run_time, run_time, <=));
00317 last_run_time = *run_time;
00318 });
00319
00320 if( cp->cp_Output != NULL )
00321 {
00322 fprintf(cp->cp_Output,
00323 "%ld.%06ld ",
00324 run_time->tv_sec,
00325 run_time->tv_usec);
00326 retval += cpSampleUsageInternal(cp);
00327 fprintf(cp->cp_Output, "\n");
00328 }
00329 return( retval );
00330 }