临界资源保护
实现方法
- 禁用中断
__attribute__((used)) static inline uint32_t read_eflags (void){
uint32_t eflags;
ASM_V("pushf\n\tpop %%eax":"=a"(eflags));
return eflags;
}
__attribute__((used)) static inline void write_eflags (uint32_t eflags){
ASM_V("push %%eax\n\tpopf"::"a"(eflags));
}
EFLAGS的位9是IF位, 为1的时候开启中断, 0屏蔽中断
//临界区管理
irq_state_t irq_enter_protection (void){
//记录一下之前的中断是开启的还是关闭的
irq_state_t state = read_eflags();
state |= EFLAGS_IF;
irq_disable_global();
return state;
}
void irq_leave_protection (irq_state_t state){
//恢复之前的IF状态
state |= read_eflags();
write_eflags(state);
}
实际使用
//打印的时候串口是一个临界资源
void log_printf(const char * fmt, ...){
char str_buf[128];
va_list args;
//格式化处理
kernel_memset(str_buf, '\0', sizeof(str_buf));
va_start(args, fmt);
kernel_vsprintf(str_buf, fmt, args);
va_end(args);
const char *p = str_buf;
irq_state_t state = irq_enter_protection(); //进入临界
while(*p != '\0')
{
//等待串口忙标志
while((inb(COM1_PORT+ 5) & (1<<6))== 0);
outb(COM1_PORT, *p++);
}
//自动换行
outb(COM1_PORT, '\r');
outb(COM1_PORT, '\n');
irq_leave_protection(state);//退出临界区
}