所谓“原子操作”就是这个操作不会被打断。Linux有2种原子操作:原子变量、原子位。
原子变量的内核操作函数
原子变量的操作函数在Linux内核文件arch\arm\include\asm\atomic.h中。
原子变量类型如下,实际上就是一个结构体(内核文件include/linux/types.h):
原子变量的内核实现
注意:SMP就是Symmetric Multi-Processors,对称多处理器;UP即Uni-Processor,系统只有一个单核CPU。
这些函数都是在Linux内核文件arch\arm\include\asm\atomic.h中。
atomic_read,atomic_set这些操作都只需要一条汇编指令,所以它们本身就是不可打断的。
问题在于atomic_inc这类操作,要读出、修改、写回。
以atomic_inc为例,在atomic.h文件中,如下定义:
从上面的宏可以知道,一个ATOMIC_OPS定义了3个函数。比如“ATOMIC_OPS(add, +=, add)”就定义了这3个函数:
我们以ATOMIC_OP(add, +=, add)为例,看它是如何实现atomic_add函数的,对于UP系统、SMP系统,分别有不同的实现方法。
ATOMIC_OP在UP系统中的实现
对于ARMv6以下的CPU系统,不支持SMP。原子变量的操作简单粗暴:关中断,中断都关了,谁能来打断我?代码如下(arch\arm\include\asm\atomic.h):
ATOMIC_OP在SMP系统中的实现
对于ARMv6及以上的CPU,有一些特殊的汇编指令来实现原子操作,不再需要关中断,代码如下(arch\arm\include\asm\atomic.h):
在ARMv6及以上的架构中,有ldrex、strex指令,ex表示exclude,意为独占地。这2条指令要配合使用,举例如下:
① 读出:ldrex r0, [r1]
读取r1所指内存的数据,存入r0;并且标记r1所指内存为“独占访问”。
如果有其他程序再次执行“ldrex r0, [r1]”,一样会成功,一样会标记r1所指内存为“独占访问”。
② 修改r0的值
③ 写入:strex r2, r0, [r1]:
如果r1的“独占访问”标记还存在,则把r0的新值写入r1所指内存,并且清除“独占访问”的标记,把r2设为0表示成功。
如果r1的“独占访问”标记不存在了,就不会更新内存,并且把r2设为1表示失败。
假设这样的抢占场景:
① 程序A在读出、修改某个变量时,被程序B抢占了;
② 程序B先完成了操作,程序B的strex操作会清除“独占访问”的标记;
③ 轮到程序A执行剩下的写入操作时,它发现独占访问”标记不存在了,于是取消写入操作。
这就避免了这样的事情发生:程序A、B同时修改这个变量,并且都自认为成功了。
举报个例子,比如atomic_dec,假设一开始变量值为1,程序A本想把值从1变为0;但是中途被程序B先把值从1变成0了;但是没关系,程序A里会再次读出新值、修改、写入,最终这个值被程序A从0改为-1。
在ARMv6及以上的架构中,原子操作不再需要关闭中断,关中断的花销太大了。并且关中断并不适合SMP多CPU系统,你关了CPU0的中断,CPU1也可能会来执行些操作啊。
在ARMv6及以上的架构中,原子操作的执行过程是可以被打断的,但是它的效果符合“原子”的定义:一个完整的“读、修改、写入”原子的,不会被别的程序打断。它的思路很简单:如果被别的程序打断了,那就重来,最后总会成功的。
原子变量使用案例
现在可以使用原子变量实现:只能有一个APP访问驱动程序。代码如下:
第5行的atomic_dec_and_test,这是一个原子操作,在ARMv6以下的CPU架构中,这个函数是在关中断的情况下执行的,它确实是“原子的”,执行过程不被打断。
但是在ARMv6及以上的CPU架构中,这个函数其实是可以被打断的,但是它实现了原子操作的效果,如下图所示:
原子位介绍
原子位的内核操作函数
能操作原子变量,再去操作其中的某一位,不是挺简单的嘛?不过不需要我们自己去实现,内核做好了。
原子位的操作函数在Linux内核文件arch\arm\include\asm\bitops.h中,下表中p是一个unsigned long指针。
原子位的内核实现
在ARMv6以下的架构里,不支持SMP系统,原子位的操作函数也是简单粗暴:关中断。以set_bit函数为例,代码在内核文件arch\arm\include\asm\bitops.h中,如下
在ARMv6及以上的架构中,不需要关中断,有ldrex、strex等指令,这些指令的作用在前面介绍过。还是以set_bit函数为例,代码如下:
标签:03,r1,原子,atomic,ARMv6,操作,原理,内核 From: https://www.cnblogs.com/liusiluandzhangkun/p/18171240