今天纠正了一个由来已久的认识错误:一个进程的时间片用完之后,当再次发生时钟中断时内核会调用schedule()来进行调度,把当前的进程上下文切出CPU,并把选定的下一个进程切换进来运行。我一直以为schedule()函数是在时钟中断处理函数中被调用的。其实不是,如果真是这样的话,那么在第一次这样的调度完成之后,时钟中断可能就要被mute掉了,系统从此失去“心跳”。

我之前那样理解是基于这样两点考虑:

  1. 在时钟中断发生时会更新进程的时间片(对于CFS调度器来说,就是更新进程的虚拟运行时间virtual run-time)。 更新完这个时间信息之后,立刻运行schedule()顺理成章,调度就应该在这个时机发生;
  2. 中断发生之后,(以arm架构为例)系统会从IRQ模式迅速切换成SVC模式,并且在此后的中断处理过程中,中断是关闭的,只有在切换回USR模式(其中还经过IRQ模式)时,才回再把中断打开。如果在中断处理函数中调用schedule()并不会带来中断无法再次打开的问题,因为最后总是要切换到USR模式的,那时时钟中断也总是有机会能重新打开的。

但是我没有注意到一个问题,就是ARM中断控制器(VIC)的mask/unmask操作。在进入中断响应函数之前,需要先对相应的中断设计掩码,即把正在处理的这个中断mask掉,在响应完后再把它unmask回来,好让中断能够继续发生。这段代码在kernel/irq/chip.c中(以下是经简化的示例代码):

void handle_level_irq(unsigned int irq, struct irq_desc *desc)
{......mask_ack_irq(desc, irq);......action_ret = handle_IRQ_event(irq, action);......unmask_irq(desc, irq);......
}

注:中断的mask/unmask与enable/disable是两个层次的概念:enable/disable是对所有中断而言,如果disable的话任何中断都不会发生;而mask/unmask是对一个特定的中断而言的,mask之后,指定的中断不会再发生了,但并不影响其它的中断。

所以,基于这种设计,在中断响应过程中,只能更新进程的时间片,却不可以进行调度。如果一旦在上述的handle_IRQ_event()里面调用了schedule()函数,就会立刻切换到其它进程(SVC模式,内核态),接下来的unmask_irq()执行不到,时钟中断就再也没有机会打开。切换到下一个进程之后,因为没有时钟中断,系统也就失去了心跳。

正确的方法是在中断处理快要结束时调用schedule():

在中断处理的汇编代码中(arm架构下主要看__irq_usr),主要的中断处理过程都完成之后,会跑到ret_to_user处准备返回用户模式。这时就会检查进程的thread_info结构中是否置有“_TIF_NEED_RESCHED”标志,如果是的话,说明需要进行进程调度,这时再调用函数schedule()。在这个时间点上,中断控制器中相应的位已经被unmask过,接下来只要开中断即可。

上面提到的汇编代码比较零散,这里就不贴了,都在文件arch/arm/kernel/entry-armv.S和entry-common.S中。

schedule()函数的调用时机(周期性调度)相关推荐

  1. Angular 依赖注入里factory函数的调用时机

    我们调用InjectionToken构造器,创建一个新的InjectionToken实例时,除了传入一个字符串作为description,还可以指定一个options结构: const MY_SERV ...

  2. 关于 Angular Component ngOnDestroy 钩子函数的调用时机

    我开发了一个 Angular Component,实现了 ngOnDestroy 钩子方法之后,没有找到其被调用的方法.查看这个StackOverflow链接后,得知无论是我刷新浏览器,还是从当前页面 ...

  3. js for循环_JS 函数的执行时机(深入理解6个6)

    定时器:setTimeout() setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式 提示: 1000 毫秒= 1 秒. 提示: 如果你只想重复执行可以使用 setInterval ...

  4. kernel调度(2)----主调度器和周期性调度器

    进程切换 上一章介绍了调度相关的基础知识,那么这章准备介绍一下进程切换相关的原理.包括主调度器和周期性调度器都做了哪些工作.以及进程切换都做了哪些工作. 周期性调度器都做了什么 我们知道周期性调度器就 ...

  5. 【Linux 内核】CFS 调度器 ④ ( 调度子系统组件模块 | 主调度器、周期性调度器 | 调度器类 )

    文章目录 一.调度子系统组件模块 二.主调度器.周期性调度器 三.调度器类 一.调度子系统组件模块 调度器 需要对 被调度的进程 进行 排序 和 调度管理 , 进程管理过程需要 调度器 的 组件模块 ...

  6. Linux系统核心调度器——周期性调度器详解

    日期 内核版本 架构 作者 内容 2019-5-13 Linux-2.6.32 X86 Bystander Linux进程调度 1 绪论 在<Linux系统进程调度--调度架构详细分析>一 ...

  7. linux cfs 参数设置,Linux CFS如何处理周期性调度器、CFS的周期性调度及总结

    1. CFS如何处理周期性调度器 周期性调度器的工作由scheduler_tick函数完成(定义在kernel/sched/core.c, line 2910), 在scheduler_tick中周期 ...

  8. schedule函数浅析

    本文主要讲了: 1.schedule函数的大体框架 2.调度的时候对prev进程都做了什么操作 3.怎么选出的next进程(O(1)算法和CFS算法) 4.CPU负载均衡在做什么 现代用户对操作系统的 ...

  9. schedule()函数(重点)

    好了,前面的准备工作都做完了,我们就进入进程调度的主体程序--schedule()函数. 函数schedule()实现调度程序.它的任务是从运行队列的链表rq中找到一个进程,并随后将CPU分配给这个进 ...

  10. 哈工大李治军老师操作系统笔记【13】:一个实际的schedule函数(Learning OS Concepts By Coding Them !)

    文章目录 0 回顾 1 linux0.11的schedule() 1.1 counter的作用 2 总结 0 回顾 实际的schedule是多种基本算法的融合,综合考虑各种情况,但也要求算法本身尽可能 ...

最新文章

  1. 搭建Ubuntu18.04+Anaconda3.x+Pycharm+SimpleITK(二)
  2. hibenate5.1配置mysql_hibernate5.2的基本配置方法(详解)
  3. vl02n 批次拆分
  4. 操作系统:升级Windows 11正式版的四种方法,值得收藏!
  5. 【剑指offer】面试题19:正则表达式匹配(Java)
  6. 收藏 | 从头训练深度监督目标检测
  7. Spring IOC学习心得之注册bean的依赖关系
  8. JAVA实现ATM源代码及感想
  9. AC日记——独木桥 洛谷 p1007
  10. C++ json解析
  11. 高速无人驾驶车辆防滑移MPC控制 学习笔记(未完结)
  12. Qt 中使用librdkafka librdkafka++ 创建消费者
  13. 输入法linux debin,Debian下安装搜狗拼音输入法
  14. ajax removeclass,Ajax成功后的jQuery addClass/removeClass
  15. 2018天津大学夏令营机试第二题
  16. openjudge 4978 宠物小精灵之收服
  17. 圆锥形怎么画_(艺考生必看)素描圆锥体怎么画?详解过程,想提高成绩的进来!...
  18. 微信影视小程序是如何赚钱的?效果怎么样?
  19. day26-多进程多线程
  20. 转:在Linux服务器上配置phpMyAdmin

热门文章

  1. java用信号量写理发师_课内资源 - 基于Java实现的生产者与消费者问题、读者写者问题、哲学家进餐问题、理发师睡觉问题、医生看病问题...
  2. 力扣-面试题 10.05 稀疏数组搜索
  3. Harmony OS — TabList和Tab分页栏
  4. vscode怎样打开终端 使用命令行
  5. Eclipse 中侧边栏、控制台、Server打不开怎么办?
  6. L1-035 情人节 (15 分)—团体程序设计天梯赛
  7. 【bug】VUE:Cannot read property '_withTask' of undefined
  8. 求10000以内n的阶乘(openjudge 2923)
  9. 创建5个组,然后把30个用户分别加入到5个组中
  10. 详解IOS开发应用之并发Dispatch Queues