first, what is the signal
We all know that with windows, when we can't end a program properly, we can force this process to end with the task manager, but how does it work? The same functionality is achieved on Linux by generating signals and capturing signals, and the running process captures the signal and then makes certain operations and ends up being terminated.
The signal is an event that occurs when UNIX and Linux systems respond to certain conditions, and the process that receives the signal takes some action accordingly. Usually the signal is generated by an error. However, they can also be used as a way to communicate or modify behavior between processes, explicitly sent to another process by one process. The generation of a signal is called generate, which receives a signal called capture.
ii. Types of signals
The name of the signal is defined in the header file signal.h, the signal is beginning with the sig, the commonly used signal is not many, the commonly used signal is as follows:
More signal types can be seen in the appendix table.
third, the Signal processing--signal () function
The program can use the signal function to process the specified signal, primarily by ignoring and restoring its default behavior. The signal function is prototyped as follows:
#include <signal.h>
void (*signal(int sig, Void (*FUNC) (int)))) (int);
This is a fairly complex statement, so be patient. Signal is a function with the sig and Func two parameters, and Func is a function pointer of type void (*) (int). The function returns a pointer of the same type as func, pointing to a function pointer that previously specified the signal handler function. The parameters for the signal to be captured are given by the sig, and the function to be called after the specified signal is received is given by the parameter func. In fact, the use of this function is quite simple, through the following example can be known. Note that the prototype of the signal processing function must be void func (int), or the following special value:
sig_ign : Ignore signal
SIG_DFL : Default behavior for recovering signals
Say so much, or give an example to illustrate, the source file is named signal1.c, the code is as follows:
#include <signal.h> #include <stdio.h> #include <unistd.h>void ouch (int sig) {printf ("\nouch! -I got signal%d\n ", SIG); Restore terminal interrupt signal SIGINT default behavior (void) signal (SIGINT, SIG_DFL);} int main () {//change the default behavior of the terminal interrupt signal SIGINT to perform the Ouch function//instead of terminating the execution of the program (void) signal (SIGINT, ouch); while (1) {printf ("Hello world!\n "); sleep (1);} return 0;}
The results of the operation are as follows:
As you can see, the first time you press the abort command (CTRL + C), the process is not terminated, and the polygon is the output ouch! -I got signal 2, because the default behavior of SIGINT is changed by the signal function, when the process receives the signal SIGINT, it calls the function ouch to deal with, notice that the OUCH function changes the signal SIGINT processing mode to the default mode, So when you press CTRL + C again, the process is terminated as it was before.
four, signal processing--sigaction () function
Before we saw the signal function for signal processing, but generally we can use a more robust signal interface--sigaction () function. Its prototype is:
#include <signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
The function, like the signal function, is used to set the action associated with the signal sig, and if the oact is not a null pointer, it is used to preserve the position of the original action on the Signal, and act is used to set the action of the specified signal.
The sigaction struct is defined in signal.h, but it includes at least the following members:
Void (*) (int) Sa_handler: Handles the function pointer, which is equivalent to the Func parameter of the signal function.
sigset_t sa_mask: Specify one. Signal set, the signal set is added to the signal screen word of the process before calling the signal processing function pointed to by Sa_handler. The signal screen word refers to a set of signals that are currently blocked, which cannot be received by the current process
int sa_flags: signal processing modifier;
The value of Sa_mask is usually set by using a signal set function, and I'll tell you more about the signal set function in my next article,--linux interprocess communication-the signal set function.
Sa_flags, you can usually take the following values:
In addition , there is now a problem where we use the signal or Sigaction function to specify the function that handles the signal, but how will the process react if the signal processing function is received before the signal is processed? It will not be processed with the processing function we set up as we imagined. Sa_mask solves this problem, Sa_mask specifies a set of signals that will be added to the signal-processing function of the process before calling the signal handler of the Sa_handler, Setting the signal screen Word prevents the signal from being received at the end of its processing function, that is, using the Sa_mask field to eliminate this race condition.
To undertake the above example, the following gives the example code with sigaction function rewrite, the source file is signal2.c, the code is as follows:
#include <unistd.h> #include <stdio.h> #include <signal.h>void ouch (int sig) {printf ("\nouch! -I got signal%d\n ", SIG);} int main () {struct sigaction act;act.sa_handler = ouch; Create an empty signal screen word, that is, do not block any information sigemptyset (&act.sa_mask); Resets the Sigaction function to the default behavior act.sa_flags = Sa_resethand;sigaction (SIGINT, &act, 0), while (1) {printf ("Hello world!\n"); Sleep (1);} return 0;}
The result of the operation is the same as in the previous example. Note that the Sigaction function is not reset by default, and if you want to reset it, the sa_flags will be sa_resethand.
v. Send a signal
The function mentioned above is how some processes react to this signal after receiving a signal, that is, the problem of signal processing, is there any function that can actively send a signal to a process? We can send a signal via two function kill and alarm.
1. Kill () function
Let's take a look at the kill function, where a process can send a signal to other processes, including itself, through the kill function, and if the program does not have permission to send the signal, the call to the KILL function will fail, and the common reason for the failure is that the target process is owned by another user. Think it is easy to understand, you can not control other people's program, of course, super User root, this kind of God-like existence is excepted.
The prototype of the Kill function is:
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
Its role is to send the signal sig to process number PID process, return 0 on success.
The kill call failed to return 1, and there are usually three main reasons for the call to fail:
1, the given signal is invalid (errno = EINVAL)
2. Insufficient send permission (errno = eperm)
3. The target process does not exist (errno = Esrch)
2. Alarm () function
This function, like its name, provides us with an alarm function that the process can call the alarm function to send a SIGALRM signal after a predetermined time.
The type of the alarm function is as follows:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
The alarm function is used to schedule the sending of a sigalrm signal after seconds seconds, and if the seconds is 0, all set alarm requests are canceled. The return value of the alarm function is the remaining number of seconds of the previously set alarm time, and returns 1 if the return fails.
Nonstop, the following gives the fork, sleep and signal functions, with an example to illustrate the use of the kill function, the source file is signal3.c, the code is as follows:
#include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include < signal.h>static int alarm_fired = 0;void Ouch (int sig) {alarm_fired = 1;} int main () {pid_t pid;pid = fork (), switch (PID) {case-1:perror ("fork failed\n"), exit (1), case 0://child process sleep (5) ; Sends a signal to the parent process Kill (Getppid (), SIGALRM); exit (0);d efault:;} //Set handler function signal (SIGALRM, ouch), while (!alarm_fired) {printf ("Hello world!\n"); sleep (1);} if (alarm_fired) printf ("\ni got a signal%d\n", SIGALRM); exit (0);}
The results of the operation are as follows:
In the code we use the fork call to replicate a new process, in the child process, after 5 seconds to send a SIGALRM signal to the parent process, the parent process to capture the signal, and use the Ouch function to process, change the value of alarm_fired, and then exit the loop. From the results we can also see the output of 5 Hello world! After that, the program receives a SIGARLM signal and then ends the process.
Note: If the parent process has nothing to do before the signal from the child process arrives, we can use the function pause () to suspend the parent process until the parent process receives the signal. When the process receives a signal, the pre-programmed signal processing function will start to run and the program will return to normal execution. This saves CPU resources because you can avoid using a loop to wait. In this example, you can change the while loop to one sentence, pause ();
Here is a small example to illustrate the use of the alarm function and the pause function, the source file name is, SIGNAL4.C, the code is as follows:
#include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include < signal.h>static int alarm_fired = 0;void Ouch (int sig) {alarm_fired = 1;} int main () {//correlation signal processing function signal (SIGALRM, ouch); Call the alarm function, send the signal after 5 seconds sigalrmalarm (5); //Suspend process pause (); After receiving the signal, return to normal execution if (alarm_fired = = 1) {printf ("Receive a signal%d\n", SIGALRM); } Exit (0);}
The results of the operation are as follows:
The process receives a SIGALRM after 5 seconds, the process resumes running, prints the information, and exits.
Six, the security problem of signal processing function
Imagine a problem when a process receives a signal and goes to your associated function, but when it executes, the process receives the same signal or another signal and executes the associated function, what does the program do?
In other words, the signal processing function can be interrupted during its execution and called again. It is critical that it continue to operate correctly when it returns to the first call. This is not just a question of recursion, but a reentrant (that is, it can be completely entered and executed again). In the case of Linux, the kernel will need to re-enter the interrupt service routines that handle multiple devices at the same time, because higher-priority interrupts may "insert" during the execution of the same piece of code.
In short, that is, if our signal processing function can be re-entered, that is, we can safely enter and execute again after leaving, in order for the signal processing function to be reentrant, it is not possible to call the non-reentrant function in the information processing function. Here are the reentrant functions in the list, the functions that are not in this table are non-reentrant, and the reentrant function table is as follows:
VII. Appendix--Signal Table
If the process receives one of these signals, and no prior arrangements are made to capture it, the process terminates.
There are other signals, as follows:
Reference:
http://blog.csdn.net/ljianhui/article/details/10128731
Linux interprocess communication-semaphore function signal (), sigaction ()