Lab Four (4)  Signals, alarm , pause, kill, raise 
See 'man 7 signal' for a list of all the signals
NAME
       signal - ANSI C signal handling
SYNOPSIS
       #include 
       typedef void (*sighandler_t)(int);
       sighandler_t signal(int signum, sighandler_t handler);
DESCRIPTION
       The signal() system call installs a new signal handler for
       the signal with number signum.  The signal handler is  set
       to  sighandler  which may be a user specified function, or
       either SIG_IGN or SIG_DFL.
       Upon arrival of a signal with number signum the  following
       happens.   If the corresponding handler is set to SIG_IGN,
       then the signal is ignored.  If  the  handler  is  set  to
       SIG_DFL,  then the default action associated to the signal
       (see signal(7)) occurs.  Finally, if the handler is set to
       a  function  sighandler  then  first either the handler is
       reset to SIG_DFL or an  implementation-dependent  blocking
       of  the  signal is performed and next sighandler is called
       with argument signum.
       Using a signal handler function for  a  signal  is  called
       "catching  the  signal".   The signals SIGKILL and SIGSTOP
       cannot be caught or ignored.
RETURN VALUE
       The signal() function returns the previous  value  of  the
       signal handler, or SIG_ERR on error.
IMPORTANT NOTE:
       What should the operating system do if a process receives
       interupt (signal) X while it is in the middle of handling
       interupt X? On some OS, it ignores the interupt until it
       has finished the first interupt.  The more recent Linux 
       versions do not do this, instead they immediately handle 
       the 2nd interupt but instead of doing the interupt function
       handler they do the default behaviour of the interupt 
       (usually terminating the process). This can be a problem 
       if your program is not properly synchronized.
Program to demostrate the 'catching' or 'trapping' of the signal FPE 
(divide-by-zero)
//by Nachum Danzig
#include 
#include 
static void sig_fpe(int signo) ;
int main(void)
{
 int x = 0;
 int y;
 if (signal(SIGFPE, sig_fpe) == SIG_ERR)
      perror("can't catch SIGFPE");
 y= 7/x;
 printf("hello");
 return 1;
}
//our trap function
static void sig_fpe(int signo) /*argument is signal number*/
{
 printf("You divided by zero, didn't you?\n");
 raise(SIGALRM);
 return;
}
Program to demostrate the 'catching' or 'trapping' of the signal crtl-c
//by Nachum Danzig
#include   
#include 
static void sig_interupt(int signo) ;
int main(void)
{
  if (signal(SIGINT, sig_interupt) == SIG_ERR)
    perror("can't catch SIGINT");
  for( ; ; )
    pause();//wait for any signal (only needed so the loop does not waste CPU time)
}
//our trap function
static void sig_interupt(int signo) /*argument is signal number*/
{
  printf("received SIGINT, but I ain't quitin'\n");
  return;
}
NAME
       pause - wait for signal
SYNOPSIS
       #include 
       int pause(void);
DESCRIPTION
       The  pause  library function causes the invoking process (or thread) to
       sleep until a signal is received that either terminates it or causes it
       to call a signal-catching function.
RETURN VALUE
       The  pause  function only returns when a signal was caught and the sig-
       nal-catching function returned. In this  case  pause  returns  −1,  and
       errno is set to EINTR.
#include   
#include 
static void sig_usr(int signo) ;
int main(void)
{ int counter=0;
  if (signal(SIGUSR1, sig_usr) == SIG_ERR)
    perror("can't catch SIGUSER1");
  if (signal(SIGUSR2, sig_usr) == SIG_ERR)
    perror("can't catch SIGUSER2");
  for( ; ; )
    {
      printf("loop number:  %d\n", ++counter);
      pause();//wait for any signal
    }
}
//one trap which handles two different interrupts
static void sig_usr(int signo) /*argument is signal number*/
{
  if (signo == SIGUSR1)
    printf("received SIGUSR1\n");
  else if (signo == SIGUSR2)
    printf("received SIGUSR2\n");
  return;
}
NAME
       alarm - set an alarm clock for delivery of a signal
SYNOPSIS
       #include 
       unsigned int alarm(unsigned int seconds);
DESCRIPTION
       alarm arranges for a SIGALRM signal to be delivered to the
       process in seconds seconds.
       If seconds is zero, no new alarm is scheduled.
       In any event any previously set alarm is cancelled.
RETURN VALUE
       alarm returns the number of seconds  remaining  until  any
       previously  scheduled  alarm  was  due to be delivered, or
       zero if there was no previously scheduled alarm.
An Example which demonstrates having a process sleep
until the ALRM signal is registered
//by Nachum Danzig
#include   
#include 
#include   
static void sig_alarm(int signo) ;
unsigned int mysleep(unsigned int nsecs );
//#define SIG_ERR (void (*)())-1
int main(void)
{ int unslept;
  for( ; ; )
    {
      printf("go to sleep.\n");
      unslept=mysleep(2);
      printf("%s \n", unslept);
    }
}
static void sig_alarm(int signo) /*argument is signal number*/
{
  return;//do nothing, just return to wake up the pause
}
  
unsigned int mysleep(unsigned int nsecs )
{
 if (signal(SIGALRM, sig_alarm) == SIG_ERR)
    return(nsecs);
 alarm(nsecs);//start timer
 pause();       //next caught signal wakes us up
 return(alarm(0)); //turn off timer, return unslept time
}   
NAME
       kill - send signal to a process
SYNOPSIS
       #include 
       #include 
       int kill(pid_t pid, int sig);
DESCRIPTION
       The  kill  system  call  can  be used to send any signal to any process
       group or process.
       If pid is positive, then signal sig is sent to pid.
       If pid equals 0, then sig is sent to every process in the process group
       of the current process.
       If  pid equals -1, then sig is sent to every process except for process
       1 (init), but see below.
       If pid is less than -1, then sig is sent to every process in  the process group pid.
       If  sig  is 0, then no signal is sent, but error checking is still 
performed.
RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and  errno  is
       set appropriately.
       
IMPORTANT NOTE:  If the signo argument is 0, then the normal error checking is
       performed by kill, but no signal is sent.  This is a way to determine if a 
       specific process exists.  If we send the process the null signal but the
       process  does not exist, kill will return -1 and errno is set to ESRCH.
       (Because of the recylcing of PID's in UNIX, the PID maybe be in use by
       another process, so you can not be 100% sure the process you intend 
       still exists)
NAME
       raise - send a signal to the current process
SYNOPSIS
       #include 
       int raise(int sig);
DESCRIPTION
       The  raise()  function  sends  a  signal to the current process.  It is
       equivalent to
              kill(getpid(), sig);
RETURN VALUE
       0 on success, nonzero for failure.
An example demonstraing the sending of a signal to
a child process.
//by Nachum Danzig
#include   
#include 
#include 
  
static void sig_usr(int signo) ;
int counter = 0;
int main(void)
{
 
  int i, error, status;
  pid_t child1;
  error = kill(999999,0);//demonstrate checking if process exists
  printf("error: %d\n", error);
  if (signal(SIGUSR1, sig_usr) == SIG_ERR)
    perror("can't catch SIGUSER1");              
  child1=fork();
  if(0==child1)
    {
    printf("child is running\n");
    for(;;)
      {
      pause();//some code
      }
    }
  else
    {
      //we are Dad
      for( i=0;i<100000000;i++);//avoid race condition
      for(counter=0;counter<3;counter++)
	{
	  kill(child1, SIGUSR1);//the real point of this example, send signal to child
	}
	 kill(child1, 9);//cleanup, really KILL the child (KILL==9) (but child will still be a zombie)
	 wait(&status);//kill zombie child (see note on 'zombies' in Lab1)
	 error = kill(child1,0);//make sure child process no longer exists
         printf("error: %d\n", error);
    }
}
static void sig_usr(int signo) /*argument is signal number*/
{
  
  printf("child received SIGUSR1 by %d\n", getpid() );
  
}
Exercise 3
You are asked to create one pipe to be used as a communication exchange.
A parent process creates 3 child processes. It will signal which child is
to listen on the pipe at which time.  The parent process will allow the
user to choose to which process he wants to send a message.  
The user will be able to send a text message to any son he wants through 
the pipe common to all processes.  The user will be able to kill any child 
he desires, and at any time.  The program will keep running until the user kills
all the 3 child processes.
If user types 'quit' you must kill all children before exiting (otherwise they will
not die until the system comes down).
Do the same if the user types control-c (note: use a trap on control-c). 
Also the father may send signals other than -KILL (-9) to the children.
Implement 3 such signals of your choice. 
'man 7 signal'  will list for you all the signals.
Sample input and output:
>
> 1 hello 
son 1: hello
> 3 hello
son 3: hello
> 1 kill -KILL
father: son 1 terminated.
> 1 hello
father: son 1 no longer alive.
> 3 hello
son 3: hello 
> 3 kill -KILL
father: son 3 terminated.   
> 2 kill -KILL
father: all sons died. Bye.
>
>   
 Partial answer to problem. 
© Ari Cirota, Nachum Danzig and Erick Fredj