Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

childProcess.c

Go to the documentation of this file.
00001 /*
00002  * childProcess.c
00003  *
00004  * Copyright (c) 2003 The University of Utah and the Flux Group.
00005  * All rights reserved.
00006  *
00007  * This file is licensed under the terms of the GNU Public License.  
00008  * See the file "license.terms" for restrictions on redistribution 
00009  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
00010  */
00011 
00012 /**
00013  * @file childProcess.c
00014  *
00015  * Implementation file for the child process accounting functions.
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  * The file name format for the process' statistics in '/proc'.
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  * Global data for child processes.
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     /* Allocate the structure and the /proc file name in one chunk. */
00099     if( (retval = calloc(1,
00100                          sizeof(struct cpChildProcess) +
00101                          strlen(PROC_STAT_FORMAT) +
00102                          16 + /* extra space for the PID */
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     /* XXX Do we have to open this everytime?  Or can we just rewind()? */
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         /* Cannot open the file, but we still need to output some usage. */
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 }

Generated on Mon Dec 1 16:29:06 2003 for CPU Broker by doxygen 1.3.4