1. Signal Concept
A signal is a message (event) that is generated by itself or sent by the process outside the process during its operation. The signal is a hardware interrupt software simulation (soft interrupt). Each signal is represented by an integer macro constants, starting with the sig, such as SIGCHLD, SIGINT, etc., which are defined in the system header file <signal.h> , or can be typed under the shell kill–l View a list of signals, or type man 7 signal for more detailed instructions.
The signal is generated from the kernel, allowing the kernel to generate signal requests from 3 locations:
L User: The user can request the kernel to generate a signal by entering CTRL + C, ctrl+\, or any other key assigned to the signal control character by the terminal driver;
L Kernel: When the process executes an error, the kernel sends a signal to the process, such as illegal segment access (memory access violation), floating-point overflow, and so on;
L Process: A process can send a signal to another process through a system call to kill, and a process can communicate through a signal to another process.
A signal generated by an operation of the process is called a synchronous signal (synchronous signals), for example, except 0; a signal generated by a process external event such as a user keystroke is called an asynchronous signal (asynchronous signals).
After the process receives the signal, the following 3 options can be processed:
L Receive default processing: The process that receives the default processing usually causes the process itself to die out. For example, the process of connecting to the terminal, the user presses CTRL + C, will cause the kernel to send a SIGINT signal to the process, if the process does not do special processing of the signal, the system will use the default method to process the signal, that is, the execution of the termination process; signal (SIGINT,SIG_DFL);
L Ignore signal: The process can ignore the processing of a signal through the code, for example: signal (sigint,sig_ign), but some signals can not be ignored;
L capture Signal and process: The process can register the signal processing function in advance, and when the signal is received, the signal processing function automatically captures and processes the signal.
There are two of signals that cannot be ignored or captured, and they are Sigkill and sigstop. That is, after the process receives both signals, it can only accept the default processing of the system, that is, terminate the process.
2. Signal signal Processing mechanism
A signal capture function can be registered with the function signal. The prototypes are:
#include <signal.h>
typedef void (*sighandler_t) (int); function pointers
sighandler_t signal (int signum, sighandler_t handler);
The 1th parameter of the signal Signum represents the signal to be captured, and the 2nd parameter is a function pointer representing the function to capture the signal, which can also be SIG_DFL (denoted by default processing by the system, equivalent to white registration) or sig_ign ( Indicates that the signal is ignored and no processing is done). Signal if the call succeeds, returns the address of the previous handler function for the signal, otherwise returns SIG_ERR.
sighandler_t is a signal capture function, which is registered by the signal function and is valid during the entire process, and can register the same signal capture function for different signals. The function has only one integer parameter, which represents the signal value.
Example:
1. Capture the SIGINT signal generated by the terminal CTRL + C:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
void Signhandler (int isignno)
{
printf ("Capture sign no:%d\n", Isignno);
}
int main ()
{
Signal (Sigint,signhandler);
while (1)
Sleep (1);
return 0;
}
After the program runs, by pressing CTRL + C will no longer terminate the program's run (or another terminal, and then send the message: "Kill–s 2 process Number" or "Kill-2 process number", you can achieve the same effect as CTRL + C.) Because the SIGINT signal generated by CTRL + C has been captured by the Signhandler function registered in the process. The program can be terminated by ctrl+\, because the combination key ctrl+\ can produce sigquit signal, and the capture function of the signal has not yet been registered in the program.
2. Ignore the SIGINT signal generated by the terminal CTRL + C:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
int main ()
{
Signal (sigint,sig_ign);
while (1)
Sleep (1);
return 0;
}
After the program runs, the SIGINT signal generated by CTRL + C is ignored, so CTRL + C will no longer be able to terminate the process, to terminate the process, you can send a sigquit signal to the process, that is, the composite key ctrl+\. Alternatively, open a port, and then execute the Ps–aux view process, and then discover the process number and then kill the process with the kill-9 process number.
3, accept the default processing of the signal, accept the default processing is equivalent to no write signal processing program:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
int main ()
{
Signal (SIGINT,SIG_DFL);
while (1)
Sleep (1);
return 0;
}
3. Sigaction signal Processing mechanism 3.1. Analysis of signal processing condition
Under the signal processing mechanism, there are many special cases to consider:
1, register a signal processing function, and after processing completed a signal, whether it is necessary to re-register, to be able to capture the next signal; (not required)
2, if the signal processing function is processing the signal, and has not finished processing, there is a signal of the same type, then how to deal with; (next to the execution)
3, if the signal processing function is processing the signal, and has not finished processing, there is a different type of signal, then how to deal with it; (jump to execute another signal, and then execute the rest of the signal is not finished processing)
4. If the program is blocked in a system call (such as read (...)) , a signal occurs when the system call returns an error and then enters the signal processing function, or jumps to the signal processing function, and the system call returns when the signal processing is complete.
Example:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iseq = 0;
void Signhandler (int isignno)
{
int iSeq = g_iseq++;
printf ("%d Enter signhandler,signo:%d\n", Iseq,isignno);
Sleep (3);
printf ("%d Leave signhandler,signo:%d\n", Iseq,isignno);
}
int main ()
{
Char Szbuf[8];
int iRet;
Signal (Sigint,signhandler); Different signals call the same handler function
Signal (Sigquit,signhandler);
do{
IRet = Read (stdin_fileno,szbuf,sizeof (SZBUF)-1);
if (IRet < 0) {
Perror ("read fail.");
Break
}
Szbuf[iret] = 0;
printf ("Get:%s", szbuf);
}while (strcmp (szbuf, "quit\n")! = 0);
return 0;
}
When the program runs, for the following types of input (to enter fast), see the output:
1, [Ctrl + C] [Ctrl + C] (one by one next to execute)
2, [Ctrl + C] [ctrl+\] (first execution of the entry, is interrupted, to execute \, and finally execute C exit)
3. Hello [ctrl+\] [Enter] (interrupt first, no output)
4. [ctrl+\] Hello [Enter] (interrupt first, output content)
5, Hel [ctrl+\] lo[enter] (interrupt first, output lo only)
3.2. Sigaction Signal Processing Registration
Function Prototypes:
#include <signal.h>
int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact);
Sigaction is also used to register a signal processing function
Parameter Signum for signals that need to be captured
The parameter act is a struct containing information such as the address of the signal processing function, the processing method, etc.
The parameter oldact is an outgoing parameter, and after the Sigaction function call succeeds, Oldact contains information about how the Signum was previously handled, usually null
If the function call succeeds, it returns 0, otherwise 1
The prototype of struct struct sigaction (note the same name as the function Sigaction) is:
struct Sigaction {
void (*sa_handler) (int); The old type of signal processing function pointer
void (*sa_sigaction) (int, siginfo_t *, void *);//new type of signal processing function pointer
sigset_t Sa_mask; The set of signals that will be blocked
int sa_flags; Signal Processing mode mask (èsa_siginfo)
void (*sa_restorer) (void); Reserved, do not use
};
The meaning of each field of the structure and how to use it:
1. Field Sa_handler is a function pointer that points to the address of the signal-processing function of the prototype void handler (int), which is the old type of signal processing function (if you use this again to Sa_flags = 0, it is equivalent to the signal () function)
2, Field sa_sigaction is also a function pointer, used to point to the prototype as:
void handler (int isignnum, siginfo_t *psigninfo, void *preserved);
Signal processing function, which is the new type of signal processing function
The three parameters of the function mean:
Isignnum: Incoming signal
Psigninfo: Some information related to this signal, it is a structure
Preserved: reserved, now useless, usually null
3, field Sa_handler and sa_sigaction should only have one effective, if you want to use the old signal processing mechanism, you should let Sa_handler point to the correct signal processing function, and let the field sa_flags 0; otherwise, you should let Sa_ Sigaction points to the correct signal processing function, and lets the field sa_flags contain sa_siginfo options
4, the field sa_mask is a structure containing a signal set, the structure of the signal in the body to signal processing, the signal will be blocked. For the sigset_t struct, there is a set of specialized functions to handle it, which are:
#include <signal.h>
int Sigemptyset (sigset_t *set); Clear signal Set Set
int Sigfillset (sigset_t *set); Fill all the signals into the set
int Sigaddset (sigset_t *set, int signum); Adding a signal to the set Signum
int Sigdelset (sigset_t *set, int signum); Removing the signal from set Signum
int Sigismember (const sigset_t *set, int signum); Determine if Signum is contained in set (yes: Return 1, no: 0)
int sigpending (sigset_t *set); The set of blocked signals is returned by the parameter set pointer
wherein, for the function sigismember, if Signum is in the set set, it returns 1; no, 0 is returned, and 1 is returned when an error occurs. All other functions return 0 successfully and fail back-1.
For example, if you intend to only block the processing of the sigquit signal when processing the signal SIGINT, you can use the following method:
struct Sigaction Act;
Act.sa_flags = Sa_siginfo;
Act.sa_sigaction = Newhandler;
Sigemptyset (&act.sa_mask);
Sigaddset (&act.sa_mask, sigquit);
Sigaction (Sigint,&act,null);
5, the field Sa_flags is a set of mask composite values, indicating the signal processing should take some of the behavior, the meaning of each mask is:
Mask |
Describe |
Sa_resethand |
After processing the signal to be captured, the registration of the signal processing function is automatically reversed, that is, the signal processing function must be re-registered in order to continue processing the next generated signal. This option does not conform to the general signal processing process and is now obsolete. |
Sa_nodefer |
In the processing of signals, if another signal occurs, immediately into the processing of other signals, and other signal processing, and then continue to deal with the current signal, that is, to handle the recursive. if Sa_flags contains the mask, the struct sigaction the Sa_mask will not work! (not commonly used) |
Sa_restart |
If the program is blocking a system call in the event of a signal, such as calling the Read () function, the signal is processed and then returned from the blocked system. If this parameter is not specified, the Read function reads failed after the interrupt processing is complete. |
Sa_siginfo |
Indicates which of the struct's signal-processing function pointers are valid, and if sa_flags contains the mask, the sa_sigaction pointer is valid, otherwise the Sa_handler pointer is valid . Common |
Example1: Uses sigaction to implement the same functions as signal (only one parameter can be passed).
#include <signal.h>
#include <stdio.h>
void handle (int signo)
{
printf ("Signo:%d\n", Signo);
}
Main ()
{
struct Sigaction St;
St.sa_handler = handle;
st.sa_flags = 0;
Sigaction (Sigint,&st,null);
while (1)
{
Sleep (1);
}
}
Example2: Call new signal processing function with Sigaction implementation
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iseq = 0;
void signhandlernew (int isignno,siginfo_t *pinfo,void *preserved)
{
int iSeq = g_iseq++;
printf ("%d Enter signhandlernew,signo:%d\n", Iseq,isignno);
Sleep (3);
printf ("%d Leave signhandlernew,signo:%d\n", Iseq,isignno);
}
int main ()
{
struct Sigaction Act;
Act.sa_sigaction = signhandlernew;
Act.sa_flags = Sa_siginfo;
Sigaction (Sigint,&act,null);
Sigaction (Sigquit,&act,null);
while (1)
{
Sleep (1);
}
return 0;
}
Practice and Validation:
For the previous 5 input cases, add some code to the following code to make it possible to respond in various forms as follows:
1, [Ctrl + C] [Ctrl + C], the 1th signal processing blocking the 2nd signal processing;
2, [Ctrl + C] [Ctrl + C], the 1th signal processing, allow a recursive 2nd signal processing;
3, [Ctrl + C] [ctrl+\], the 1th signal blocking the 2nd signal processing;
4. Read do not return failed results because of signal processing.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iseq = 0;
void signhandlernew (int isignno,siginfo_t *pinfo,void *preserved)
{
int iSeq = g_iseq++;
printf ("%d Enter signhandlernew,signo:%d.\n", Iseq,isignno);
Sleep (3);
printf ("%d Leave signhandlernew,signo:%d\n", Iseq,isignno);
}
int main ()
{
Char Szbuf[8] = {0};
int iRet = 0;
struct Sigaction Act;
Act.sa_sigaction = signhandlernew;
Act.sa_flags = Sa_siginfo | Sa_restart;
Sigemptyset (&act.sa_mask);
Sigaddset (&act.sa_mask, sigquit);
Sigaction (Sigint,&act,null);
do{
IRet = Read (stdin_fileno,szbuf,sizeof (SZBUF)-1);
if (IRet < 0) {
Perror ("read fail");
Break
}
Szbuf[iret] = 0;
printf ("Get:%s", szbuf);
}while (strcmp (szbuf, "quit\n")! = 0);
return 0;
}
You will find that when a signal is blocked, the signal occurs several times before unblocking, but when unblocked, the kernel sends only one signal to the process, regardless of how many signals are generated during its blocking, because Linux does not queue the signal. In addition, this is used to interrupt the read input interrupt processing, must be added parameter Sa_restart, for the signal function, it installs the signal processing function, the system by default automatically restarts the interrupted system call, rather than let it error return. For the Sigaction function, you must specify the Sa_restart to implement the restart function, if not specified will read fails, prompting read when the interrupt occurs.
Signal Processing (i)