linux 进程调度学习笔记

https://zhuanlan.zhihu.com/p/1248579228

吐血整理 | 肝翻 Linux 进程调度所有知识点

(一)Linux进程调度器-基础_学习笔记 - Hello-World3 - 博客园

Linux CFS调度器之唤醒抢占--Linux进程的管理与调度(三十) - yooooooo - 博客园

调度时刻

调度的本质就是选择下一个进程,然后切换。在执行调度之前需要设置调度标记 TIF_NEED_RESCHED,然后在调度的时候会判断当前进程有没有被设置 TIF_NEED_RESCHED,如果设置则调用函数 schedule 来进行调度。

1. 设置调度标记

为 CPU 上正在运行的进程 thread_info 结构体里的 flags 成员设置 TIF_NEED_RESCHED。

那么,什么时候设置TIF_NEED_RESCHED呢 ?

1.scheduler_tick 时钟中断

2.wake_up_process 唤醒进程的时候

3.do_fork 创建新进程的时候

4.set_user_nice 修改进程nice值的时候

5.smp_send_reschedule 负载均衡的时候

    

task_fork_fair函数:

 /*  如果设置了sysctl_sched_child_runs_first期望se进程先运行
     *  但是se进行的虚拟运行时间却大于当前进程curr
     *  此时我们需要保证se的entity_key小于curr, 才能保证se先运行
     *  内核此处是通过swap(curr, se)的虚拟运行时间来完成的  */
    if (sysctl_sched_child_runs_first && curr && entity_before(curr, se))
    {
        /*
         * Upon rescheduling, sched_class::put_prev_task() will place
         * 'current' within the tree based on its new key value.
         */
        /*  由于curr的vruntime较小, 为了使se先运行, 交换两者的vruntime  */
        swap(curr->vruntime, se->vruntime);
        /*  设置重调度标识, 通知内核在合适的时间进行进程调度  */
        resched_curr(rq);
    }

        使用参数sysctl_sched_child_runs_first控制新建子进程是否应该在父进程之前运行. 这通常是有益的, 特别在子进程随后会执行exec系统调用的情况下. 该参数的默认设置是1, 但可以通过/proc/sys/kernel/sched_child_first修改如果entity_before(curr, se), 则父进程curr的虚拟运行时间vruntime小于子进程se的虚拟运行时间, 即在红黑树中父进程curr更靠左(前), 这就意味着父进程将在子进程之前被调度. 这种情况下如果设置了sysctl_sched_child_runs_first标识, 这时候我们必须采取策略保证子进程先运行, 可以通过交换curlr和se的vruntime值, 来保证se进程(子进程)的vruntime小于curr.

2.执行调度

Kernel 判断当前进程标记是否为 TIF_NEED_RESCHED,是的话调用 schedule 函数,执行调度,切换上下文,这也是上面抢占(preempt)机制的本质。那么在哪些情况下会执行 schedule 呢?

  1. 用户态抢占

ret_to_user 是异常触发,系统调用,中断处理完成后都会调用的函数。

el0_sync 是 ARM 架构中处理来自 EL0(用户模式)同步异常的入口点。同步异常是指那些在执行特定指令时立即触发的异常,而不是由外部事件(如中断)引起的异常。同步异常的例子包括软件中断(SWI/SVC)、未定义指令、预取中止和数据中止等。

图片

  1. 内核态抢占

 el1_irq 是 ARMv8-A 架构中处理来自 EL1(内核模式)的中断(IRQ)的异常处理入口

图片

可以看出无论是用户态抢占,还是内核态抢占,最终都会调用 schedule 函数来执行真正的调度:

图片

上一篇:Spring Boot编程训练系统:前端与后端集成


下一篇:labview连接sql server数据库