2019独角兽企业重金招聘Python工程师标准>>>

内核中的调度算法在不断变化,2.4内核中的调度器是在所有的进程中选择优先级最高的进程,2.6内核前期的调度器是基于O(1)算法的,而 2.6.23版本之后的内核采用CFS调度算法,并同时对调度器进行了比较大的改善。内核主要是引入了调度器类来增加调度器的可扩展性。调度器类将各种调 度策略模块化,封装了对不同调度策略的具体实现。

内核中对进程调度的方法有两种,其一为周期性调度器(generic scheduler),它对进行进行周期性的调度,以固定的频率运行;其二为主调度器(main scheduler),如果进程要进行睡眠或因为其他原因主动放弃CPU,那么就直接调用主调度器。

内核的主调度器是通过schedule()实现的,该函数的主要工作就是挑选下一个应该被调度的进程next。
该函数首先禁止内核抢占,并且依次获取当前CPU编号cpu、当前CPU对应的运行队列rq、当前进程的切换次数switch_count以及当前进程的描述符prev。

1 asmlinkage void __sched schedule(void)
2 {
3     struct task_struct *prev, *next;
4     unsigned long *switch_count;
5     struct rq *rq;
6     int cpu;
7  
8 need_resched:
9     preempt_disable();
10     cpu = smp_processor_id();
11     rq = cpu_rq(cpu);
12     rcu_sched_qs(cpu);
13     prev = rq->curr;
14     switch_count = &prev->nivcsw;
15  
16     release_kernel_lock(prev);
17 need_resched_nonpreemptible:
18  
19     schedule_debug(prev);
20  
21     if (sched_feat(HRTICK))
22         hrtick_clear(rq);

接下来通过update_rq_clock()更新就绪队列上的时钟,接着通过clear_tsk_need_resched()清除当前进程prev的重新调度标志TIF_NEED_RESCHED。

1 raw_spin_lock_irq(&rq->lock);
2 update_rq_clock(rq);
3 clear_tsk_need_resched(prev);

如果当前进程是可中断睡眠状态(可运性状态TASK_RUNNING宏的值为0),但它却收到了某个唤醒它的信号,那么当前进程的标志被更新为TASK_RUNNING,等待再次被调度。否则,通过deactivate_task()将当前进程prev从就绪队列中删除。

这里的deactivate_task()根据调度类的不同实现也有所不同,但这些差异对主调度器是透明的,因为调度器类在各种调度实例和调度器之间起到了连接作用。该函数的核心语句即为:

1 p->sched_class->dequeue_task(rq, p, sleep);

sched_class是进程描述符中描述当前进程所属调度类的字段,通过这个字段回调钩子函数dequeue_task()。

1 if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
2     if (unlikely(signal_pending_state(prev->state, prev)))
3         prev->state = TASK_RUNNING;
4     else
5         deactivate_task(rq, prev, 1);
6     switch_count = &prev->nvcsw;
7 }
8  
9 pre_schedule(rq, prev);
10  
11 if (unlikely(!rq->nr_running))
12     idle_balance(cpu, rq);

通过put_prev_task()将prev进程重新插入到就绪队列合适的位置中。再通过pick_next_task()在当前的就绪队列中挑选下一个应该被执行的进程next。这两个函数都属于调度器类中的钩子函数,它们的具体实现根据调度实例的不同而不同。

1 put_prev_task(rq, prev);
2 next = pick_next_task(rq);

有时候,调度器所选的下一个被执行的进程恰好就是当前进程,那么调度器就不必耗费精力去执行上下文切换,但这种情况不是经常发生的。如果prev和 next不是同一个进程,那么先通过sched_info_switch()更新两个进程描述符的相关字段,并且更新可运行队列的相关字段。

接下来调用context_switch()进行prev和next两个进程的上下文切换,该函数由一段汇编代码组成。

1 if (likely(prev != next)) {
2     sched_info_switch(prev, next);
3     perf_event_task_sched_out(prev, next);
4  
5     rq->nr_switches++;
6     rq->curr = next;
7     ++*switch_count;
8  
9     context_switch(rq, prev, next); /* unlocks the rq */
10     /*
11      * the context switch might have flipped the stack from under
12      * us, hence refresh the local variables.
13      */
14     cpu = smp_processor_id();
15     rq = cpu_rq(cpu);
16 } else
17     raw_spin_unlock_irq(&rq->lock);

切换完毕后,当前的进程就是新选择的进程,它会开始执行。而被切换出去的进程重新运行时会从切换函数的下一条语句开始执行。

1     post_schedule(rq);
2  
3     if (unlikely(reacquire_kernel_lock(current) < 0)) {      prev = rq->curr;
4         switch_count = &prev->nivcsw;
5         goto need_resched_nonpreemptible;
6     }
7  
8     preempt_enable_no_resched();
9     if (need_resched())
10         goto need_resched;
11 }

根据上述对主调度器函数源码的分析,可以总结出主调度器的主要功能如下:

1.获取当前进程的描述符以及本地CPU的运行队列

2.将当前进程prev放入可运行队列中,等待下一次被重新调度

3.在当前的可运行队列中选取下一个被调度的新进程next

4.从当前进程切换到新进程

转载于:https://my.oschina.net/u/174242/blog/72938

基于CFS算法的schedule()源码分析相关推荐

  1. SVM算法及OpenCV源码分析

    关于SVM原理,请参看: 系统学习机器学习之SVM(一) 系统学习机器学习之SVM(二) 系统学习机器学习之SVM(三)--Liblinear,LibSVM使用整理,总结 系统学习机器学习之SVM(四 ...

  2. Spark 随机森林算法原理、源码分析及案例实战

    图 1. Spark 与其它大数据处理工具的活跃程度比较 回页首 环境要求 操作系统:Linux,本文采用的 Ubuntu 10.04,大家可以根据自己的喜好使用自己擅长的 Linux 发行版 Jav ...

  3. LIRe图像检索:CEDD算法原理与源码分析

    本文节选自论文<Android手机上图像分类技术的研究>,并结合我对LIRe中CEDD源码进行分析.解读和研究. 颜色和边缘方向性描述符(Color and EdgeDirectivity ...

  4. LIRe图像检索:FCTH算法原理与源码分析

    本文节选自论文<基于半监督和主动学习相结合的图像的检索研究>,并结合我对LIRe中FCTH源码进行分析.解读和研究. 模糊颜色和纹理直方图(Fuzzy Color and Texture ...

  5. Apache Mahout中推荐算法Slope one源码分析

    2019独角兽企业重金招聘Python工程师标准>>> 关于推荐引擎 如今的互联网中,无论是电子商务还是社交网络,对数据挖掘的需求都越来越大了,而推荐引擎正是数据挖掘完美体现:通过分 ...

  6. Java -- 基于JDK1.8的LinkedList源码分析

    1,上周末我们一起分析了ArrayList的源码并进行了一些总结,因为最近在看Collection这一块的东西,下面的图也是大致的总结了Collection里面重要的接口和类,如果没有意外的话后面基本 ...

  7. 基于Android7.0的Launcher3源码分析(1)——框架设计分析

    从事Android rom一年多,一直在负责 Launcher 相关的工作.最近打算写些文章记录下自己对这个模块的理解和源码实现的一些解析. 这些文章将会基于 Android 7.0 的 Launch ...

  8. 基于XMPP协议的aSmack源码分析

    在研究如何实现Pushing功能期间,收集了很多关于Pushing的资料,其中有一个androidnp开源项目用的人比较多,但是由于长时间没有什么人去维护,听说bug的几率挺多的,为了以后自己的产品稳 ...

  9. jdk1.8 源码分析导图

    以下总结全部基于 jdk1.8,详细源码分析见 GitHub 链接:https://github.com/zchen96/jdk1.8-source-code-read 一.非并发 幕布导图链接:ht ...

最新文章

  1. JS中常遇到的浏览器兼容问题和解决方法
  2. 3亿美元,腾讯第三次领投行业AI独角兽明略,这次还有淡马锡领投,快手跟投...
  3. Devexpress Barmanager设置
  4. python json是什么_python json详解
  5. 无法获取未定义或 null 引用的属性“value”_SpringBoot之Spring@Value属性注入使用详解
  6. 作者:姜春宇(1987-),男,中国信息通信研究院移动互联网与大数据部工程师,数据中心联盟大数据技术与产品工作组组长。...
  7. [深度学习-实践]Transformer模型训练IMDB-tensorflow2 keras
  8. 刺激味蕾的甜品果汁饮品psd分层海报素材,愉悦使用图层!
  9. ArcEngine数据编辑--选择要素
  10. P2770 航空路线问题
  11. Install Air Conditioning HDU - 4756(最小生成树+树形dp)
  12. 边缘检测法之Roberts算子
  13. c语言程序设计实例220,C语言程序设计实例大全(220个例子)
  14. 亲测可用企业级自动发卡平台系统源码
  15. Winrar 5.60 beta 4 个性破解注册码(2018.5.22)
  16. centos7 python3 爬虫登陆邮箱_使用爬虫爬取超星学习通的作业时间并且通过邮件提醒!...
  17. 数字逻辑与数字电路知识点整理
  18. STM32H743IIT6+USB3300,USB_HS高速双向HID通讯开发
  19. 就业推荐表鉴计算机水平,毕业生就业推荐表的鉴定评语
  20. centos kvm镜像

热门文章

  1. github上的python爬虫_python爬虫入门(2):让你的github项目火起来
  2. Linux用户与用户组
  3. linux系统电源时钟,linux电源管理的一些梳理
  4. Java运算符优先级和表达式及数据类型转换
  5. oracle批量生成索引,ORACLE迁移时批量导出索引、存储过程,表结构等
  6. python批量修改文件名为excel中指定名称_在Python脚本的帮助下,使用excelsh中的名称映射重命名文件夹中的文件名...
  7. 在用c语言写代码是这么找出错误,写代码(C语言)常见粗心小错误
  8. C++ 使用模板需要注意的事情
  9. 使用kibana客户端工具操作ElasticSearch(增删改查一)
  10. (二)注册服务提供者