Signal 2 of IPC mode under Linux

Signal 2 of IPC mode under Linux

3. Signal set operation function

The kernel determines whether the signal should be processed by reading the set of pending signals. The signal mask word mask can affect the pending signal set. We can customize the set in the application to change the mask. The purpose of shielding the specified signal has been achieved.

3.1 signal set setting

sigset_t  set;		// typedef unsigned long sigset_t; 
int sigemptyset(sigset_t *set);					Set a signal0		 		success:0;Failed:-1
int sigfillset(sigset_t *set);					Set a signal1		  		success:0;Failed:-1
int sigaddset(sigset_t *set, int signum);		Add a signal to the signal set  		success:0;Failed:-1
int sigdelset(sigset_t *set, int signum);		Clearing a signal out of a signal set   		success:0;Failed:-1
int sigismember(const sigset_t *set, int signum);Judge whether a signal is in signal concentration	Return value: in the collection:1;be not in:0;Error:-1  

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);-Used to set or unblock a signal set
int sigpending(sigset_t *set);-Get pending signal set

sigset_ The essence of type T is bitmap. However, bit operation should not be used directly, but the above functions should be used to ensure effective cross system operation.
Compare the cognitive select function.

3.2 sigprocask function

This function is also used to mask and unshield signals. In essence, read or modify the signal mask word of the process (in PCB)
Strictly note that shielding signal: it only delays the signal processing (until the shielding is removed); ignoring means that the signal processing is lost.

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);	
//success:0;Failed:-1,set up errno

Parameters:

Set: the passed in parameter is a bitmap. The position 1 in the set indicates which signal the current process shields.

oldset: outgoing parameter, saving the old signal mask set.

how parameter value: assume that the current signal mask word is mask
 1.SIG_BLOCK: set block. When how is set to this value, set indicates the signal to be masked. Equivalent to mask = mask|set
 2.SIG_UNBLOCK: unblock. When how is set to this, set indicates the signal to be unshielded. Equivalent to mask = Mask & ~ set
 3.SIG_SETMASK: set to the new set of blocking signals. When how is set to this, set represents the new mask set used to replace the original mask set. Equivalent to mask = set, calling sigprocmask to unblock several current signals, at least one of them will be delivered before sigprocmask returns.

3.3 sigpending function

Read the pending semaphore set for the current process

int sigpending(sigset_t *set);	
set outgoing parameters.   
Return value: Success: 0; failure: - 1, set errno

3.4 put the pending signal set of all conventional signals on the screen

Put signal 2 (ctrl+c) on the blocking signal set, so that the signal will be reserved on the pending signal set

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
 
int main(){
	sigset_t pend, sigproc;
	//Set the blocking signal and wait for the key to generate the signal
	//Clear first
	sigemptyset(&sigproc);
	//Put signal 2 (ctrl+c) in the set
	sigaddset(&sigproc, SIGINT);
	//Set blocking signal set
	sigprocmask(SIG_BLOCK, &sigproc, NULL);
 
	//Cycle the signal in the pending signal set
	while(1){
		//Loop read pending signal, print
		sigpending(&pend);
		for(int i=0; i<32; i++){
			//There is a signal set
			if(sigismember(&pend, i)==1){
				printf("1");
			}else{
				printf("0");
			}
		}
		printf("\n");
		sleep(1);
	}
 
	return 0;
}

4. Signal capture (important)

The main purpose is to prevent accidental death of the process

4.1 signal function

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

signum 		Signals to capture
handler 	To execute a capture function pointer, the function should declare void func(int);//Variable function name

4.2 sigaction function

Modify signal processing actions (usually used in Linux to register a signal capture function)

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);  

Success: 0; failure: - 1, set errno
 Signal: captured signal
 act: passed in parameter, new processing method.
oldact: outgoing parameter, old processing method.	

struct sigaction structure

struct sigaction {
        void     (*sa_handler)(int);
        void     (*sa_sigaction)(int, siginfo_t *, void *);
        sigset_t   sa_mask; 
        int       sa_flags; 
        void     (*sa_restorer)(void);
    };
	sa_restorer: This element is obsolete and should not be used, POSIX.1The element will not be specified by the standard.(Discard)
	sa_sigaction: When sa_flags Designated as SA_SIGINFO Flag, use this signal handler.(Rarely used)  

Key points:
① sa_handler: function pointer. Specifies the name of the processing function after signal capture (that is, the registration function). Can also be assigned SIG_IGN table ignored or SIG_DFL table perform default action
② sa_mask: the set of signals (signal mask words) to be masked when calling the signal processing function. Note: the mask takes effect only when the processing function is called, which is a temporary setting.
③ sa_flags: usually set to 0, the table uses the default property.

Capture the number 14 suicide signal we regularly send to ourselves

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/time.h>
 
//Define capture function
void catch_sig(int num){
	printf("catch %d sig\n", num);
}
 
int main(){
	//Register capture function
	struct sigaction act;
	//The first capture function in the sigaction structure is used for you
	act.sa_flags=0;
	//The function pointer of the capture function points to the catch function we wrote above_ Sig
	act.sa_handler=catch_sig;
	//Clear signal set
	sigemptyset(&act.sa_mask);
	sigaction(SIGALRM, &act, NULL);
 
	//Setitimer five seconds later, every three seconds
	struct itimerval myit={{3,0},{5,0}};
	setitimer(ITIMER_REAL, &myit, NULL);
	while(1){
		printf("Who can kill me!\n");
		sleep(1);
	}	
	return 0;
}

Operation result:

4.3 signal capture characteristics

  1. When the process is running normally, there is a signal shielding word in the default PCB. If it is ☆, it determines which signals the process automatically shields. When a signal capture function is registered, it is called after the signal is captured. The function may be executed for a long time, during which the shielded signal is not specified by ☆. It's sa_mask to specify. After calling the signal processing function, restore it to ☆.
  2. During the execution of XXX signal capture function, XXX signal is automatically shielded.
  3. Queueing is not supported for blocked conventional signals, which are generated multiple times and recorded only once. (the last 32 real-time signals support queuing)

4.4 signal capture process in kernel

5. SIGCHLD signal (important)

5.1 generation conditions of sigchld

  1. When a subprocess terminates
  2. When the subprocess receives SIGSTOP signal
  3. When the subprocess is in the stop state and wakes up after receiving sigmont

5.2 signal recovery subprocess with SIGCHLD

When a child process pauses or ends running, its parent process will receive SIGCHLD signal. The default processing action for this signal is ignore. This signal can be captured to complete the state recovery of the subprocess in the capture function.
We can capture SIGCHLD signal to receive subprocesses back and forth.

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
 
void catch_sig(int num){
	pid_t pid=waitpid(-1, NULL, WNOHANG);
	if(pid>0){
		printf("wait child %d ok\n", pid);
	}
}
 
int main(){
	int i=0;
	pid_t pid;
	for(i=0; i<10; i++){
		pid=fork();
		if(pid==0){
			break;
		}
	}
	if(i==10){
		//father
		struct sigaction act;
		act.sa_flags=0;
		sigemptyset(&act.sa_mask);
		act.sa_handler=catch_sig;
		sigaction(SIGCHLD, &act, NULL);
		while(1){
			sleep(1);
		}
	}else if(i<10){
		printf("I am %d child, pid=%d\n", i, getpid());
		sleep(i);
	}
	return 0;
}


There is a problem with the above program. If the ten subprocesses die together instead of one by one, there will be a zombie process, because the signals are not queued.
Comment out the above program sleep(i)

else if(i<10){
		printf("I am %d child, pid=%d\n", i, getpid());
		//sleep(i);
	}

Operation result:

Improve the code above so that it doesn't have a zombie process. We are going to catch the signal collection function_ SIG uses a while loop to process the SIGCHLD signals collected by pid.

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
 
void catch_sig(int num){
	pid_t pid;
	//At this time, if multiple subprocesses die together, the pid pair obtains multiple signals
	while((pid=waitpid(-1, NULL, WNOHANG))>0) {
		if(pid>0){
			printf("wait child %d ok\n", pid);
		}
	}	
}
 
int main(){
	int i=0;
	pid_t pid;
	for(i=0; i<10; i++){
		pid=fork();
		if(pid==0){
			break;
		}
	}
	if(i==10){
		//father
		struct sigaction act;
		act.sa_flags=0;
		sigemptyset(&act.sa_mask);
		act.sa_handler=catch_sig;
		sigaction(SIGCHLD, &act, NULL);
		while(1){
			sleep(1);
		}
	}else if(i<10){
		printf("I am %d child, pid=%d\n", i, getpid());
	}
	return 0;
}


If the subprocess dies before signing up for sigaction, a zombie process will still be generated. How to avoid it?

Before the subprocess dies, if the main function has not registered sigaction, the SIGCHLD signal can be masked. The work of shielding signals should be done before creating subprocesses, so as to avoid errors in extreme cases.

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
 
void catch_sig(int num)
{
    pid_t wpid ;
    while( (wpid = waitpid(-1,NULL,WNOHANG)) > 0   ){
        printf("wait child %d ok\n",wpid);
    }
    
}
 
int main()
{
    int i =0;
    pid_t pid ;
 
    //Mask SIGCHLD signals before creating child processes
    sigset_t myset,oldset;
    sigemptyset(&myset);
    sigaddset(&myset,SIGCHLD);
    //oldset keeps the scene and sets SIGCHLD to block signal set
    sigprocmask(SIG_BLOCK,&myset,&oldset);
 
    for(i = 0 ; i < 10 ; i ++){
        pid =fork();
        if(pid == 0 ){
            break;
        }
    }
 
    if(i == 10 ){
        //parent 
		//Simulated registration dies after child process
        sleep(2);
        struct sigaction act ;
        act.sa_flags  = 0;
        sigemptyset(&act.sa_mask);
        act.sa_handler = catch_sig;
 
        sigaction(SIGCHLD,&act,NULL);
        
        //Unshielded site
        sigprocmask(SIG_SETMASK,&oldset,NULL);
 
        while(1){
            sleep(1);
        }
    }else if(i < 10){
        printf("I am %d child,pid = %d\n",i,getpid());
    }
 
    return 0;
}

Keywords: Linux

Added by moola on Thu, 11 Jun 2020 09:57:44 +0300