临界段的保护
什么是临界段
临界段,用一句话概括就是一段在执行时不能被中断的代码段。在RT-Thread中,临界段最常出现的场景就是对全局变量的操作,全局变量就好像是一个靶子,谁都可以对其开枪,但是有一人开枪,其他人就不能开枪,否则就不知道是谁命中了靶子。
那么什么情况下临界段会被打断?一个是系统调度,还有一个就是外部中断。在RT-Thread中,系统调度最终也是产生PendSV中断,在PendSV Handler中实现线程的切换,所以还是可以归结为中断。既然这样,RT-Thread对临界段的保护就处理得很干脆了,直接把中断关闭,但NMI FAULT和硬FAULT除外。
Cortex-M内核快速关中断指令
为了快速地开关中断,Cortex-M内核专门设置了一条CPS指令,有4种用法。
代码清单CPS指令用法
CPSID I ;PRIMASK=1 ;关中断
CPSIE I ;PRIMASK=0 ;开中断
CPSID F ;FAULTMASK=1 ;关异常
CPSIE F ;FAULTMASK=0 ;开异常
代码清单中PRIMASK和FAULTMAST是Cortex-M内核中3个中断屏蔽寄存器中的2个,还有一个是BASEPRI,有关这3个寄存器的详细用法如表所示。
关中断
RT-Thread关中断的函数在contex_rvds.s中定义,在rthw.h中声明,具体实现参见代码清单4-2。
关中断
rt_hw_interrupt_disable PROC
EXPORT rt_hw_interrupt_disable
MRS r0, PRIMASK
CPSID I
BX LR
ENDP
1):关键字PROC表示汇编子程序开始。
2):使用EXPORT关键字导出标号rt_hw_interrupt_disable,使其具有全局属性,在外部头文件声明后(在rthw.h中声明),就可以在C文件中调用。
3):通过MRS指令将特殊寄存器PRIMASK寄存器的值存储到通用寄存器r0。当在C中调用汇编的子程序返回时,会将r0作为函数的返回值。所以在C中调用rt_hw_interrupt_disable()时,需要事先声明一个变量用来存储rt_hw_interrupt_disable()的返回值,即r0寄存器的值,也就是PRIMASK的值。
4):关闭中断,即使用CPS指令将PRIMASK寄存器的值置1。
5):子程序返回。
6):ENDP表示汇编子程序结束,与PROC成对使用。
开中断
RT-Thread开中断的函数在contex_rvds.s中定义,在rthw.h中声明。
开中断
rt_hw_interrupt_enable PROC
EXPORT rt_hw_interrupt_enable
MSR PRIMASK, r0
BX LR
ENDP
1):关键字PROC表示汇编子程序开始。
2):使用EXPORT关键字导出标号rt_hw_interrupt_enable,使其具有全局属性,在外部头文件声明后(在rthw.h中声明),就可以在C文件中调用。
3):通过MSR指令将通用寄存器r0的值存储到特殊寄存器PRIMASK。
4):子程序返回。
5):ENDP表示汇编子程序结束,与PROC成对使用。
临界段代码的应用
在进入临界段之前,我们会先把中断关闭,退出临界段时再把中断打开,而且Cortex-M内核中设置了快速关中断的CPS指令,开关中断的函数的实现和临界段代码的保护。
开关中断的函数的实现和临界段代码的保护
开关中断的函数的实现
rt_hw_interrupt_disable PROC
EXPORT rt_hw_interrupt_disable
CPSID I
BX LR
ENDP
;
rt_hw_interrupt_enable PROC
EXPORT rt_hw_interrupt_enable
CPSIE I
BX LR
ENDP
PRIMASK = 0;
{
rt_hw_interrupt_disable();
{
}
rt_hw_interrupt_enable();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)