Lab 06: Fork-Exec-Wait, Repeat!
Table of Contents
Task 1: Four Sons
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <string.h> int main(){ pid_t c_pid[4]; //array of 4 children pid's pid_t pid; int i, status; for(i = 0; i < 4; i ++){ c_pid[i] = fork(); if (c_pid[i] == 0){ /* Child */ pid = getpid(); switch(i){ case 0: //Child 0: The wise son printf("Child 0: %d: Sleeping 1 second, Exiting status 16\n", pid); sleep(1); //sleep 1 sec exit(16); //exit break; case 1: //Child 1: The simple son printf("Child 1: %d: I'm going to dereference a NULL pointer\n", pid); int * p = NULL; *p = 10; //dereferencing NULL exit(1);//just in case break; case 2: //Child 2: The wicked son printf("Child 2: %d: I'm going to shoot myself with a SIGABRT because I can\n", pid); kill(pid, SIGABRT); exit(1);//just in case break; case 3: //Child 3: The son who doesn't know how to ask question printf("Child 3: %d: Ummm ....\n", pid); exit(0); //success? break; } } } /*Parent*/ //TODO: Wait on all children and print some status while( (pid = wait(&status)) > 0){ for(i = 0; c_pid[i] != pid ; i++); printf("Parent: Child %d: %d terminated", i, pid); if ( WIFEXITED(status) ){ printf(" and exited with status %d\n", WEXITSTATUS(status)); }else if( WIFSIGNALED(status) ){ printf(" and exited due to signal %s", strsignal(WTERMSIG(status))); if(WCOREDUMP(status)){ printf( " and also core dumped\n"); }else{ printf( "\n"); } } } return 0; }
Task 2: timer
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/types.h> /** * timeval_subtract : subtract timeval x - y and store result in result **/ int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) { /* Perform the carry for the later subtraction by updating y. */ if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } /* Compute the time remaining to wait. tv_usec is certainly positive. */ result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; } int main(int argc, char * argv[]){ int status; pid_t c_pid; struct timeval start, end, diff; //get start time gettimeofday(&start, NULL); if ( (c_pid = fork()) == 0 ){ /*CHILD*/ //execute the arguments execvp(argv[1], argv+1); perror("child: failed execv"); exit(2);//exit error }else if (c_pid > 0){ /* PARENT */ //wait for child to finish wait(&status); gettimeofday(&end, NULL); timeval_subtract(&diff, &end, &start); printf("Run Time: %ld.%04ld (s)\n", diff.tv_sec, diff.tv_usec/1000); }else{ /* ERROR */ perror("failed fork"); exit(2); //exit error } return 0; }
Task 3: mini-sh
#include <stdio.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <readline/readline.h> #include <readline/history.h> #include <unistd.h> #include <sys/wait.h> #include <sys/time.h> #define MAX_ARGS 128 int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) { /* Perform the carry for the later subtraction by updating y. */ if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } /* Compute the time remaining to wait. tv_usec is certainly positive. */ result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; } int main(int argc, char * argv[]){ char * line; //DO NOT EDIT, for readline char prompt[256]; //DO NOT EDIT, for readline pid_t c_pid; //NOTE: to store child pid int status, i; //NOTE: For wait status and iteration char * cmd_argv[MAX_ARGS]; //NOTE: use this store your argv array, // don't go beyond MAX_ARGS char * tok; //NOTE: This is useful for tokenizatoin struct timeval start, end, diff; //for timing start.tv_sec = 0; start.tv_usec = 0; diff = end = start; //initialize times to zero //for readline setup, don't edit! rl_bind_key('\t', rl_abort); while(1){ //prompt snprintf(prompt, 256, "mini-sh (%ld.%04ld) #> ", diff.tv_sec, diff.tv_usec/1000); //readline allocates a new line every time it reads line = readline(prompt); //read EOF if (line == NULL){ free(line); printf("\n"); break; } //read empty line if (strcmp(line,"")==0){ free(line); continue; } //******************************************************************* //need to generate argv array tok = strtok(line, " "); cmd_argv[0] = tok; i = 1; while( (tok = strtok(NULL, " ")) != NULL){ cmd_argv[i] = tok; if ( i+1 > MAX_ARGS ){ //don't go beyond MAX_ARGS break; } i++; } cmd_argv[i] = NULL; //NULL Final Space in argv array //record start time gettimeofday(&start, NULL); if ( (c_pid = fork()) == 0 ){ /* CHILD */ execvp(cmd_argv[0],cmd_argv); perror("mini-sh"); //error _exit(2); //hard exit, don't want a fork bomb! }else if (c_pid > 0){ /* PARENT */ //wait for child to fail if ( wait(&status) < 0){ perror("wait failed"); _exit(2); } //record time gettimeofday(&end, NULL); timeval_subtract(&diff, &end, &start); //******************************************************************* }else{ /* ERROR */ perror("fork failed"); _exit(2); } free(line); //free the current line } return 0; }