schedule()函数的调用时机(周期性调度)
今天纠正了一个由来已久的认识错误:一个进程的时间片用完之后,当再次发生时钟中断时内核会调用schedule()来进行调度,把当前的进程上下文切出CPU,并把选定的下一个进程切换进来运行。我一直以为schedule()函数是在时钟中断处理函数中被调用的。其实不是,如果真是这样的话,那么在第一次这样的调度完成之后,时钟中断可能就要被mute掉了,系统从此失去“心跳”。
我之前那样理解是基于这样两点考虑:
- 在时钟中断发生时会更新进程的时间片(对于CFS调度器来说,就是更新进程的虚拟运行时间virtual run-time)。 更新完这个时间信息之后,立刻运行schedule()顺理成章,调度就应该在这个时机发生;
- 中断发生之后,(以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()函数的调用时机(周期性调度)的更多相关文章
- MFC浅析(7) CWnd类虚函数的调用时机、缺省实现
CWnd类虚函数的调用时机.缺省实现 FMD(http://www.fmdstudio.net) 1. Create 2. PreCreateWindow 3. PreSubclassWindow 4 ...
- CWnd类虚函数的调用时机、缺省实现
MFC(VC6.0)的CWnd及其子类中,有如下三个函数: class CWnd : public CCmdTarget{ public: virtual BOOL PreCrea ...
- Linux CFS调度器之task_tick_fair处理周期性调度器--Linux进程的管理与调度(二十九)
1. CFS如何处理周期性调度器 周期性调度器的工作由scheduler_tick函数完成(定义在kernel/sched/core.c, line 2910), 在scheduler_tick中周期 ...
- Linux核心调度器之周期性调度器scheduler_tick--Linux进程的管理与调度(十八)
我们前面提到linux有两种方法激活调度器:核心调度器和 周期调度器 一种是直接的, 比如进程打算睡眠或出于其他原因放弃CPU 另一种是通过周期性的机制, 以固定的频率运行, 不时的检测是否有必要 因 ...
- Direct3D Draw函数 异步调用原理解析
概述 在D3D10中,一个基本的渲染流程可分为以下步骤: 清理帧缓存: 执行若干次的绘制: 通过Device API创建所需Buffer: 通过Map/Unmap填充数据到Buffer中: 将Buff ...
- Spring AOP在函数接口调用性能分析及其日志处理方面的应用
面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志.本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信 ...
- 驱动:中断【2】中断处理程序、中断上下文中处理延时及一些函数的调用规则(调IIC中断驱动有感)
中断处理程序.中断上下文中处理延时及一些函数的调用规则(调IIC中断驱动有感)http://blog.csdn.net/samantha_sun/article/details/6790492 1,中 ...
- (copy)赋值构造函数的4种调用时机or方法
第一种调用方法: demo #include <iostream> using namespace std; class Text { public: Text() // 无参数构造函数 ...
- 周期性调度器scheduler_tick
周期性调度器由中断实现,系统定时产生一个中断,然后启动周期性调度器,周期性调度器执行过程中要关闭中断, 周期性调度器执行完毕后再打开中断(handle_IRQ_event, IRQF_DISABLE ...
随机推荐
- Spring3 MVC 拦截器拦截不到的问题
拦截器: com.zk.interceptors.MyInterceptor 实现了 HandlerInterceptor接口,可以拦截@RequestMapping注解的类和方法 第一种方式 < ...
- Linux 静态库&动态库调用
1.什么是库在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.由于windows和linux的本质不同,因此二者库的二进制是不 ...
- 做自己的Android ROM,屏蔽对framework中的系统APK的签名检查
最近两天一直在尝试更新Android中的关键库以达到定制ROM的效果,中间比较曲折,记录下来供自己和大家参考. 因为我需要基于Android的原生代码做一定的修改,所以如果无法将我自己编译出的APK或 ...
- 解决android应用程序适用新老android系统版本方法
老的android系统不能运行高版本系统的新方法,为了解决这个问题: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { ...
- 内省(一)之Introspector、BeanInfo、PropertyDescriptor
内省(Introspector)是专门用来操作JavaBean属性的.不是所有的字段(Field)都能被称之为属性,只有某些字段具有getXXX或setXXX方法的才能称之为属性,当然要称为是一个Be ...
- How to find configuration file MySQL uses?(转)
http://www.dbasquare.com/2012/04/01/how-to-find-mysql-configuration-file/ A customer called me today ...
- vector中的find
vector中的find - huangyimin的专栏 - 博客频道 - CSDN.NET vector中的find 2011-01-13 09:57 11334人阅读 评论(0) 收藏 举报 ve ...
- XML学习经验实例总结2
DTD约束 Book.dtd: <!ELEMENT 书架 (书+)> <!ELEMENT 书 (书名,价格,介绍)> <!ELEMENT 书名 (#PCDATA)> ...
- c++ try throw catch
c++ try throw catch 这三者联合使用 , try { statement list; } catch( typeA arg ) { statement list; } catch( ...
- TCP_NODELAY详解
在网络拥塞控制领域,我们知道有一个非常有名的算法叫做Nagle算法(Nagle algorithm),这是使用它的发明人John Nagle的名字来命名的,John Nagle在1984年首次用这个算 ...