/* * kerneltimer_partC.c * * @author * Benjamin Bertka - 21306103 * bbertka@mss.icics.ubc.ca * * CICS505 - OS5 */ #include #include #include #include #include #include #include /*Long integer valueseused to keep track of the parent, child1, and child2 real, prof, and virt timer times. These values are updated whenever a signal is is received by the handler. */ long rsecs = 0; long vsecs = 0; long psecs = 0; long c1_rsecs = 0; long c1_vsecs = 0; long c1_psecs = 0; long c2_rsecs = 0; long c2_vsecs = 0; long c2_psecs = 0; /* Itimerval structs for each parent, child1, and child2 which maintain timer times for the real, profile, and virtual timers. */ struct itimerval realTimer; struct itimerval virtualTimer; struct itimerval profileTimer; struct itimerval C1realTimer; struct itimerval C1virtualTimer; struct itimerval C1profileTimer; struct itimerval C2realTimer; struct itimerval C2virtualTimer; struct itimerval C2profileTimer; /* These are the signals for the parent, child1, and child2 */ struct sigaction realSignalAction; struct sigaction C1realSignalAction; struct sigaction C2realSignalAction; /* Function prototypes that read the current status of the timers and save the info to the tv_Sec and tv_usec values in each parent, child1, and child2 */ void getItime(); void C1getItime(); void C2getItime(); /* These are the signal handler functions for the parent, child1, and child2 */ void realTimeHandler (int signum); void C1realTimeHandler (int signum); void C2realTimeHandler (int signum); /* * recursivley computes the fibonacci number for the unsigned int n */ long unsigned int fibonacci(unsigned int n); /* * computes elapsed time in milliseconds from seconds and microseconds */ long int elapsed(long int secs, long int microsecs); /* * Prints the timer values from the itimers for the calling type (p, ch1, ch2) */ void printItime(char *type, unsigned long fibo, long r, long v, long p, struct itimerval real, struct itimerval virt, struct itimerval prof); /* * This method computes the nth fibonacci number using recursion * During execution, each process calles this finction with a different n * PRE: n is a valid number * POST: the method recursivley calls itself until the final value is found * NoTE: This was direct from the assignment page */ long unsigned int fibonacci(unsigned int n){ if(n==0) return 0; else if(n==1||n==2) return 1; else return(fibonacci(n-1) + fibonacci(n-2)); } /* * This method computed the elapsed time in milliseconds using the two input * times which asre in real seconds, and microseconds. It uses a case by case * basis to avoid any bad computations of zero or negative values. * Subtracts the microseconds from countdown maximum to get actual time. * PRE: secs and microsecs are not NULL * POST: the output is milliseconds */ long int elapsed(long int secs, long int microsecs){ if(secs == 0 && microsecs == 0){ return 0; }else if(secs == 0 && microsecs > 0){ return (999999 - microsecs)/1000; }else if(secs > 0 && microsecs == 0){ return (secs*1000); }else if(secs > 0 && microsecs > 0){ return (secs*1000) + (999999 - microsecs)/1000; }else{ return -1; } } /* * This methods prints out the process profile as per the assignment page's * specifications, and in a format readable. The Kernal time is negative * often for the child2 process and I still dont know why. It uses the * elapsed() method to compute the millisecond times. * PRE: all input values are defined * POST: The profile for the calling process is printed to stdout */ void printItime(char * type, unsigned long fibo, long r, long v, long p, struct itimerval rt, struct itimerval vt, struct itimerval pt){ printf("\n\t%s: FIB: %lu\n", type, fibo); printf("\t%s: REAL: sec:%ld msec:%ld\n",type, r, elapsed(rt.it_value.tv_sec, rt.it_value.tv_usec)); printf("\t%s: CPU: sec:%ld msec:%ld\n", type, p, elapsed(pt.it_value.tv_sec, pt.it_value.tv_usec)); printf("\t%s: USER: sec:%ld msec:%ld\n", type, v, elapsed(vt.it_value.tv_sec, vt.it_value.tv_usec)); /* printf("\t%s: KERN: sec:%ld msec:%ld\n", type, p-v, elapsed(pt.it_value.tv_sec, pt.it_value.tv_usec) - elapsed(vt.it_value.tv_sec, vt.it_value.tv_usec)); */ long temp = elapsed(pt.it_value.tv_sec, pt.it_value.tv_usec) - elapsed(vt.it_value.tv_sec, vt.it_value.tv_usec); if(temp < 0){ printf("\t%s: KERN: sec:%ld msec:%ld\n", type, p-v-1, temp + 1000); }else{ printf("\t%s: KERN: sec:%ld msec:%ld\n", type, p-v, elapsed(pt.it_value.tv_sec, pt.it_value.tv_usec) - elapsed(vt.it_value.tv_sec, vt.it_value.tv_usec)); } } /* * The handler for the parent process. When a signal is called, the appropriate * value is updated for the corresponding itimer */ void realTimeHandler (int signum) { switch(signum){ case SIGALRM: ++rsecs; //updates the real seconds break; case SIGVTALRM: ++vsecs; //updates the virtual seconds break; case SIGPROF: ++psecs; //updates the profile seconds break; } } /* * The handler for the child1 process. When a signal is called, the appropriate * value is updated for the corresponding itimer */ void C1realTimeHandler (int signum) { switch(signum){ case SIGALRM: ++c1_rsecs; //updates the real seconds break; case SIGVTALRM: ++c1_vsecs; //updates the virtual seconds break; case SIGPROF: ++c1_psecs; //updates the profile seconds break; } } /* * The handler for the child2 process. When a signal is called, the appropriate * value is updated for the corresponding itimer */ void C2realTimeHandler (int signum) { switch(signum){ case SIGALRM: ++c2_rsecs; //updates the real seconds break; case SIGVTALRM: ++c2_vsecs; //updates the virtual seconds break; case SIGPROF: ++c2_psecs; //updates the profile seconds break; } } /* * A wrapper for the getitimer call for the parent timer. Updates the * tv_sec and tv_usec values with the most recent itimer times */ void getItime(){ getitimer(ITIMER_REAL,&realTimer); getitimer(ITIMER_VIRTUAL,&virtualTimer); getitimer(ITIMER_PROF,&profileTimer); } /* * A wrapper for the getitimer call for the child1 timer. Updates the * tv_sec and tv_usec values with the most recent itimerval times */ void C1getItime(){ getitimer(ITIMER_REAL,&C1realTimer); getitimer(ITIMER_VIRTUAL,&C1virtualTimer); getitimer(ITIMER_PROF,&C1profileTimer); } /* * A wrapper for the getitimer call for the child2 timer. Updates the * tv_sec and tv_usec values with the most recent itimerval times */ void C2getItime(){ getitimer(ITIMER_REAL,&C2realTimer); getitimer(ITIMER_VIRTUAL,&C2virtualTimer); getitimer(ITIMER_PROF,&C2profileTimer); } /* * Initializes the itimers for the parent, and sets them */ void timerInit(){ realTimer.it_value.tv_sec = 0; realTimer.it_value.tv_usec = 999999; realTimer.it_interval.tv_sec = 0; realTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_REAL, &realTimer, NULL); virtualTimer.it_value.tv_sec = 0; virtualTimer.it_value.tv_usec = 999999; virtualTimer.it_interval.tv_sec = 0; virtualTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_VIRTUAL, &virtualTimer, NULL); profileTimer.it_value.tv_sec = 0; profileTimer.it_value.tv_usec = 999999; profileTimer.it_interval.tv_sec = 0; profileTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_PROF, &profileTimer, NULL); } /* * Initializes the itimers for the child1, and sets them */ void C1timerInit(){ C1realTimer.it_value.tv_sec = 0; C1realTimer.it_value.tv_usec = 999999; C1realTimer.it_interval.tv_sec = 0; C1realTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_REAL, &C1realTimer, NULL); C1virtualTimer.it_value.tv_sec = 0; C1virtualTimer.it_value.tv_usec = 999999; C1virtualTimer.it_interval.tv_sec = 0; C1virtualTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_VIRTUAL, &C1virtualTimer, NULL); C1profileTimer.it_value.tv_sec = 0; C1profileTimer.it_value.tv_usec = 999999; C1profileTimer.it_interval.tv_sec = 0; C1profileTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_PROF, &C1profileTimer, NULL); } /* * Initializes the itimers for the child2, and sets them */ void C2timerInit(){ C2realTimer.it_value.tv_sec = 0; C2realTimer.it_value.tv_usec = 999999; C2realTimer.it_interval.tv_sec = 0; C2realTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_REAL, &C2realTimer, NULL); C2virtualTimer.it_value.tv_sec = 0; C2virtualTimer.it_value.tv_usec = 999999; C2virtualTimer.it_interval.tv_sec = 0; C2virtualTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_VIRTUAL, &C2virtualTimer, NULL); C2profileTimer.it_value.tv_sec = 0; C2profileTimer.it_value.tv_usec = 999999; C2profileTimer.it_interval.tv_sec = 0; C2profileTimer.it_interval.tv_usec = 999999; setitimer (ITIMER_PROF, &C2profileTimer, NULL); } /* *Initializes the signalaction struct for the parent timers */ void signalInit(){ bzero (&realSignalAction, sizeof (realSignalAction)); realSignalAction.sa_handler = &realTimeHandler; sigaction(SIGALRM, &realSignalAction, NULL); sigaction(SIGVTALRM, &realSignalAction, NULL); sigaction(SIGPROF, &realSignalAction, NULL); } /* *Initializes the signalaction struct for the child1 timers */ void C1signalInit(){ bzero (&C1realSignalAction, sizeof (C1realSignalAction)); C1realSignalAction.sa_handler = &C1realTimeHandler; sigaction(SIGALRM, &C1realSignalAction, NULL); sigaction(SIGVTALRM, &C1realSignalAction, NULL); sigaction(SIGPROF, &C1realSignalAction, NULL); } /* *Initializes the signalaction struct for the child2 timers */ void C2signalInit(){ bzero (&C2realSignalAction, sizeof (C2realSignalAction)); C2realSignalAction.sa_handler = &C2realTimeHandler; sigaction(SIGALRM, &C2realSignalAction, NULL); sigaction(SIGVTALRM, &C2realSignalAction, NULL); sigaction(SIGPROF, &C2realSignalAction, NULL); } /* * The main entry point to the program. Uses the above methods to create * a forked processes where the parent and two children all compute a fib * number, while they are being profiled for their time. */ int main (int argc, char **argv){ unsigned long fib = 30; //just a default value for fib int status; int pid1 = fork(); //fork a child if(pid1 == 0){ C1timerInit(); //initialize child1 timer C1signalInit(); //initialize child1 signal fib = fibonacci(30); //compute fib C1getItime(); //update timers with current time printf("\nFibonacci(30):"); printItime((char*)"child1", fib, c1_rsecs, c1_vsecs, c1_psecs, C1realTimer, C1virtualTimer, C1profileTimer); fflush(stdout); return 0; //return }else{ int pid2 = fork(); //fork another child if(pid2 == 0){ C2timerInit(); //initialize child2 timers C2signalInit(); //intialize child2 signal fib = fibonacci(34); //compute fib C2getItime(); //update timers with current time printf("\nFibonacci(34):"); printItime((char*)"child2", fib, c2_rsecs, c2_vsecs, c2_psecs, C2realTimer, C2virtualTimer, C2profileTimer); fflush(stdout); return 0; //return }else{ timerInit(); //initialize timers for child2 signalInit(); //initialize signal for child2 fib = fibonacci(40); //compute fib getItime(); //update timers printf("\nFibonacci(40):"); printItime((char*)"parent", fib, rsecs, vsecs, psecs, realTimer, virtualTimer, profileTimer); waitpid(0, &status, 0); waitpid(0, &status, 0); //wait waitpid(0, &status, 0); fflush(stdout); return 0; } } printf("this line should never be printed\n"); //and it isnt! return 0; }