Linux Kernel source code scenario analysis-Mandatory scheduling

Source: Internet
Author: User
Tags goto prev

The mandatory scheduling of processes in the Linux kernel, i.e. involuntary, passive, and stripped-down scheduling, is mainly caused by time. As mentioned earlier, this scheduling occurs on the eve of a break, an exception, a system call returning from the system space to the user space, that is, in ret_with_reschedule, whether the call to schedule () is true at this point, and ultimately depends on the current process task_ The need_resched in a struct structure is 1 (not 0), so the problem is that the need_resched of the current process is under what circumstances it is set to 1. There are several main cases:

1. In a service program with clock interruption, it is found that the current process (continuous) has been running for a long time.

2. The process of waking up a sleep is to discover that the process being awakened is more qualified to run than the current process.

3, a process through the system call to change the scheduling policy or comity. This situation should actually be considered an active, voluntary dispatch, so such a system call would cause immediate dispatch.


In the first case, in the Linux kernel source scenario analysis-interrupt upper half of the article, the Do_timer Interrupt service program, called the Update_process_times, the code is as follows:

void update_process_times (int user_tick) {struct Task_struct *p = current;int CPU = smp_processor_id (), System = User_tick ^ 1;update_one_process (p, User_tick, System, CPU); if (p->pid) {if (--p->counter <= 0) {p->counter = 0;p->ne ed_resched = 1;//Forced dispatch}if (P->nice > 0) kstat.per_cpu_nice[cpu] + = user_tick;elsekstat.per_cpu_user[cpu] + = User_ TICK;KSTAT.PER_CPU_SYSTEM[CPU] + = system;} else if (Local_bh_count (CPU) | | local_irq_count (CPU) > 1) kstat.per_cpu_system[cpu] + = System;
If at this time in the user state interrupt, enter the kernel state, P->counter minus 0, then the p->need_resched is set to 1, the interrupt will be forced to return the dispatch.

If a system call occurs at this point, the kernel state, and then the interrupt, P->counter minus 0, then the p->need_resched is set to 1, the interrupt is returned, and then the system call will be forced to dispatch.

If there is an exception in the user state at this time, enter the kernel state, and then interrupt, P->counter minus 0, then the p->need_resched is set to 1, when the interrupt is returned, the dispatch is forced when the exception returns.


In the second case, when a process is awakened, the code is as follows:

inline void wake_up_process (struct task_struct * p) {unsigned long flags;/* * We want the common case fall through straight , thus the Goto. */spin_lock_irqsave (&runqueue_lock, flags);p->state = task_running;//The status of the process is set to Task_runningif (Task_on_ Runqueue (p)) goto Out;add_to_runqueue (P);//Attach process to Runqueuereschedule_idle (p); Out:spin_unlock_irqrestore (& Runqueue_lock, flags);}

static void Reschedule_idle (struct task_struct * p) {        ... int this_cpu = smp_processor_id (); struct task_struct *tsk ; tsk = Cpu_curr (THIS_CPU);//Gets the TASK_STRUCT data structure of the current process if (Preemption_goodness (tsk, p, this_cpu) > 1)// Compare the combined weights of the current process and the awakened process tsk->need_resched = 1;//If the synthesized weight of the process being awakened is larger than the current process, then force scheduling}
static inline int preemption_goodness (struct task_struct * prev, struct task_struct * p, int cpu) {return goodness (p, CPU, PREV->ACTIVE_MM)-Goodness (prev, CPU, prev->active_mm);}
If a system call occurs and the kernel state is entered, the above procedure occurs, and the dispatch is forced when the system call returns.

If an exception occurs in the user state and enters the kernel state, the above procedure occurs, and the schedule is forced when the exception returns.

If the user state has been interrupted, enter the kernel state, cannot call wake_up_process.


In the case of a third situation, it should be considered a voluntary surrender. However, from the form of kernel code, it is also the same way, the current process of the NEED_RESCHED flag is set to 1, so that the process returned to the user space on the eve of scheduling, so also put in this section. There are two of such system calls, one is Sched_setscheduler () and the other is Sched_yield ().

The function of system call Sched_setscheduler () is to change the scheduling policy of the process. After the user logs on to the system, the applicable scheduling policy for the first process is Sched_other, which is the default for interactive applications without real-time requirements. When fork () creates a new process, it inherits the scheduling policy that the process applies to the child process. However, the user can change the applicable scheduling policy through system call Sched_setscheduler ().

Sched_setscheduler, the code for the kernel state is as follows:

asmlinkage Long Sys_sched_setscheduler (pid_t pid, int policy, struct Sched_param *param) {return Setscheduler (PID, Policy, param );} Asmlinkage long Sys_sched_setparam (pid_t pid, struct Sched_param *param) {return Setscheduler (PID,-1, param);} 
static int Setscheduler (pid_t pid, int policy, struct Sched_param *param) {struct Sched_param lp;struct task_struct *p;int Retval;retval =-einval;if (!param | | pid < 0) Goto Out_nounlock;retval =-efault;if (Copy_from_user (&AMP;LP, param, siz EOF (struct Sched_param))//Copy the SCHED_PARAM structure from user space to the Lpgoto out_nounlock;/* * We play safe to avoid deadlocks. */READ_LOCK_IRQ (&tasklist_lock), Spin_lock (&runqueue_lock);p = Find_process_by_pid (PID);//PID Find Task_ Structretval =-esrch;if (!p) goto out_unlock;if (Policy < 0)//policy for -1policy = p->policy;//maintain the original policy else {retval =-E INVAL;IF (Policy! = Sched_fifo && Policy! = SCHED_RR &&policy! = sched_other)//must be one of these three policies Goto out_unlock; }/* * Valid priorities for SCHED_FIFO and SCHED_RR am 1..99, Valid * priority for Sched_other is 0. */retval =-einval;if (lp.sched_priority < 0 | | lp.sched_priority >) goto out_unlock;if (Policy = = Sched_other)! = (Lp.sched_priority = = 0))//If the policy is sched_other,sched_priority must be 0goto Out_uNlock;retval =-eperm;if (Policy = = Sched_fifo | | policy = = SCHED_RR) &&!capable (cap_sys_nice)) Goto Out_unlo Ck;if ((Current->euid! = p->euid) && (current->euid! = p->uid) &&!capable (cap_sys_nice)) go to Out_unlock;retval = 0;p->policy = Policy;p->rt_priority = Lp.sched_priority;if (Task_on_runqueue (p)) move_ First_runqueue (P);//move from the current position of the executable process queue to the front of the queue so that it is in a more advantageous position at the time of dispatch current->need_resched = 1;//forced dispatch out_unlock:spin_ Unlock (&runqueue_lock); Read_unlock_irq (&tasklist_lock); Out_nounlock:return retval;}


Another system calls Sched_yield () so that the running process can "give way" to other processes, but does not go to sleep. The implementation of the kernel Sys_sched_yield, the code is as follows:
Asmlinkage long Sys_sched_yield (void) {/* * Trick. Sched_yield () First counts the number of truly  * ' pending ' runnable Processes, then returns if it ' s * is only the current processes. (This test does not has * to is atomic.) In threaded applications This optimization * gets triggered quite often.  */int nr_pending = nr_running; #if config_smpint i;//substract non-idle processes running on other cpus.for (i = 0; i < Smp_num_cpus; i++) if (Aligned_data[i].schedule_data.curr! = Idle_task (i)) nr_pending--; #else//On the "This" process is on the Runqueue as W ellnr_pending--; #endifif (nr_pending) {//The number of running processes that are waiting */* * This process can only being rescheduled by us, * so the is safe wit Hout any locking. */if (Current->policy = = sched_other) current->policy |= Sched_yield;//sched_yield flag position 1, in _schedule_ Tail 0current->need_resched = 1;//forced dispatch}return 0;}


The third case, only occurs, uses theSched_setscheduler () or Sched_yield () system calls, the system call forces the dispatch when it returns.

Linux Kernel source code scenario analysis-Mandatory scheduling

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.