文章目录
Linux内核并发和竞态
案例一:
案例二:
分析
相关概念
Linux内核解决竞态引起的异常(漏洞)的方法
Linux内核并发和竞态
案例一:
前面就发现了在Linux内核中使用全局变量或者多线程可能同时访问的区域会遇到竞态的问题,比如前面的定时器使用的实现部分就发生了并发问题。Linux驱动开发——定时器
造成这样的原因是因为当我们按下按键的时候会操作多次按键中断触发,而在按键中断处理函数中会对一个全局变量mytimer_value进行自增或者自减,由于我们使用的板子是多核CPU的,所以当几乎同时的两次中断触发发生时,可能会有两个CPU核同时对按键中断进行处理,而他们在取得这个全局变量的时候值如果相同,在经过判断后都进行了自增或者自减,那么就相当于一次进行了两次自增或者自减。对应多次触发中断处理这个现象不是什么问题,但是我们在处理中添加了数值增减的范围,那么在并发的时候我们的这个判读就没有任何作用了。最终导致我们设置1到10的范围却发现能够将mytimer_value这个变量的值在这样的判断下加到11、降到0。这还是很严重的问题。
案例二:
如果让CPU通过某个GPIO给LCD显示屏发送一个固定周期(10ms)的高低电平(高电平5ms,低电平5ms)
实现过程,软件编程如下:
void lcd_config(void) { //拉高 gpio_set_value(PAD_GPIO_B+8, 1); //让高电平持续5ms mdelay(5); //拉低 gpio_set_value(PAG_GPIO_B+8, 0); //让低电平持续5ms mdelay(5); }
但是,此代码运行以后,通过示波器抓取波形,测量这周的时间要大于10ms。
分析问题产生的原因:
- 假如是某个进程来调用此函数配置高低电平,如果当这个进程刚拉高电平(还没有执行mdelay),此时此刻来了一个高优先级的进程,或者来一个中断,会将这个进程的CPU资源抢走,CPU资源进行切换执行处理别的高优先级的进程或者中断而这个执行过程中,GPIOB8还是持续为高电平,当CPU处理完高优先级的进程或者中断返回以后在执行mdelay,最终造成高电平的持续时间势必大于5ms,整个周期势必超时10ms。
分析
通过以上两个案例,我们能够得出结论
在Linux内核中,产生以上类似漏洞的四种情形:
- 多核(多个CPU,简称SMP) ,多核CPU是共享内存,闪存,GPIO等硬件资源。
- 同一个CPU上的进程与进程之前的抢占。
- 中断和进程(中断的优先级高于进程):硬件中断和进程,软中断和进程。
- 中断和中断(硬件中断优先级高于软中断):硬件中断和软中断,软中断和软中断。
相关概念
并发: 多个执行单元(进程或中断)同时发送。
竞态: 多个执行单元对共享资源的同时访问形成竞争的状态(必须具备以下三个条件):
- 必须有多个执行单元。
- 必须有共享资源。
- 必须同时访问。
共享资源: 软件上的全局变量或者硬件资源。
临界区: 对共享资源访问的区域。
互斥访问: 当一个执行单元在访问临界区时,其他执行单元禁止访问临界区,直到访问临界区的当前任务访问完毕。
执行路径具有原子性: 当某个任务获取到CPU资源踏踏实实访问临界区时(共享资源),不允许发生CPU资源的切换,要保证这个任务能够顺利访问临界区,而其他任务等待。
Linux内核解决竞态引起的异常(漏洞)的方法
总共有四种方式:
- 中断屏蔽。
- 自旋锁。
- 信号量。
- 原子操作。