Sleep and wakeup of Linux Processes

Source: Internet
Author: User

1. Sleep and wakeup of Linux Processes
In Linux, processes that only wait for CPU time are called ready processes. They are placed in a running queue, and the status flag of a ready process is task_running. Once a running process runs out of time slices, the Linux kernel scheduler will deprive the process of control over the CPU and select a suitable process from the running queue for running.
Of course, a process can also take the initiative to release control of the CPU. The schedule () function is a scheduling function that can be actively called by a process to schedule other processes to occupy the CPU. Once the process that voluntarily gave up the CPU is rescheduled to occupy the CPU, it will start to run from the last stop, that is, it will call schedule () the execution starts at the next line of code.
Sometimes, the process needs to wait until a specific event occurs, such as the device Initialization is complete, the I/O operation is complete, or the timer is reached. In this case, the process must be removed from the running queue and added to a waiting queue. At this time, the process enters the sleep state.
In LinuxProcess sleepThere are two States: one is an interrupted sleep state, and its status indicates task_interruptible;
The other is an uninterrupted sleep state with the status flag task_uninterruptible. An interrupted sleep process will sleep until a certain condition changes to true. For example, a hardware interruption, a system resource waiting for the process to be released, or a signal can be sent to wake up the process. The non-disruptive sleep state is similar to that of the interruptible sleep state. However, an exception is that a process that transmits signals to this sleep state cannot change its state, that is to say, it does not respond to the wake-up of signals. Non-disruptive sleep is generally rarely used, but in some specific situations this status is still very useful. For example, the process must wait and cannot be interrupted until a specific event occurs.
In the modern Linux operating system, the process generally uses the method of calling schedule () to enter the sleep state. The following code shows
Shows how to make a running process sleep.
Sleeping_task = current;
Set_current_state (task_interruptible );
Schedule ();
Func1 ();
/* Rest of the code ...*/
In the first statement, the program stores a process structure pointer sleeping_task, and current is a macro, which points to the execution
Process structure. Set_current_state () changes the status of the process from execution status task_running to sleep status.
Task_interruptible. If schedule () is scheduled by a process in the task_running state, schedule () will schedule another process to occupy the CPU; If schedule () is scheduled by a process in the status of task_interruptible or task_uninterruptible. Then, an additional step will be executed: the currently executed process will be removed from the running queue before another process is scheduled. This will cause the running process to sleep because it is no longer in the running queue.
We can use the following function to wake up the sleep process.
Wake_up_process (sleeping_task );
After wake_up_process () is called, the status of the sleep process is set to task_running, And the Scheduler
Will add it to the running queue. Of course, this process can be truly put into operation only when it is scheduled by the scheduler next time.
2. Invalid Wakeup
In almost all cases, the process will go to sleep after checking certain conditions and finds that the conditions are not met. However, sometimes
The process will start to sleep after determining that the condition is true. If so, the process will sleep indefinitely. This is the so-called invalid wake-up problem. In the operating system, when multiple processes attempt to process shared data in a certain way, and the final result depends on the order in which the process runs, competition conditions will occur, this is a typical problem in the operating system. Failure to wake up is precisely due to competition conditions.
Suppose there are two processes A and B. process a is processing a linked list. It needs to check whether the linked list is empty.
The data in the table is operated, and process B is also adding nodes to the linked list. When the linked list is empty, process a goes to sleep due to no data operation. After process B adds a node to the linked list, process a is awakened. The Code is as follows:
Process:
1 spin_lock (& list_lock );
2 If (list_empty (& list_head )){
3 spin_unlock (& list_lock );
4 set_current_state (task_interruptible );
5 schedule ();
6 spin_lock (& list_lock );
7}
8
9/* rest of the code ...*/
10 spin_unlock (& list_lock );
Process B:
100 spin_lock (& list_lock );
101 list_add_tail (& list_head, new_node );
102 spin_unlock (& list_lock );
103 wake_up_process (processa_task );
A problem occurs here. If process a runs before 3rd rows after 4th rows, process B is scheduled by another processor.
Put into operation. In this time slice, process B executes all its commands, so it tries to wake up process A. At this time, process A is not sleep, so the wake-up operation is invalid. After that, process a continues to execute. It mistakenly deems that the linked list is still empty at this time, so it sets its status to task_interruptible and calls schedule () to sleep. If the wake-up of process B is missed, it will sleep indefinitely. This is an invalid wake-up problem, because process a still sleeps even if there is data in the linked list to be processed.
3. Avoid invalid Wakeup
How can we avoid invalid wake-up problems? We found that the failed wake-up mainly occurs after the condition check and the Process status is set to sleep.
Previously, the wake_up_process () of the B process provided an opportunity to set the status of process a to task_running. Unfortunately, the status of process A is still task_running, so the wake_up_process () the attempt to change the status of process a from sleep to running does not play the expected role. To solve this problem, we must use a safeguard mechanism to make it an inseparable step to judge whether the linked list is empty and set the process status to sleep, that is to say, the root cause of competition conditions must be eliminated, so that the wake-up process that appears later can wake up the process in sleep state.
After finding the cause, re-design the code structure of process a to avoid the problem of invalid wake-up in the above example.
Process:
1 set_current_state (task_interruptible );
2 spin_lock (& list_lock );
3 if (list_empty (& list_head )){
4 spin_unlock (& list_lock );
5 schedule ();
6 spin_lock (& list_lock );
7}
8 set_current_state (task_running );
9
10/* rest of the code ...*/
11 spin_unlock (& list_lock );
As you can see, this Code sets the status of the current execution process to task_interruptible before the test conditions, and sets itself to task_running state when the linked list is not empty. In this way, if process B checks the process of process
If the linked list is empty, call wake_up_process (). Then the status of process a is automatically changed from task_interruptible.
It becomes task_running. After that, even if the process calls schedule () Again, it will not be removed from the running queue because its current status is task_running, so it will not mistakenly go to sleep, of course, this avoids the invalid wake-up problem.
4 Linux kernel example
In the Linux operating system, kernel stability is crucial. In order to avoid the problem of invalid wake-up in the Linux operating system kernel,
Linux Kernel is requiredProcess sleepYou should use the following operations:
/* 'Q' is the waiting queue we want to sleep */
Declare_waitqueue (wait, current );
Add_wait_queue (Q, & wait );
Set_current_state (task_interruptible );
/* Or task_interruptible */
While (! Condition)/* 'condition' is the waiting condition */
Schedule ();
Set_current_state (task_running );
Remove_wait_queue (Q, & wait );
The preceding operations enable the process to safely add itself to a waiting queue through the following steps:
Use declare_waitqueue () to create a waiting queue item, call add_wait_queue () to add yourself to the waiting queue, and set the process status to task_interruptible or task_interruptible. Then check whether the condition is true cyclically: If yes, there is no need to sleep. If the condition is not true, schedule () is called (). After the conditions of the process check are met, the process sets itself as task_running and calls remove_wait_queue () to remove itself from the waiting queue.
We can see from the above that the Linux kernel code maintainer also sets the Process status to sleep before the process check conditions,
Then the condition is checked cyclically. If the condition is reached before the process starts to sleep, the loop exits and uses set_current_state () to set its status to ready, this also ensures that the process will not have a wrong tendency to enter the sleep, of course, it will not lead to invalid wake-up problems.
Next let's take a look at the Linux kernel with an instance in the Linux kernel to see how it can avoid sleep ineffective, this code comes from the Linux 2.6 kernel (linux-2.6.11/kernel/sched. C: 4254 ):
4253/* Wait For kthread_stop */
4254 set_current_state (task_interruptible );
4255 while (! Kthread_should_stop ()){
4256 maid ();
4257 set_current_state (task_interruptible );
4258}
4259 _ set_current_state (task_running );
4260 return 0;
The above code belongs to the migration service thread migration_thread, which constantly checks kthread_should_stop (),
It can exit the loop until kthread_should_stop () returns 1, that is, as long as kthread_should_stop () returns 0, the process will continue to sleep. From the code, we can see that the check kthread_should_stop () is indeed executed after the Process status is set to task_interruptible. Therefore, if another process tries to wake it up after the condition check but before schedule (), the wake-up operation of the process will not expire.
Summary
Through the above discussion, we can find that in Linux, the key to avoiding invalid wake-up of processes is to set the process before the process checks the conditions.
The status is set to task_interruptible or task_uninterruptible, and should be
Set its status to task_running. In this way, no matter whether the waiting conditions of the process are met, the process will not mistakenly enter the sleep state because it is removed from the ready queue, thus avoiding invalid wake-up problems.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.