RT-Thread临界段的保护

简介: RT-Thread临界段的保护

临界段的保护

什么是临界段

临界段,用一句话概括就是一段在执行时不能被中断的代码段。在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_base_t rt_hw_interrupt_disable();
; */
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中声明。

开中断

/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
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指令,开关中断的函数的实现和临界段代码的保护。

开关中断的函数的实现和临界段代码的保护
开关中断的函数的实现
/*
* void rt_hw_interrupt_disable();
*/
rt_hw_interrupt_disable  PROC
 EXPORT rt_hw_interrupt_disable
  CPSID  I    
  BX   LR
  ENDP
;/*
; * void rt_hw_interrupt_enable(void);
; */
rt_hw_interrupt_enable  PROC
  EXPORT rt_hw_interrupt_enable
  CPSIE  I    
  BX   LR
  ENDP
PRIMASK = 0;           /* PRIMASK初始值为0,表示没有关中断 */    
/* 临界段代码保护 */
{
  /* 临界段开始 */
  rt_hw_interrupt_disable();   /* 关中断,PRIMASK = 1 */    
  {
    /* 执行临界段代码,不可中断 */    
  }
  /* 临界段结束 */
    rt_hw_interrupt_enable();   /* 开中断,PRIMASK = 0 */   
}
相关文章
|
6月前
更换外部晶振RT-Thread中修改频率
更换外部晶振RT-Thread中修改频率
|
6月前
|
Java
线程数设置
线程数设置
72 0
|
调度 C语言 芯片
RT-Thread记录(二、RT-Thread内核启动流程 — 启动文件和源码分析)
今天就在前面我们RT-Thread Studio工程基础之上讲一讲RT-Thread内核启动流程
637 0
RT-Thread记录(二、RT-Thread内核启动流程 — 启动文件和源码分析)
|
消息中间件 算法 安全
关于RT-Thread内核的介绍
关于RT-Thread内核的介绍
RT-Thread线程创建和删除
RT-Thread线程创建和删除
143 0
|
编译器 程序员 C语言
【玩转RT-Thread】RT-Thread内核宏定义详解(rtdef.h)
【玩转RT-Thread】RT-Thread内核宏定义详解(rtdef.h)
650 0
|
传感器 调度 芯片
【玩转RT-Thread】线程管理(详细原理)(上)
【玩转RT-Thread】线程管理(详细原理)(上)
296 0
|
API 调度
【玩转RT-Thread】线程管理(详细原理)(下)
【玩转RT-Thread】线程管理(详细原理)
307 0
|
传感器
【玩转RT-Thread】I2C(内核学习)
【玩转RT-Thread】I2C(内核学习)
195 0
|
调度 芯片
【玩转RT-Thread】 时钟管理(原理+实战)
【玩转RT-Thread】 时钟管理(原理+实战)
363 0