Analysis on sleep and wakeup of Linux Processes

Source: Internet
Author: User


1. Linux processes sleep and wake up in Linux. processes that only wait for CPU time are called ready processes, which are placed in a running queue, the status flag of a ready process is TASK_RUNNING. Once a running process runs out of time slices, the scheduler in the Linux Kernel 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 www.2cto.com Linux, there are two types of process sleep states:
One is the resumable sleep status, which indicates TASK_INTERRUPTIBLE; the other is the non-disruptive sleep status, which indicates 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, cannot be interrupted until a specific event occurs. In modern Linux operating systems, a process generally enters sleep state by calling schedule (). The following Code demonstrates how to sleep a running process. 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 that points to the process structure being executed. 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); www.2cto.com after wake_up_process () is called, the status of the sleep process is set to TASK_RUNNING, And the scheduler adds 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 ineffective wake-up 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. If it is not empty, perform some operations on the data in the linked list, 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: A 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} 89/* 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); www.2cto.com 103 wake_up_process (processa_task); a problem occurs here, if process A runs before 3rd rows and 4th rows, process B is scheduled to run by another processor. 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. How to Avoid invalid wakeup? We found that the failed wake-up mainly occurs after the check condition and before the Process status is set to sleep. The wake_up_process () of the B process provided an opportunity to set the Process status to TASK_RUNNING, unfortunately, the status of process A is still TASK_RUNNING at this time, so the attempt of wake_up_process () 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 items must be eliminated, so that the wake_up_process () that appears after this 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.
A 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); 910/* Rest of the code... */11 spin_unlock (& list_lock); you can see that this Code sets the status of the current execution process to TASK_INTERRUPTIBLE before the test conditions, when the linked list is not empty, it sets itself to TASK_RUNNING. In this way, if process B calls wake_up_process () after process A checks that the linked list is empty, the status of process A is automatically changed from TASK_INTERRUPTIBLE to TASK_RUNNING, after that, even if the process calls schedule () again, because the current status is TASK_RUNNING, it will not be removed from the running queue, so it will not mistakenly go to sleep, of course, this avoids the invalid wake-up problem. 4 Linux kernel example in Linux, kernel stability is crucial. To avoid the problem of invalid wake-up in Linux kernel, the Linux kernel should use the following operations when the process needs to be sleep:/* '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 (); www.2cto.com set_current_state (TASK_RUNNING); remove_wait_queue (q, & wait); the operation above, the process securely adds itself to a waiting queue for sleep using the following steps: first call DECLARE_WAITQUEUE () to create a waiting queue item, and then call add_wait_queue () 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.
As you can see from the above, the Linux kernel code maintainer also sets the Process status to sleep before the process check conditions, and then cyclically checks the conditions. 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 us use linux kernel instances to see how the Linux kernel is to avoid invalid sleep, this code 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 schedule (); 4257 set_current_state (TASK_INTERRUPTIBLE); 4258} 4259 _ set_current_state (TASK_RUNNING); 4260 return 0; the code above www.2cto.com belongs to the migration service thread migration_thread, which constantly checks kthread_should_stop () and exits the loop until kthread_should_stop () returns 1, that is, as long as kthread_should_stop () if the return value is 0, the process will remain asleep. 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. Through the above discussion, we can find that in Linux, the key to avoiding invalid processes is to set the process status to TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE before the process check conditions, if the check conditions are met, set the status to TASK_RUNNING again. 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. Author chumojing

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.