Table of contents
2.1 Hardware generation (press the key on the keyboard):
3. kill- [num] [pid] can send a signal to the process
5.1 Understanding of basic concepts:
5.3 The difference between real-time signal and non-real-time signal when registering:
6. Unify the understanding of signals
7.1 Deregistration of unreliable signals
7.2 Deregistration of reliable signals
8. Custom processing of signals
8.3 The principle of the two functions in the kernel:
Interlude the processing of the process kernel code
10.1 Characteristics of signal blocking:
11. Cooperate with the signal to solve the zombie process:
1. Process signal
1. The concept of signal
signal is a software interrupt
"Example of daughter-in-law crossing the road" in daily life
Daughter-in-law's call to eat is just a signal to tell you to eat, but it is not mandatory
1.1 just tells that there is such a signal, but how to deal with this signal and when to deal with it is determined by the process, so it is a soft interrupt
2. Signal generation
2.1 Hardware generation (press the key on the keyboard):
- ctrl+c : No. 2 signal SIGINT, pressing ctrl+c actually means that the process has received the No. 2 signal, and the No. 2 signal causes the process to exit.
- ctrl+z : No. 20 signal SIGTSTP,
ctrl+|: No. 3 signal SIGQUIT
The kill -l command can view the signal values defined by the operating system and the names corresponding to the signals
So what are these signals for?
We can see that the default action of SIGINT is term termination
Signals can also be sent through the kill command
2.2 Software generated:
1. kill function
int kill(pid_t pid,int sig);
- parameter:
- pid_t: To send to that process, fill in the pid of that process
- sig: the signal to send to the process
Use: We can send a No. 2 signal to the current process, and then run it to see the result
Run it:
found that the process terminated
2. raise function:
- Role: Who calls and who sends the signal
- Parameters: The signal value to send the signal to the calling process
- Use: Send yourself a No. 2 signal to terminate the process
Our code executes raise(2) in this process
One run: We found that the process also terminated after the raise call
3. kill- [num] [pid] can send a signal to the process
We can see that the process is suspended
3. Types of signals
kill -l can list signals
- Non-real-time signal (non-reliable signal):
- Feature: signal may be lost (1-31)
- Live signal (reliable signal):
- Features: Signal will not be lost (33-64)
4. Signal processing method
How the operating system handles signals (man 7 signal
term core cont ign stop
- Default processing method:
- SIG_DFL, the processing method of the number signal has been defined in the operating system
- For example signal number 2 -> terminate the process
- 11->Terminate the process and generate a core dump file
Ignore the processing method:
- SIG_ IGN, the signal is ignored ( zombie process )
- After the process receives the signal of ignoring the processing method, it does not process it, such as the generation of the zombie process learned before:
- The child process exits before the parent process, and the child process will send a SIGCHLD signal to the parent process when it exits, but the parent process ignores the processing of this signal, resulting in the parent process not recycling the exit status information of the child process, Thus the child process becomes a zombie process
- Custom processing:
- The programmer can change the signal processing method, define a function, and when the process receives the signal, call the function written by the programmer himself. (The 7th dot involves)
5. Registration of signals
5.1 Understanding of basic concepts:
- A process receives a signal, this process is called registration
- The registration and deregistration of signals are not a process, but two independent processes
Understanding of the signal registration bitmap in the kernel and the sigqueue queue
- They are all inside the task_struct structure
- Each process has its own unique registration bitmap and sigqueue queue
5.2 Registration of Signals:
- Change the bitmap to 1, add the Sigqueue node to the sigqueue queue
- When the signal is registered, the bit corresponding to the signal will be changed from 0 to 1, indicating that the current process has received the signal.
- You also need to add a sigqueue node to the sigqueue queue. The queue is essentially a doubly linked list in the operating system kernel (the first-in-first-out feature
The registration process is roughly as follows:
-
5.3 The difference between real-time signal and non-real-time signal when registering:
- Registration of non-real-time signals (non-reliable signals)
- The first registration: modify the sig bitmap (0-1), modify the sigqueue queue.
- The second registration: the signal of the same signal value, on the premise that the previous signal has not been processed: modify the sig bitmap (1->1), and will not add the sigqueue node.
- Summary: Add again, no sigqueue node will be added
- Registration of Live Signals (Reliable Signals)
- The first registration: modify the sig bitmap (0-1), modify the sigqueue queue.
- The second registration: the signal of the same signal value: modify the sig bitmap (1->1), add the sigqueue node to the sigqueue queue.
- Add it again, the siquque node will be added again
The reason why non-real-time signals are prone to signal loss is that the sigqueue node will not be added when registering again
6. Unify the understanding of signals
It is divided into three parts: before receiving the signal, receiving the signal, and processing the signal
7. Cancellation of signal:
-
7.1 Deregistration of unreliable signals
- 1. Set the bit position in the s ig bitmap corresponding to the signal to 0 (1-0)
- 2. Dequeue the sigqueue node of the corresponding signal
-
7.2 Deregistration of reliable signals
- 1. Dequeue the sigqueue node of the corresponding signal
- 2. Determine whether there are S igqueue nodes with the same signal in the s igqueue queue
- If there is: the bit remains unchanged
- If not: then bit change bit 0
8. Custom processing of signals
-
8.1 Concept:
- The custom processing method is to let the programmer define the processing method of a certain signal. For example, our No. 2 signal is a termination command. We can define it by ourselves to let him do other things, such as printing a sentence.
8.2 Functions
- 1.sighandler_t signal (int signum, sighandler_t handler);
- Function :
- When calling the signal function, we pass the address of a callback function to the second parameter of the function. When we receive the signal value defined by the first parameter, the callback function will be called to execute the function of the callback function.
- Parameters :
- signum: signal value
- handler: Change which function to handle, accept a function address, function pointer (callback function).
- typedef void (*sighandler_ t)(int);
- Code verification :
- Let's write a code to test what happens when the process receives signal No. 2 to see if the process is terminated
After knowing the custom processing method of the signal, we have a bold idea:
Consider the following piece of code:
So, isn't my process "invulnerable"?
Let's see what happens next
When other signals are killed, it doesn't work. Only signal No. 9 works. Why?
Because the No. 9 signal is a strong killing signal, it cannot be customized , (otherwise it would be the same as a cancer cell ...)
3.int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact)
For this function, we can also write code to verify:
We can find that this function can have the same effect as the signal function
We can also use this function to perform coquettish operations
Let's look at the following code:
In this code, we actually made two changes to signal No. 2, let's execute this code:
8.3 The principle of the two functions in the kernel:
structure in the kernel
Interlude the processing of the process kernel code
First we need to know the location of the process kernel code
Once we know the location, we can find
After vim sched.h, we entered the interface
So how to better find the definition of each structure and where it is used?
We can create an index relationship for the source code through ctags
9. Signal capture process
- When our process switches from kernel mode to user mode, do_signal is called to check whether the process has received a signal.
A process is registered with a signal by the operating system, and the process processes this signal only when it switches from user space to kernel space.
Call the dosignal function to judge whether the process has received a signal, and process it if there is one. When the processing is completed, the signal must be canceled from the process.
After logging out, return to the user state to continue executing his code. It is also possible that the process will be terminated directly when the signal is processed.
10. Signal blocking
-
10.1 Characteristics of signal blocking:
- The registration of a signal is a signal registration, and the signal blocking is a signal blocking. The blocking of the signal does not interfere with the registration of the signal, but means that after the process receives the signal, it does not process the signal temporarily due to blocking.
-
10.2 Interface:
- int sigprocmask (int how, const sigset_ t *Set, sigset_ t *oldset); (cannot block signals 9 and 19)
parameter:
- how: what do you want sigp rocmask to do
- SIG_ BLOCK: Set a signal to block
- SIG_ UNBL.OCK : Set a signal as non-blocking state
- SIG_SETMASK : Use the second parameter "set" to replace the original barrier bitmap. (meaning to replace)
- set : newly set blocking bitmap
- Compute a new blocking bitmap based on the function variables passed in:
- 1. Block a single signal, block multiple signals (just set the corresponding signal bitmap to 1)
- 2. Touch to block a single signal/unblock multiple signals.
- oldset : the original old blocking bitmap
Principle analysis:
- When how is SIG_ _BLOCK, the function will calculate a new blocking bitmap according to the set, the way is:
- block(new) = block(old) | set; The new block bitmap and the old block bitmap are bitwise ORed.
- When how is SIG_ _UNBLOCK, the function will calculate a new blocking bitmap according to the set, the way is:
- block(new) = block(old) & (^ 'set); first invert the incoming new bitmap, and then perform a bitwise AND operation with the old bitmap
- When how is SIG_SETMASK, the function will calculate a new blocking bitmap according to set in the following way:
- block (new) = set;
Test code:
We call the sigprocmask function and want to set the bit position corresponding to signal No. 2 in the set bitmap to 1
In order to implement the code, we must first know some functions of set
At this time, the blocking setting is indeed verified, but it is not verified that the blocking does not affect the registration of the signal, so the code needs to be modified again
Now let's verify that blocking does not affect the registration of signals, and reliable signals will not lose signals, and unreliable signals will lose signals
Ideas:
code:
Let's run it and observe the result:
It can be seen that reliable signals will not be lost, but unreliable signals can be lost
11. Cooperate with the signal to solve the zombie process:
Before we solve the zombie process, we can only call the wait function or the waitpid function, but there is a problem when calling these two functions, that is, when calling,
Either the parent process is always blocked waiting for the child process to exit, or it has to be used in conjunction with the non-blocking state of loop and waitpid.
Our parent process can't do anything. Here we can use signals to recycle the child process.
Let's look at this code
Let's run the code:
We can see that the signal can be received and the parent process is released from wait
12. volatile keyword:
- effect:
- Guaranteed memory visibility
- The data to be calculated by the CPU is obtained from the memory every time, and the program optimized at compile time (obtained from the registers) is rejected. The compilation options of gcc/gt+ "-00, 01, -02, -03, the optimization level is getting more and more High. (Understanding the higher the optimization level, the faster the program may execute) The higher the optimization level, the greater the possibility of taking values from registers
Let's write a code to experiment
We run and find that press ctrl+c to input signal No. 2 to the process, and the process ends directly. This is because we did not optimize the program when compiling , and it is taken from the memory at this time.
We optimize to O3 level
At this time, we press Ctrl again, and we can find that there is no exit, indicating that the value is not taken from the memory, but directly from the register.
But when we give another volatile keyword, even if we optimize it, we still get the value from the memory