Sunday, October 19, 2014

Unix Prog: Job-Control Signals

1. Job-Control Signals

SIGCHLD, child process has stopped or continued.
SIGCONT, continue process, if stopped.
SIGSTOP, stop signal(can't be caught or ignored)
SIGTSTP, Interactive stop signal
SIGTTIN, Read from controlling terminal by member of a background process group
SIGTTOU, Write to controlling terminal by member of a background process group

Except for SIGCHLD, most applications don't handle the job-control signals, the shell itself will handle them. For example:

1) When typing the suspend character(ctrl-z), SIGTSTP is sent to all processes in the foreground process group.
2) When telling the shell to resume a job in the foreground or background, the shell sends all the processes in the job a SIGCONT signal.
3) If SIGTTIN or SIGTTOU is delivered to a process by shell, the process is stopped by default, and the job-control shell recognizes this and notifies us.

Interaction of job-control signals:
When any of the four stop signals(SIGTSTP, SIGSTOP, SIGTTIN, or SIGTTOU) is generated for a process, any pending SIGCONT signal for that process is discarded.

When SIGCONT signal is generated, any pending stop signals are discarded.

2. Example of job-control signal handling:

tstp.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<signal.h>  
   
 #define BUFFSIZE 1024  
   
 void sig_tstp(int signo)  
 {  
  sigset_t mask;  
   
  printf("\ncatch the stop signal. \n");  
   
  /* Before stopping the process, we can use code over here to re-setup  
   * the terminal. So user could do other work after this interactive app  
   * is stopped  
   */  
   
  // Unblock the SIGTSTP signal  
  sigemptyset(&mask);  
  sigaddset(&mask, SIGTSTP);  
  sigprocmask(SIG_UNBLOCK, &mask, NULL);  
   
  // Set the SIGTSTP signal back to default way, stop the process  
  signal(SIGTSTP, SIG_DFL);  
  kill(getpid(), SIGTSTP);  
   
  // Then the process get stopped, it won't return back from kill until  
  // receiving one SIGCONT signal  
   
  signal(SIGTSTP, sig_tstp);  
   
  /* After the process is continued, we can use code over there to re-clean  
   * the screen. So user could continue using the interactive app  
   */  
  printf("\ncatch the continue signal. \n");  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int n;  
  char buf[BUFFSIZE];  
   
  // only catch the SIGTSTP if we're running with a job-control shell  
  /* Note, init process will initialize the handler of SIGTSTP to be SIG_IGN,  
   * and job-control shell will re-setup it to be SIG_DFL)  
   */  
  if(signal(SIGTSTP, SIG_IGN) == SIG_DFL)  
   signal(SIGTSTP, sig_tstp);  
   
  while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)  
   if(write(STDOUT_FILENO, buf, n) != n) {  
    printf("write error!\n");  
    exit(1);  
   }  
   
  if(n < 0) {  
   printf("read error!\n");  
   exit(2);  
  }  
   
  exit(0);  
 }  

shell:
Run the tstp.out, after typing the Ctrl Z to trigger the SIGTSTP signal, the signal handler catch the stop signal and stuck on "kill(getpid(), SIGTSTP)".
Run the fg command, to send SIGCONT signal, then "kill" system call return and re-setup the SIGTSTP handler.
 ubuntu@ip-172-31-23-227:~$ ./tstp.out  
 Hello world!  
 Hello world!  
 ^Z  
 catch the stop signal.  
   
 [2]+ Stopped         ./tstp.out  
 ubuntu@ip-172-31-23-227:~$ fg  
 ./tstp.out  
   
 catch the continue signal.  
 Hello world!  
 Hello world!  
 ^C  

No comments:

Post a Comment