IC221: Systems Programming (SP14)


Home Policy Calendar Syllabus Resources Piazza

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;
}