代码的临界段指处理时不可分割的代码,一旦这部分代码开始执行,则不允许任何中断打断。为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而临界段代码执行完后要立即开中断。
同其他内核一样,uC/OS-II为了处理临界段代码,须关中断,处理完毕后,再开中端。关中断使得uC/OS-II能够避免同时有其他任务或中断服务进入临界段代码。
关中断的时间是实时内核的最重要的指标之一,因为这个指标影响用户系统对实时事件的响应特性。uC/OS-II努力使关中断时间降至最短,但就使用uC/OS-II而言,关中断的时间很大程度上取决于微处理器的结构以及编译器所生成代码的质量。
uC/OS-II定义2个宏来关中断和开中断,这两个宏分别是:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。这两个宏总是成对使用的,把临界段代码封包起来,如一下代码所列:
{
OS_ENTER_CRITICAL();
/* uC/OS-II临界段代码 */
OS_EXIT_CRITICAL();
}
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()可以用不同的方法实现,具体使用哪种方法,取决于用户打算移植到的处理器的结构和所用的C编译器。通过定义宏OS_CRITICAL_METHOD可以选择具体使用哪种方法。
OS_CRITICAL_METHOD == 1
第1种方法是以最简单的方式来实现这2个宏调用的:用处理器指令关中断完成OS_ENTER_CRITICAL(),用处理器开中断指令完成OS_EXIT_CRITICAL()。然而,这种方法有点小问题,如果调用uC/OS-II的功能函数时,中断是已经关掉的,则从uC/OS-II的函数放回时,中断就打开了。这种情况下用户往往希望从uC/OS-II的函数返回时中断任然是关掉的。在此情况下,这种实现方法就不妥当,但对一些特定的处理器或编译器,使用这种方法是唯一的选择。
OS_CRITICAL_METHOD == 2
第2种方法实现OS_ENTER_CRITICAL()是在堆栈中保存中断的开/关状态,然后再关中断。在实现OS_EXIT_CRITICAL()时,只需简单的从堆栈中弹出原来中断的开关状态即可。
#define OS_ENTER_CRITICAL() asm("PUSH PSW") \
asm("DI")
#define OS_EXIT_CRITICAL() asm("POP PSW")
如上代码所列,是在C代码行中插入汇编语句。这里用户需查阅所使用的编译器是否允许直接在C代码行中插入汇编语句。一些编译器对插入的行汇编代优化得并不好,上述方法也未必可行。
OS_CRITICAL_METHOD == 3
一些编译器提供了扩展功能,用户可以得到当前处理器状态字的值,并保存在C函数的局部变量中,这个变量可以用于恢复PSW,如一下程序所列:
#define OS_ENTER_CRITICAL() cpu_sr = get_processor_psw(); \
disable_interrupter();
#define OS_EXIT_CRITICAL() set_processor_psw(cpu_sr);