Linux内核学习之内核控制路径

注:本文包含个人的一些理解和认知

内核控制路径

内核控制路径可以理解为内核代码的另一种叫法,它将内核代码分成三类,即,

  1. 系统调用处理代码
  2. 异常处理代码
  3. 中断处理代码

其实,从某种意义上来说,它们都是一样的,都属于中断的一种。
系统调用是一种软中断,一般使用的是中断中,优先级较低的软中断,就像arm的svc指令
异常的话,也是一种中断,单从结果上来看的话,异常和中断没什么区别,都是让cpu停下当前正在做的事情,然后去响应突发事件。之所以有这两个概念,主要是想区分事件的来源。
谈异常的时候,更多的是指cpu内部事件,常指编程错误,如除数为0、访问无权限或者根本不存在的内存地址,由于内部事件时钟源都是系统时钟,因此事件一般都是同步的。
谈中断的时候,更多的是指cpu外部事件,即外部中断,由于外部事件具有不可预测性,因此中断往往是异步的,做成异步的另一个原因是,能提高中断的响应的及时性。

可重入性

内核控制路径都是设计成可重入的,可重复性能够保证多个进程同时进入内核态,能够提高程序的效率。实现可重入的一个基本方法就是尽可能使用局部变量,少使用全局变量,当然有些内核函数避免不了需要访问全局数据结构, 这时候,为了保证可重入性及数据的一致性,需要对全局变量的访问加锁处理,实际上加锁还不够,因为在锁内,代码仍然能够被中断打断,当中断程序也访问了那个全局变量,就会造成数据不安全,因此往往还需要配合关中断来实现。

交叉执行的内核控制路径

内核控制路径交叉执行说的是,一个内核控制路径未执行完成,另一个内核控制路径就开始执行,实际中会出现多个内核控制路径交叉执行。
内核控制路径交叉执行的场景可以归纳为四类:

  1. 阻塞性系统调用
  2. 内核态异常
  3. 内核态中断
  4. 内核态抢占
  • 阻塞性系统调用,是指,应用程序调用了某些阻塞性的系统调用,比如等待一个socket接入,等待消息队列,这时,进程会在内核态阻塞,调度器会选择下一个进程投入执行,然后下一个进程又通过系统调用进入一个内核控制路径,这时,两个进程出现了两个内核控制路径,这两个内核控制路径分别代表两个进程进行执行。
  • 内核态异常,实际上,一个设计调试好的内核,是不能随便在内核态产生异常的,因为异常是指内部事件,常指编程错误,是可预见、可避免的,正如其名,异常就是指不正常的事件,但是Linux内核巧妙的利用了少数异常来完成一些功能,比如利用缺页异常完成内存交换。当一个进程进入到内核控制路径,这时访问的地址触发了硬件缺页异常,然后CPU就会跳转了缺页异常处理程序,首先为进程分配页(就是建立页到物理页框的映射),然后将页表内容从磁盘读取到页内存(这个过程其实也相当费时,读磁盘的过程中甚至会发生进程切换,这里暂不讨论),这里就已经有了两个内核控制路径,一个是进程的系统调用,一个是异常处理,这两个内核控制路径都代表这进程的执行,时间都要算到该进程。
  • 内核态中断,为了提升中断的响应速度,Linux内核代码大部分地方都是开启了中断的,当进程通过系统调用进入内核态后,这时,发生了中断,CPU会切换到中断执行程序,这里同样有两个内核控制路径,一个是系统调用,一个是中断处理程序,在当前Linux实现中,这个中断处理程序的执行时间被算给了这个进程,然而,中断程序是没有必要代表进程执行的。
  • 内核态抢占,这需要在编译Linux内核时开启内核抢占功能,不是所有Linux都支持的。我们知道,进程调度中,最基础的时间片调度是通过定时器实现的,一般定时器1ms产生一次中断,在中断执行程序中,内核会检查就绪进程的优先级,选择一个最高优先级的进程投入执行。当一个进程通过系统调用进入内核后,刚好产生了定时中断,并且存在高优先级就绪进程,那么内核会立即切换到另一个进程运行,另一个进程也会通过系统调用进入内核控制路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值