【第6章】中断重入

     乍一看上去,我们的时钟中断程序已经挺完善的了,但有一个问题,我们应该允不允许中断重入呢?中断重入就是在一个中断程序执行过程中又被另一个中断打断,转而又去执行另一个中断程序。我们是应该允许这种情况的,因为在时钟中断中进行进程调度时我们还是希望接受键盘中断的,但我们又不希望因为中断重入而引起程序的错误。会引起什么错误呢?下面我们就来模拟一下这个错误。   

      由于我们的进程被打断进入中断程序时会自动关中断,所以我们先开中断。我们想让中断程序运行得足够久以至于能够被时钟中断再次打断,所以我们调用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,如果不等于则粗暴的跳出中断程序,我们暂且先这么做吧:

     先声明和定义这个全局变量:

Code:
  1. extern u32 Is_Reenter;  /* in global.h */  
  2. 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的代码,我们看到两者的速度又会一样了。中断重入的问题就算解决了,后面的目标是实现多进程,激动啊。。。

没有更多推荐了,返回首页