乍一看上去,我们的时钟中断程序已经挺完善的了,但有一个问题,我们应该允不允许中断重入呢?中断重入就是在一个中断程序执行过程中又被另一个中断打断,转而又去执行另一个中断程序。我们是应该允许这种情况的,因为在时钟中断中进行进程调度时我们还是希望接受键盘中断的,但我们又不希望因为中断重入而引起程序的错误。会引起什么错误呢?下面我们就来模拟一下这个错误。
由于我们的进程被打断进入中断程序时会自动关中断,所以我们先开中断。我们想让中断程序运行得足够久以至于能够被时钟中断再次打断,所以我们调用Delay函数,这样重入的度不断增加,控制权永远不会回到我们的进程中,而且内核堆栈迟早会溢出,产生异常进入13号中断处理程序,下面就来修改代码来模拟这个错误:
extern Delay
...
HW_Int_00:
;push 0;
;call IRQ_Handler
;add esp,4
;hlt
pushad
push ds
push es
push fs
push gs
mov dx,ss
mov ds,dx
mov es,dx
mov esp,Top_Of_Stack
mov al,20h
out 20h,al
sti
inc byte [gs:0]
mov eax,0dh
push eax
push Int_Msg
add esp,8
push 1
call Delay
add esp,4
cli
mov esp,[p_Resume_PCB]
lea eax,[esp + 68]
mov dword [tss + 4],eax
pop gs
pop fs
pop es
pop ds
popad
iretd
运行结果如图所示:
下面我们就来解决这个问题,就是设置一个全局变量Is_Reenter,初值设为-1,这个变量让中断程序知道自己是否出入中断重入状态。在中断程序中先自增1,然后判断是否等于0,如果不等于则粗暴的跳出中断程序,我们暂且先这么做吧:
先声明和定义这个全局变量:
- extern u32 Is_Reenter; /* in global.h */
- u32 Is_Reenter = -1; /* in global.c */
然后在时钟中断程序修改:
extern Is_Reenter
...
HW_Int_00:
;push 0;
;call IRQ_Handler
;add esp,4
;hlt
pushad
push ds
push es
push fs
push gs
mov dx,ss
mov ds,dx
mov es,dx
inc byte [gs:0]
mov al,20h
out 20h,al
inc dword [Is_Reenter]
cmp dword [Is_Reenter],0
jne .reenter
mov esp,Top_Of_Stack
sti
mov eax,0dh
push eax
push Int_Msg
add esp,8
push 1
call Delay
add esp,4
cli
mov esp,[p_Resume_PCB]
lea eax,[esp + 68]
mov dword [tss + 4],eax
.reenter:
dec dword [Is_Reenter]
pop gs
pop fs
pop es
pop ds
popad
iretd
运行得知,左上角字符的速度明显比进程打印的字符的速度快,原因是inc byte [gs:0]的执行次数比进程体的打印语句要频繁得多。如果注释掉调用Delay的代码,我们看到两者的速度又会一样了。中断重入的问题就算解决了,后面的目标是实现多进程,激动啊。。。