进程调度之优先级详解...

This commit is contained in:
gatieme
2016-06-18 20:11:14 +08:00
parent 3444ff35c0
commit ffee574ab4
4 changed files with 1158 additions and 16 deletions
@@ -144,6 +144,8 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进
| 0——99 | 实时进程 |
| 100——139 | 非实时进程 |
![内核的优先级标度](./images/priority.jpg)
优先级数值通过宏来定义, 如下所示, 其中MAX_RT_PRIO指定了实时进程的最大优先级, 而MAX_PRIO则是普通进程的最大优先级数值
@@ -425,7 +427,7 @@ static int effective_prio(struct task_struct *p)
* 设置进程的普通优先级(实时进程99-rt_priority, 普通进程为static_priority)
* 计算进程的动态优先级(实时进程则维持动态优先级的prio不变, 普通进程普通优先级即为动态优先级)
* 计算进程的动态优先级(实时进程则维持动态优先级的prio不变, 普通进程的动态优先级即为其普通优先级)
最后, 我们综述一下在针对不同类型进程的计算结果
@@ -457,47 +459,81 @@ policy == SCHED_FIFO || policy == SCHED_RR;
对于临时提高至实时优先级的非实时进程来说, 这个是必要的, 这种情况可能发生在是哦那个实时互斥量(RT-Mutex)时.
##设置prio的时机
-------
在新进程用wake_up_new_task唤醒时, 或者使用nice系统调用改变其静态优先级时, 则会通过effective_prio的方法设置p->prio
* 在新进程用wake_up_new_task唤醒时, 或者使用nice系统调用改变其静态优先级时, 则会通过effective_prio的方法设置p->prio
>wake_up_new_task(), 计算此进程的优先级和其他调度参数,将新的进程加入到进程调度队列并设此进程为可被调度的,以后这个进程可以被进程调度模块调度执行。
* 进程创建时copy_process通过调用sched_fork来初始化和设置调度器的过程中会设置子进程的优先级
##nice系统调用的实现
-------
nice系统调用是的内核实现是sys_nice, 其定义在[kernel/sched/core.c#L7498](http://lxr.free-electrons.com/source/kernel/sched/core.c?v=4.6#L7498),
它在通过一系列检测后, 通过[set_user_nice函数](http://lxr.free-electrons.com/source/kernel/sched/core.c?v=4.6#L3497), 其定义在[kernel/sched/core.c#L3497](http://lxr.free-electrons.com/source/kernel/sched/core.c?v=4.6#L3497)
关于其具体实现我们会在另外一篇博客里面详细讲
##fork时优先级的继承
-------
在进程分叉处子进程时, 子进程的静态优先级继承自父进程. 子进程的动态优先级p->prio则被设置为父进程的普通优先级, 这确保了实时互斥量引起的优先级提高不会传递到子进程.
可以参照sched_fork函数, 在进程复制的过程中copy_process通过调用sched_fork来设置子进程优先级, 参见[sched_fork函数](http://lxr.free-electrons.com/source/kernel/sched/core.c#L2236)
```c
/*
* fork()/clone()-time setup:
*/
int sched_fork(unsigned long clone_flags, struct task_struct *p)
{
/* ...... */
/*
* Make sure we do not leak PI boosting priority to the child.
* 子进程的动态优先级被设置为父进程普通优先级
*/
p->prio = current->normal_prio; /* 子进程的动态优先级被设置为父普通优先级 */
p->prio = current->normal_prio;
/*
* Revert to default priority/policy on fork if requested.
*/
if (unlikely(p->sched_reset_on_fork)) {
if (task_has_dl_policy(p) || task_has_rt_policy(p)) {
p->policy = SCHED_NORMAL;
p->static_prio = NICE_TO_PRIO(0);
p->rt_priority = 0;
} else if (PRIO_TO_NICE(p->static_prio) < 0)
p->static_prio = NICE_TO_PRIO(0);
* sched_reset_on_fork标识用于判断是否恢复默认的优先级或调度策略
p->prio = p->normal_prio = __normal_prio(p);
*/
if (unlikely(p->sched_reset_on_fork)) /* 如果要恢复默认的调度策略, 即SCHED_NORMAL */
{
/* 首先是设置静态优先级static_prio
* 由于要恢复默认的调度策略
* 对于父进程是实时进程的情况, 静态优先级就设置为DEFAULT_PRIO
*
* 对于父进程是非实时进程的情况, 要保证子进程优先级不小于DEFAULT_PRIO
* 父进程nice < 0即static_prio < 的重新设置为DEFAULT_PRIO的重新设置为DEFAULT_PRIO
* 父进程nice > 0的时候, 则什么也没做
* */
if (task_has_dl_policy(p) || task_has_rt_policy(p))
{
p->policy = SCHED_NORMAL; /* 普通进程调度策略 */
p->static_prio = NICE_TO_PRIO(0); /* 静态优先级为nice = 0 即DEFAULT_PRIO*/
p->rt_priority = 0; /* 实时优先级为0 */
}
else if (PRIO_TO_NICE(p->static_prio) < 0) /* */
p->static_prio = NICE_TO_PRIO(0); /* */
/* 接着就通过__normal_prio设置其普通优先级和动态优先级
* 这里做了一个优化, 因为用sched_reset_on_fork标识设置恢复默认调度策略后
* 创建的子进程是是SCHED_NORMAL的非实时进程
* 因此就不需要绕一大圈用effective_prio设置normal_prio和prio了
* 直接用__normal_prio设置就可 */
p->prio = p->normal_prio = __normal_prio(p); /* 设置*/
/* 设置负荷权重 */
set_load_weight(p);
/*
@@ -506,8 +542,12 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
*/
p->sched_reset_on_fork = 0;
}
}`
``
/* ...... */
}
```
http://blog.sina.com.cn/s/blog_9ca3f6e70102wkwp.html
http://lxr.free-electrons.com/source/kernel/sched/core.c#L3527
http://blog.chinaunix.net/uid-20671208-id-4909620.html
http://blog.chinaunix.net/uid-20671208-id-4909623.html
http://www.linuxidc.com/Linux/2016-05/131244.htm
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff