注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

FY

Johnson 's Blog

 
 
 

日志

 
 

Linux 2.4.0 多CPU的SMP中进程调度  

2017-01-03 14:17:47|  分类: Linux内核 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

每次schedule中,从switch_to“返回”后,要进行schedule_tail(prev)

Prev代表当前进程之前那个进程,代表当前进程从哪个进程被调度过来的。

函数schedule_tail

prev->has_cpu = 0;

       mb();

       if (prev->state == TASK_RUNNING)

              goto needs_resched;

首先将prevhas_cpu0,让它可以继续允许有资格被调度。

如果prev的状态还是TASK_RUNNING,说明prev这个进程是被强制调度的

可能是时间片消耗完了。但不管怎么说prev的本意或是意愿还是想继续RUNNING的。于是我们跳往needs_reshced,来看看能不能为这个prev找另一个CPU上去继续让它RUN下去。

needs_resched:

       {

              if ((prev == idle_task(smp_processor_id())) ||

                                          (policy & SCHED_YIELD))

                     goto out_unlock;

首先如果prev是一个idle进程,或者这个prev虽然意愿是RUNING,但它自己通过系统调用让自己YIELD(礼让)了,这种情况下我们就直接退出了。

否则就要通过reschedule_idle来看看能不能为prev重新调度在其他CPU

if (prev->state == TASK_RUNNING)

                     reschedule_idle(prev);

reschedule_idle函数:

遍历所有CPU,找到CPU上合适的对象进程,把这个对象进程的need_resched设为1,想将它调度出去。哪些是可以作为对象进程的呢,

1) 其他CPU中如果有某个CPU是正跑在一个它自己的idle进程,那这个CPU的这个idle进程肯定可以作为对象进程。

2) 其他CPU上虽然都在跑着进程,但是这些进程中存在goodness,就是优先度比prev来的低的,我们从这些低优先度中选取一个最低的,我们可以让这个最低的进程在它运行的那个CPU上被调度出去,好让那个CPU能找到能看到prev这个比较高优先度的进程,从而prev能够在那个CPU上被继续RUN

方法是,将这个最低等级的对象进程的need_reshced设为1,然后向它所在的CPU发送一个中断。

所以从SMP启动开始, CPU和所有次CPU都在运行各自的idle进程,主CPU发现自己的idle进程need_reched=1,所以调度到initPID=1)进程,然后如果init继续调度进程A,那进程A会在主CPU上运行,但init进程并不代表就不再继续运行了,别忘了我们是多CPUSMP结构,这时在进入进程A后,它调用

schedule_tail à reschedule_idle, 发现次CPU都在跑各自的idle进程,所以就找到了对象进程:某个次CPUidle进程,将它的need_resched设为1

tsk->need_resched = 1; 然后向这个次CPU发送中断:RESCHEDULE_VECTOR

此时这个次CPU其实是处于真正硬件睡眠的,它收到中断被唤醒,并且重新跑一遍 cpu_idle中的while循环,发现当前进程(idle进程)need_resched=1,于是它调用schedule,它schedule中发现了init这个状态是RUNNING,但has_cpu=0的进程,那就调度它了。结果发现init进程在主CPU上执行调度,主CPU接着运行进程A了,但进程A接下来会马上调用schedule_tail à reschedule_idle,它“想办法init进程移师到了另一个次CPU上继续运行了。

void cpu_idle (void)

{

       /* endless idle loop with no priority at all */

       init_idle();

       current->nice = 20;

       current->counter = -100;

 

       while (1) {

              void (*idle)(void) = pm_idle;

              if (!idle)

                     idle = default_idle;

              while (!current->need_resched)

                     idle();//进入硬件睡眠

               //RESCHEDULE_VECTOR中断唤醒,接着往下执行schedule

              schedule();

它次CPU上开始执行schedule,找到了init进程,将它的has_cpu=1,并且它的processor设定为次CPU的号,然后init进程就在次CPU上执行了。于是变成了:

CPU执行进程A,次CPU执行init进程这样的情况。

以上是SMP的场合,如果是单CPU的情况下,那我们只要判断当前CPU运行的进程,它的goodness是否比prev低,如果低,则将当前运行的进程的need_reshced设为1,把它调度出去。但是注意,在schedule_tail中,针对单CPU场合是不会调用reschedule_idle的。

在单CPU上,只有一种情况会调用reschedule_idle,那就是wake_up某个进程,将这个进程状态设为RUNNING,挂入就绪队列runqueue,然后调用reschedule_idle

因为如果被唤醒的进程的优先度比当前正在运行的进程高,则当前进程会被调度出去。这也是为什么谈到强制调度时说到有2种情况,一种是时钟中断发现进程的时间片消耗到了,另一种就是这里,本身进程的时间片还没有消耗完,但是它向另一个处在睡眠状态的进程X发送了信号,把它唤醒,如果被唤醒的这个进程比它有更高的goodness,那本身这个进程就会被强制调度了。

inline void wake_up_process(struct task_struct * p)

{

 

       spin_lock_irqsave(&runqueue_lock, flags);

       p->state = TASK_RUNNING;

       if (task_on_runqueue(p))

              goto out;

       add_to_runqueue(p);

       reschedule_idle(p);

  评论这张
 
阅读(5)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017