Chinaunix

标题: 想不明白的一个进程调度问题 [打印本页]

作者: yifei429    时间: 2011-12-08 15:18
标题: 想不明白的一个进程调度问题
内核中经常有set_current_state(TASK_INTERRUPTIBLE);这段代码,并且还没有放入唤醒队列中(例如2.6.18中的do_poll函数),当执行完这段代码之后:
1.此时刚好时间片到期,那此进程是不是永远不会执行了?
2.此事发生抢占,会出现什么情况?

另外,内核中有preempt_schedule函数,这个函数中
                add_preempt_count_notrace(PREEMPT_ACTIVE);
                schedule();
                sub_preempt_count_notrace(PREEMPT_ACTIVE);
当schedule返回后,进程已经切换,此时 sub_preempt_count_notrace的是另一个进程的preempt???
作者: mihouge    时间: 2011-12-08 16:23
内核中经常有set_current_state(TASK_INTERRUPTIBLE);这段代码,并且还没有放入唤醒队列中(例如2.6.18中的do_poll函数),当执行完这段代码之后:
1.此时刚好时间片到期,那此进程是不是永远不会执行了?
2.此事发生抢占,会出现什么情况?

另外,内核中有preempt_schedule函数,这个函数中
                add_preempt_count_notrace(PREEMPT_ACTIVE);
                schedule();
                sub_preempt_count_notrace(PREEMPT_ACTIVE);
当schedule返回后,进程已经切换,此时 sub_preempt_count_notrace的是另一个进程的preempt???

1.第一个问题不怎么懂,但你的看了你的列子
          poll_initwait(&table);
        fdcount = do_poll(nfds, head, &table, end_time);
        poll_freewait(&table);
应该和do_poll的前后两个函数有关。
2.这个首先应该不是 “sub_preempt_count_notrace的是另一个进程的preempt”   当schedule()返回后,仍然在原进程中。
preempt_active在内核里解释的很清楚,当进行内核抢占时的标志。

作者: yifei429    时间: 2011-12-08 16:39
本帖最后由 yifei429 于 2011-12-08 16:44 编辑

回复 2# mihouge
1. 第一个问题我想问的是时间片到了之后会设置set_tsk_need_resched;但此时进程状态不是running,还会被调度回来么?
函数schedule中有
if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
..........
deactivate_task(rq, prev, DEQUEUE_SLEEP);
}
不就把当前进程踢出去了么?

2. preempt_schedule中,为什么schedule之后还是原进程?那抢占的优先级高的进程没有得到执行?
作者: azzurris    时间: 2011-12-08 16:58
preempt_schedule中,为什么schedule之后还是原进程?那抢占的优先级高的进程没有得到执行?
yifei429 发表于 2011-12-08 16:39



    下班没时间看第一个问题了
第二个问题是这样的
你的进程A先调用add_preempt_count_notrace(PREEMPT_ACTIVE);
然后调用schedule(),该进程A放弃了对CPU的占用,进程A处于运行队列或者休眠队列中。CPU执行别的进程的语句了。
过了一段时间之后,等到再度调度到你的进程A,这时,你的进程A又一次占用到了CPU,就从上次断掉的地方开始执行,也就是开始执行sub_preempt_count_notrace(PREEMPT_ACTIVE);
作者: yifei429    时间: 2011-12-08 17:16
下班没时间看第一个问题了
第二个问题是这样的
你的进程A先调用add_preempt_count_notrace(PRE ...
azzurris 发表于 2011-12-08 16:58



    那也就是说preempt_schedule是在第一个进程中调用的?调用点再第一个进程中?
作者: yifei429    时间: 2011-12-08 17:43
回复 4# azzurris

第一个问题就是问,当一个进程调用set_current_state(TASK_INTERRUPTIBLE);之后,刚好时间片用完,此时会发生什么情况?
时间片用完后,时钟中断会调用schedule吧,此时schedule因为该进程不是running,会不会把该进程踢出去,从而该进程永远不会被执行。
作者: kouu    时间: 2011-12-08 18:46
http://bbs.chinaunix.net/viewthr ... p;extra=&page=2
作者: yifei429    时间: 2011-12-09 10:05
本帖最后由 yifei429 于 2011-12-09 10:08 编辑
kouu 发表于 2011-12-08 18:46

抢占是调度的时候调用的是preempt_schedule(),但如果刚好时间片到了呢?那应该调用的是schedule()吧?此时没有机会设置PREEMPT_ACTIVE?
作者: kouu    时间: 2011-12-09 10:46
什么叫抢占?运行中的进程非自愿的让出CPU就是抢占。时间片到了,显然也是属于非自愿的。进程根本不知道时间片这回事,想着要继续运行呢,但是却被sched了。
所以时间片到,调用的也是preempt_schedule()。

时间片到的流程是这样的:
1、时钟中断触发,软中断里面会更新current的运行时间,并且判断是否应该抢占。如果要抢占,则设置TIF_NEED_RESCHED标记;
2、中断上下文结束的时候,看到TIF_NEED_RESCHED标记,会调用preempt_schedule_irq;
3、preempt_schedule_irq在schedule之前会设置PREEMPT_ACTIVE;
作者: 瀚海书香    时间: 2011-12-09 10:51
回复 1# yifei429
内核中经常有set_current_state(TASK_INTERRUPTIBLE);这段代码,并且还没有放入唤醒队列中(例如2.6.18中的do_poll函数),当执行完这段代码之后:
1.此时刚好时间片到期,那此进程是不是永远不会执行了?
2.此事发生抢占,会出现什么情况?

这个问题的确是可能发生的,但是内核通过一个标志PREEMPT_ACTIVE来防止这种情况的发生。
PREEMPT_ACTIVE的作用:防止已经处于非运行状态的进程还没有加入到相应的队列之前,就被抢占的情况发生。
具体代码在schedule函数中:
  1. asmlinkage void __sched schedule(void)
  2. {
  3.         struct task_struct *prev, *next;
  4.         long *switch_count;
  5.         struct rq *rq;
  6.         int cpu;

  7. need_resched:
  8.         preempt_disable();
  9.         cpu = smp_processor_id();
  10.         rq = cpu_rq(cpu);
  11.         rcu_qsctr_inc(cpu);
  12.         prev = rq->curr;
  13.         switch_count = &prev->nivcsw;

  14.         release_kernel_lock(prev);
  15. need_resched_nonpreemptible:

  16.         schedule_debug(prev);

  17.         /*
  18.          * Do the rq-clock update outside the rq lock:
  19.          */
  20.         local_irq_disable();
  21.         __update_rq_clock(rq);
  22.         spin_lock(&rq->lock);
  23.         clear_tsk_need_resched(prev);

  24.         if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
  25.                 if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&
  26.                                 unlikely(signal_pending(prev)))) {
  27.                         prev->state = TASK_RUNNING;
  28.                 } else {
  29.                         deactivate_task(rq, prev, 1);
  30.                 }
  31.                 switch_count = &prev->nvcsw;
  32.         }

  33.         if (unlikely(!rq->nr_running))
  34.                 idle_balance(cpu, rq);

  35.         prev->sched_class->put_prev_task(rq, prev);
  36.         next = pick_next_task(rq, prev);

  37.         sched_info_switch(prev, next);

  38.         if (likely(prev != next)) {
  39.                 rq->nr_switches++;
  40.                 rq->curr = next;
  41.                 ++*switch_count;

  42.                 context_switch(rq, prev, next); /* unlocks the rq */
  43.         } else
  44.                 spin_unlock_irq(&rq->lock);

  45.         if (unlikely(reacquire_kernel_lock(current) < 0)) {
  46.                 cpu = smp_processor_id();
  47.                 rq = cpu_rq(cpu);
  48.                 goto need_resched_nonpreemptible;
  49.         }
  50.         preempt_enable_no_resched();
  51.         if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
  52.                 goto need_resched;
  53. }
复制代码

作者: yifei429    时间: 2011-12-09 11:07
本帖最后由 yifei429 于 2011-12-09 11:14 编辑
什么叫抢占?运行中的进程非自愿的让出CPU就是抢占。时间片到了,显然也是属于非自愿的。进程根本不知道时间 ...
kouu 发表于 2011-12-09 10:46



也就是说流程为:
1,发生时钟中断
2,中断执行timer_tick:  更新时间片,发现时间片耗尽,设置TIF_NEED_RESCHED标记;
3,中断返回前检查TIF_NEED_RESCHED标记,如果设置则执行preempt_schedule_irq;
明白了,谢谢!

另外那preempt_schedule_irq执行是在中断返回之前么?还是已经从中断中返回到当前进程上下文中?应该是已经返回了吧
因为如果在中断之前,那此时
preempt_schedule_irq(){
                add_preempt_count(PREEMPT_ACTIVE);
                local_irq_enable();
                schedule();
                local_irq_disable();
                sub_preempt_count(PREEMPT_ACTIVE);
}
add_preempt_count增加的和sub_preempt_count之后减少的current进程就不同了吧。
也就是说当前进程自己在被中断返回后首先调用了preempt_schedule_irq()??
作者: azzurris    时间: 2011-12-09 11:35
也就是说流程为:
1,发生时钟中断
2,中断执行timer_tick:  更新时间片,发现时间片耗尽,设置TI ...
yifei429 发表于 2011-12-09 11:07



    中断返回之前调用的preempt_schedule_irq
作者: yifei429    时间: 2011-12-09 11:40
回复 11# yifei429

哦,我理解错了,我的意思是如果中断返回之前调用,那会不会形成中断嵌套?
中断->preempt_schedule_irq->中断返回
而在preempt_schedule_irq之中,还有可能发生中断,那就形成了中断嵌套?
作者: azzurris    时间: 2011-12-09 11:46
回复  yifei429

哦,我理解错了,我的意思是如果中断返回之前调用,那会不会形成中断嵌套?
中断->pre ...
yifei429 发表于 2011-12-09 11:40



/*
* this is the entry point to schedule() from kernel preemption
* off of irq context.
* Note, that this is called and return with irqs disabled. This will
* protect us against recursive calling from irq.
*/
asmlinkage void __sched preempt_schedule_irq(void)
作者: azzurris    时间: 2011-12-09 11:50
也就是说流程为:
1,发生时钟中断
2,中断执行timer_tick:  更新时间片,发现时间片耗尽,设置TI ...
yifei429 发表于 2011-12-09 11:07



preempt_schedule_irq在中断上下文调用的证据如下:
  1. 1:        bl        preempt_schedule_irq                @ irq en/disable is done inside
  2.         ldr        r0, [tsk, #TI_FLAGS]                @ get new tasks TI_FLAGS
  3.         tst        r0, #_TIF_NEED_RESCHED
  4.         beq        preempt_return                        @ go again
  5.         b        1b
复制代码
这里会反复检查NEED_RESCHED标志,直到没有该标志为止,eq条件满足,跳到preempt_return执行,这里会恢复进中断之前的preempt_count,和被中断进程的寄存器与CPSR,只有CPSR被恢复,才能保证系统从中断上下文里退出到内核态。(因为你是执行内核态的__set_current_state(TASK_INTERRUPTIBLE)函数时进中断的)

因此preempt_schedule_irq是在还没有退出中断上下文的时候执行的。
作者: yifei429    时间: 2011-12-09 13:05
preempt_schedule_irq在中断上下文调用的证据如下:这里会反复检查NEED_RESCHED标志,直到没有该标志 ...
azzurris 发表于 2011-12-09 11:50


谢谢。
不过那preempt_schedule_irq调用local_irq_enable();之后是否会再次被中断?
因为preempt_schedule_irq是在中断中返回之前调用的,那再次被中断之后就形成了中断嵌套?
作者: 瀚海书香    时间: 2011-12-09 14:55
回复 16# yifei429
因为preempt_schedule_irq是在中断中返回之前调用的,那再次被中断之后就形成了中断嵌套?

linux是允许中断嵌套的
作者: yifei429    时间: 2011-12-12 10:05
回复  yifei429

linux是允许中断嵌套的
瀚海书香 发表于 2011-12-09 14:55



哦,linux允许中断嵌套么?我记得看过资料不允许,有相关资料的链接么?
作者: embeddedlwp    时间: 2011-12-12 10:11
回复 18# yifei429




建议看看ULK3 第四章
作者: 瀚海书香    时间: 2011-12-12 10:14
回复 18# yifei429
最近刚刚阅读了内核中断部分的代码,所以可以肯定的说,在2.6.24内核中是支持中断嵌套的。
作者: yifei429    时间: 2011-12-12 10:21
回复  yifei429
最近刚刚阅读了内核中断部分的代码,所以可以肯定的说,在2.6.24内核中是支持中断嵌套的。 ...
瀚海书香 发表于 2011-12-12 10:14



谢谢,对那块代码不熟悉,能引用一段过来么?在网上google了一下,都说得不是很明白
作者: yifei429    时间: 2011-12-12 10:24
回复 19# embeddedlwp


    好的,我查一下。
作者: 瀚海书香    时间: 2011-12-12 10:32
回复 21# yifei429
看看这个吧http://bbs.chinaunix.net/thread-3624009-1-1.html
作者: embeddedlwp    时间: 2011-12-12 10:33
回复 23# 瀚海书香


    线上讨论之linux中断总结分享  100楼的问题再帮看看呗,麻烦了!




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2