临界区代码`OS_CRITICAL_ENTER();OS_CRITICAL_EXIT();OS_CRITICAL_EXIT_NO_SCHED();`是用来对一些不能被打断的代码进行保护的操作,即通过进行临界区OS_CRITICAL_ENTER()退出临界区OS_CROTOCAL_EIT()操作中间所保护起来的
代码叫临界区。
对于如果临界区可以通过中断服务程序和任务访问的话则需要通过禁用中断来保护临界区;如果临界区只能由任务级代码访问的话,则可以通
过使用抢占锁来保护临界区。在μC/OS-III中,临界区的访问由中断所使用的ISR post方法来决定(即中断的管理部分)。
如果OS_CFG_ISR_POST_DEFERRED_EN(os_cfg.h文件中)被置0,则当进入内部临界区前,μC/OS-III将会禁用中断。
如果OS_CFG_ISR_POST_DEFERRED_EN被置1则当进入内部临界区的时候μC/OS-III将会锁定调度器。
- 禁用中断方法:
OS_CFG_ISR_POST_DEFERRED_EN(os_cfg.h文件中)被置0,
进入临界区OS_CRITICAL_ENTER()
(os.h文件中)调用CPU_CRITICAL_ENTER()
(cpu.h文件中)来进一步调用CPU_SR_Save()
(cpu.h文件)以保存当前CPU状态和禁用中断。之后保持的中断禁用状态将会返回给OS_CRITICAL_ENTER()
函数的调用者,故而在使用进入临界区函数之前需要使用CPU_SR_ALLOC();
(cpu.h文件)以声明一个存放中断禁用状态的变量“cpu_sr”。
退出临界区OS_CRITICAL_EXIT()
和OS_CRITICAL_EXIT_NO_SCHED()
都通过使用宏CPU_CRITICAL_EXIT()
来调用CPU_SR_Restore()
在退出临界区时通过保存的“cpu_sr”变量来重建中断。
具体代码如下
#define OS_CRITICAL_ENTER() CPU_CRITICAL_ENTER()
#define OS_CRITICAL_EXIT() CPU_CRITICAL_EXIT()
#define OS_CRITICAL_EXIT_NO_SCHED() CPU_CRITICAL_EXIT()
/* cpu.h */
/* 禁用中断并且开始中断禁用时间测量 */
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \
CPU_IntDisMeasStart(); } while (0)
#define CPU_INT_DIS() do { cpu_sr = CPU_SR_Save(); } while (0)
/* 停止测量并且重新打开中断 */
#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \
CPU_INT_EN(); } while (0)
#define CPU_INT_EN() do { CPU_SR_Restore(cpu_sr); } while (0)
- 禁用中断时间测量
用户可以通过设置CPU_CFG_INT_DIS_MEAS_EN
(cpu_cfg.h文件)为1来使用这项功能。当使用OS_CRITICAL_EXIT()
进入临界区时,会调用CPU_IntDisMeasStart();
以记录禁用中断的时刻,在调用OS_CRITICAL_EXIT()
或OS_CRITICAL_EXIT_NO_SCHED()
时会调用CPU_IntDisMeasStop();
以此获得禁用中断的时间间隔,而测量到的时间间隔被放在了对于任务的任务块数据结构中即OS_TCB数据结构中的IntDisTimeMax
。 - 锁定调度器:
OS_CFG_ISR_POST_DEFERRED_EN(os_cfg.h文件中)被置1
OS_CRITICAL_ENTER()此时则通过增加OSSchedLockNestingCtr变量来锁定调度器,调度器通过对OSSchedLockNestingCtr是否为0来确定是否锁定调度器。
相应的OS_CRITICAL_EXIT()通过减小OSSchedLockNestingCtr变量至0值来解锁并调用调度器。而OS_CRITICAL_EXIT_NO_SCHED()虽然也会减小OSSchedLockNestingCtr变量但它不会调用调度器。
/* 调度只在中断发生时发生 */
#define OS_CRITICAL_ENTER() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr++; \
if (OSSchedLockNestingCtr == 1u) { \
OS_SCHED_LOCK_TIME_MEAS_START(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0)
#define OS_CRITICAL_EXIT() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr--; \
if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \
OS_SCHED_LOCK_TIME_MEAS_STOP(); \
if (OSIntQNbrEntries > (OS_OBJ_QTY)0) { \
CPU_CRITICAL_EXIT(); \
OS_Sched0(); \
} else { \
CPU_CRITICAL_EXIT(); \
} \
} else { \
CPU_CRITICAL_EXIT(); \
} \
} while (0)
#define OS_CRITICAL_EXIT_NO_SCHED() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr--; \
if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \
OS_SCHED_LOCK_TIME_MEAS_STOP(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0)
同优先级的多任务:虽然μC/OS-III支持具有同优先级的多个任务,但同优先级的多个任务需要创建更长的临界区,然而如果只是少数的几个任务具有同优先级那么中断延时相对较小,如果没有多个任务是同优先级的那么使用中断
禁用模式
事件标志:如果只有少量的任务(大约1到5个)等待一个事件标志组,那么临界区便足够短,可以使用中断禁用模式。
版权声明:本文为weixin_43486211原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。