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

childProcess.c

Go to the documentation of this file.
00001 /*
00002  * childProcess.c
00003  *
00004  * Copyright (c) 2003, 2004 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     /*
00184      * Do the open everytime since it can be a little buggy and we probably
00185      * do not need the speed here.
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         /* Cannot open the file, but we still need to output some usage. */
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 }

Generated on Fri Oct 22 07:50:24 2004 for CPU Broker by  doxygen 1.3.9.1