1.临界段代码,也叫临界区,是指那些必须完整连续运行,不可被打断的代码段。在uC/OS-III中存在大量的临界段代码。
2.中断处理程序和任务都会访问的临界段代码,需要使用关中断的方法加以保护;仅由任务访问的临界段代码,可以通过给调度器上锁的方法来保护。
3.在uC/OS-III中,使用宏OS_CRITICAL_ENTER()进入临界区;使用宏OS_CRITICAL_EXIT()和OS_CRITICAL_EXIT_NO_SCHED()退出临界区。
注:上面的三个宏是uC/OS-III内部的定义,外部的任务不能使用。
3.uC/OS-III可以使用两种方式保护临界段代码:关中断或锁定调度器。
OS_CFG_ISR_POST_DEFERRED_EN为0,使用关中断的方式;OS_CFG_ISR_POST_DEFERRED_EN为1,使用锁定调度器方式。
注:OS_CFG_ISR_POST_DEFERRED_EN在os_cfg.h文件中定义
4.有关保护临界段代码的宏定义的代码位于os.h文件中,87行 - 141行
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u // 延迟发布模式,采用锁定调度器方式
// 进入临界区
#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_ENTER_CPU_CRITICAL_EXIT() \
do { \
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)
#else // 直接发布模式,采用关中断方式
#define OS_CRITICAL_ENTER() CPU_CRITICAL_ENTER() // 进入临界区
#define OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT() // 进入临界区
#define OS_CRITICAL_EXIT() CPU_CRITICAL_EXIT() // 退出临界区
#define OS_CRITICAL_EXIT_NO_SCHED() CPU_CRITICAL_EXIT() // 退出临界区
#endif
5.再深入研究一下
#define CPU_INT_DIS() do { cpu_sr = CPU_SR_Save(); } while (0) // 保存CPU的状态寄存器并禁止中断
#define CPU_INT_EN() do { CPU_SR_Restore(cpu_sr); } while (0) // 恢复CPU状态寄存器的值
#ifdef CPU_CFG_INT_DIS_MEAS_EN // 允许计算中断关闭时间
// 禁止中断,并开启计算
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \
CPU_IntDisMeasStart(); } while (0)
// 使能中断,并停止计算
#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \
CPU_INT_EN(); } while (0)
#else // 禁止计算中断关闭时间
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0) // 禁止中断
#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0) // 使能中断
#endif
6.说明
上面的代码中涉及到计算中断关闭时间或锁定调度器时间的部分,这里不再做详细说明,以后用到之后再详细解释。
7.注意
在使用进入临界区和退出临界区的宏定义时,需要在使用前声明一个宏CPU_SR_ALLOC(),该宏的定义位于cpu.h文件中,295行 - 299行
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0 // 声明cpu_sr变量,临时存储CPU的状态寄存器的值
#else
#define CPU_SR_ALLOC()
#endif