IC221: Systems Programming (SP14)


Home Policy Calendar Syllabus Resources Piazza

Lab 9: Signal Handling

Table of Contents

1 PART 1: Shredder:

 #include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <signal.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <sys/types.h>

int ticks = 0;
pid_t cpid;

void tick(int signum){
  //TODO: complete the SIGALRM handler
  //
  // One each alarm, print 
  //    printf("%d: tick-tock\n", ticks);
  //
  // If 5 ticks occur, kill the child with SIGKILL
  //
  // (hint: don't forget to set the next alarm)

  ticks++;

  printf("%d: tick-tock\n", ticks);

  if (ticks >= 5){
    kill(cpid, SIGKILL);
  }else{
    alarm(1);
  }

}

int main(int argc, char * argv[]){


  int status;

  if (( cpid = fork()) == 0){
    /*CHILD*/

    execvp(argv[1], argv+1);
    perror("execvp");
    _exit(1);
  }else if ( cpid > 0){
    /*PARRENT*/

    signal(SIGALRM, tick);

    //TODO: Complete the program
    // 
    // If the child finished before 3 ticks:
    //  "Blast that grotesque ganglion! You let them get away!\n"
    //
    // If the child finished after 3 ticks but not killed:
    //  "Sayonara you shell-backed simpletons. I'll get you next time!\n"
    //
    // If the child was killed:
    //  "Tonight I dine on turtle soup! Muhaha!\n"
    //
    // (hint: don't forget to turn off unscheduled alarms)
    // (hint: recall the WIF---() functions ...)

    alarm(1);

    wait(&status);

    alarm(0);

    if (WIFEXITED(status)){
      if (ticks < 3){
        printf("Blast that grotesque ganglion! You let them get away!\n");
      }else{
        printf("Sayonara you shell-backed simpletons. I'll get you next time!\n");
      }
    }

    if ( WIFSIGNALED(status) ){
      printf("Tonight I dine on turtle soup! Muhaha!\n");
    }

  }else{
    /*ERROR*/
    perror("fork");
    _exit(1);
  }

  return 0;
}

2 PART 2: More Sons:

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>


#include <signal.h>
#include <sys/signal.h>

pid_t c_pid[4]; //array of 4 children pid's

void child_handler(int signum, siginfo_t * siginfo, void * context){
  int i;
  pid_t pid;


  //TODO: Complete the handler to print info about the child's state
  //
  //  You should investigate the following fields of the siginfo structure
  //  siginfo->si_pid    : pid of the signaling child
  //  siginfo->si_code   : why the child signaled SIGINFO
  //  signifo->si_status : status of a child
  //
  //  Read the man page for sigaction for more detail

  pid = siginfo->si_pid;

  for(i=0;i<4;i++){
    if(c_pid[i] == pid){
      break;
    }
  }

  printf("Parent: Child %d: %d ", i, pid);

  if( siginfo->si_code ==  CLD_STOPPED ){
    printf("stopped, continuing ...\n");
    kill(pid,SIGCONT);
  }else if( siginfo->si_code ==  CLD_CONTINUED ){
    printf("just continued\n");
    kill(pid,SIGCONT);
  }else if( siginfo->si_code == CLD_EXITED){
    printf("terminated and exited with status %d\n", siginfo->si_status);
  }else if(siginfo->si_code == CLD_KILLED){
    printf("terminated and exited due to signal no. %d", siginfo->si_status);
    if( siginfo->si_code == CLD_DUMPED){
      printf(" and also core dumped\n");
    }else{
      printf("\n");
    }
  }

  fflush(stdout);
}

int main(){


  pid_t pid;
  int i;

  setvbuf(stdout, NULL, _IONBF, 0);

  struct sigaction action;
  //TODO: Setup the sigaction
  //  
  //  (hint: you will need a restart, siginfo, and nodefer flag. Use and ORing)

  action.sa_sigaction = child_handler;
  action.sa_flags = SA_RESTART | SA_SIGINFO | SA_NODEFER; 
  sigaction(SIGCHLD, &action, NULL);


  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: Sending myself SIGSTOP\n", pid);
        fflush(stdout);
        kill(getpid(), SIGSTOP);

        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);
        fflush(stdout);
        int * p = NULL; 
        *p = 10; //dereferencing NULL

        exit(1);//just in case
        break;
      case 2:
        //Child 2: The wicked son
        printf("Child 2: %d: Scheduling an alarm for 1 second\n", pid);
        fflush(stdout);
        alarm(1);
        pause();

        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 .... exit 0?\n", pid);
        fflush(stdout);
        exit(0); //success?
        break;
      }

    }
  } 
  /*Parent*/

  //Loop unitl all children terminate
  while(wait(NULL) > 0);

  return 0;
}