Linux kernel学习(五)进程调度与切换

上篇文章主要讲了进程的结构以及进程的创建、初始化,这篇文章主要来讲进程是如何调度(schedule)和切换的(switch)。

进程调度函数void schedule(void)

进程切换函数switch_to(next)

两个函数在意义上有着较大区别,进程调度是指CPU需要选择出来一个进程来执行,因此进程调度函数内部是选择的算法,而进程切换是指将当前进程切换为已经选择出来的进程上,主要是一个切换的过程。

辅助函数show_task函数,用来打印进程的信息,包括进程ID、进程状态、堆栈剩余内存信息、父进程ID、子进程ID等等,该函数在show_state函数中被调用。linux规定了进程的几种状态如图:

翻译过来分别就是:

运行状态:进程的运行以及进程的切换必须发生在进程的运行状态下

可中断睡眠状态:可以被信号中断使其变成RUNNING状态

不可中断睡眠状态:只能被wakeup唤醒变成RUNNING状态

僵死状态:通过指令暂停某个进程的运行

暂停状态:进程停止运行了,但是它的父进程还没有将其清空

首先看调度函数schedule(void),函数大体可以分为两个部分,第一部分是唤醒任何收到信号的可中断任务,也就是中断当前的进程,第二部分是调度的算法。

for循环中是在遍历整个task链表,alarm表示进程计时器,如果当前计时器时间小于jiffies,就将进程的信号更改为SIGALRM,接下来判断进程是否存在信号且信号是否为非阻塞信号量,并且状态是可中断的状态,那么将进程状态改为RUNNING状态,这部分意在让所有task链表中的满足条件的进程都能拥有SIGALRM这个信号,从而进入就绪状态。

第二部分是算法部分,首先CPU在选择进程运行的时候,比较的是时间片(counter)的大小,谁大先执行谁,当然这只是其中一种类型的调度算法(优先级轮转调度算法),那么计算时间片大小的操作就需要算法来进行排列了:

首先在152行,将counter先和c(-1)比较,然后和c进行替换,最后通过整个的遍历,获取到task链表中最大的counter赋值c,然后判断c是否大于0,大于的话则直接结束循环去执行后续switch函数;若为0的话,系统就会认为当前所有的进程的counter都已归0,然后就会开始进行时间片的重分配,因此要重新遍历一遍当前task链表,获取到新的进行信息,然后在158、159行进行分配,简单来说就是将counter的值赋值为counter/2+priority(优先级),这样将counter的值都改一遍再重复以上行为。

调度函数讲完接下来讲一下切换进程的函数switch_to,该函数是通过一段汇编的宏定义代码实现的:

首先比较一下指针所指向的是否为当前进程,然后将需要切换的进程赋值给当前进程(current),进行进程的上下文切换,这里可以用一张图片更直观的表示

在CPU中会有专门负责保存每个进程TSS地址的区域,在前面讲过CPU通过TSS进程状态描述符来获取到进程的重要信息,所以CPU在切换上下文时需要做的就是将原进行的TSS和新进程的TSS在CPU的TSS段寄存器中进行替换,将原TSS返还给原进程的TSS,将新的载入进去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值