熟悉ucos,或者读过Jean.J.Labrosse写过的ucos书籍的人,一定会知道ucos中著名的临界去管理宏:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。
同样是通过关中断来保护临界区,OS_ENTER_CRITICAL/OS_EXIT_CRITICAL一共实现了三种实现方式,如下所示:
cpp] view plaincopyprint?
- #if OS_CRITICAL_METHOD == 1
- #define OS_ENTER_CRITICAL() __asm__("cli")
- #define OS_EXIT_CRITICAL() __asm__("sti")
- #endif
- #if OS_CRITICAL_METHOD == 2
- #define OS_ENTER_CRITICAL() __asm__("pushf \n\t cli")
- #define OS_EXIT_CRITICAL() __asm__("popf")
- #endif
- #if OS_CRITICAL_METHOD == 3
- #define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR())
- #define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr))
- #endif
第一种方式,OS_ENTER_CRITICAL()简单地关中断,OS_EXIT_CRITICAL()简单地开中断。这种方式虽然简单高效,但无法满足嵌套的情况。如果有两层临界区保护,在退出内层临界区时就会开中断,使外层的临界区也失去保护。虽然ucos的内核写的足够好,没有明显嵌套临界区的情况,但谁也无法保证一定没有,无法保证今后没有,无法保证在附加的驱动或什么位置没有,所以基本上第一种方法是没有人用的。
第二种方式,OS_ENTER_CRITICAL()会在关中断前保存之前的标志寄存器内容到堆栈中,OS_EXIT_CRITICAL()从堆栈中恢复之前保存的状态。这样就允许了临界区嵌套的情况。但现在看来,这种方法还存在很大的问题,甚至会出现致命的漏洞。
在OS_CRITICAL_METHOD=2的情况下,假设有如下代码:
[cpp] view plaincopyprint?
- function_a()
- {
- int a=(1<<31);
- OS_ENTER_CRITICAL();
- function_b(a);
- OS_EXIT_CRITICAL();
- }
|