冬天OS(八):加入调度

--------------------------------------------------------

调度初探

--------------------------------------------------------

上一节我们实现了从内核跳转到用户任务执行,这节我们实现时钟的调度...

 

一,测试时钟中断是否正常

运行:

——OK,时钟中断运行正常(0,0位置的字符在变幻)!

 

二,试图揭露调度的关键
在试图探索调度的关键之前,我们先要清楚一个问题:三个堆栈!第一个堆栈就是任务在运行时使用的低特权级堆栈,第二个堆栈是指向进程的进程表的堆栈,这个堆栈在用户进程进入时钟中断之后就设置了,我们可以称其为高特权级堆栈,第三个堆栈是内核堆栈,在进入调度程序之后,因为 sp0 指向进程的进程表,所以不能作为调度程序内使用的堆栈,此时使用调度程序重定向的堆栈!
 

ALIGN   16
hwint00:                
        ; ----
        ; so there is important!
        ; we save the old task's status!
        ; ----
        sub     esp, 4
        pushad
        push    ds
        push    es
        push    fs
        push    gs
        mov     dx, ss
        mov     ds, dx
        mov     es, dx
        
        ; ----
        ; important!
        ; change to kernel stack!
        ; ----
        mov     esp, StackTop

        push    clock_int_msg
        call    disp_str
        add     esp, 4

        mov     al, EOI
        out     INT_M_CTL, al
        
        ; ----
        ; imortant!
        ; back to process table stack!
        ; ----
        mov     esp, [p_proc_ready]

        ; ----
        ; important!
        ; set sp0 to new task!
        ; ----
        lea     eax, [esp + P_STACKTOP]
        mov     dword [tss + TSS3_S_SP0], eax

        ; ----
        ; important!
        ; load new task's status!
        ; ----
        pop     gs      ; ┓
        pop     fs      ; ┃
        pop     es      ; ┣ 恢复原寄存器值
        pop     ds      ; ┃
        popad           ; ┛
        add     esp, 4

        ; do switch!
        iretd

——这段节选代码做了 6 件事:
1,保存旧的(要被换下)进程的状态
2,切换内核态堆栈
3,调度程序内的动作(打印字符)
4,从内核堆栈恢复
5,设置 sp0 到新进程(要被换上)的进程表
6,iretd 指令调度新进程执行

——于是调度的关键就在于 5,6 ——5 来保存, 6 来调度!在调度一个进程执行之后,这个进程就要准备着在下一次调度的时候被换下,那时需要保存其状态!
 

运行:

因为字符的打印是有延时的,所以在延时的途中中断了很多次!

 

三,探讨中断重入
默认当进入中断后会关中断,因此默认情况下中断内部是不会发生中断的,但是我们要求中断内部可以发生中断,叫做中断的嵌套,遇到的问题就是上次中断没有结束下次中断又开始了,对于时钟中断而言,这将递归嵌套到死机,我们的解决办法是只有一个有效的时钟中断占用长时间的中断例程,其余嵌套的时钟中断立马结束!
 

ALIGN   16
hwint00:                
        ; ----
        ; so there is important!
        ; we save the old task's status!
        ; ----
        sub     esp, 4
        pushad
        push    ds
        push    es
        push    fs
        push    gs
        mov     dx, ss
        mov     ds, dx
        mov     es, dx

        mov     al, EOI         
        out     INT_M_CTL, al   

        ; if interrupt reenter? 
        inc     dword [k_reenter]
        cmp     dword [k_reenter], 0
        jne     .re_enter

        ; ----
        ; important!
        ; change to kernel stack!
        ; ----
        mov     esp, StackTop
        
        sti     

        push    clock_int_msg
        call    disp_str
        add     esp, 4

        push    1
        call    delay
        add     esp, 4

        ; ----
        ; imortant!
        ; back to process table stack!
        ; ----
        mov     esp, [p_proc_ready]

        ; ----
        ; important!
        ; set sp0 to new task!
        ; ----
        lea     eax, [esp + P_STACKTOP]
        mov     dword [tss + TSS3_S_SP0], eax
.re_enter:                              ; 如果(k_reenter != 0),会跳转到这里
        dec     dword [k_reenter]       ; k_reenter--;

        ; ----
        ; important!
        ; load new task's status!
        ; ----
        pop     gs      ; ┓
        pop     fs      ; ┃
        pop     es      ; ┣ 恢复原寄存器值
        pop     ds      ; ┃
        popad           ; ┛
        add     esp, 4

        ; do switch!
        iretd

这种解决嵌套的本质:

 

ALIGN   16
hwint00:                
        ; ----
        ; so there is important!
        ; we save the old task's status!
        ; ----
        sub     esp, 4
        pushad
        push    ds
        push    es
        push    fs
        push    gs
        mov     dx, ss
        mov     ds, dx
        mov     es, dx

        mov     al, EOI         
        out     INT_M_CTL, al   

        ; if interrupt reenter? 
        inc     dword [k_reenter]
        cmp     dword [k_reenter], 0
        jne     .re_enter

        ; ----
        ; important!
        ; change to kernel stack!
        ; ----
        mov     esp, StackTop
        
        sti     

        push    clock_int_msg
        call    disp_str
        add     esp, 4

        push    1
        call    delay
        add     esp, 4

        ; ----
        ; imortant!
        ; back to process table stack!
        ; ----
        mov     esp, [p_proc_ready]

        ; ----
        ; important!
        ; set sp0 to new task!
        ; ----
        lea     eax, [esp + P_STACKTOP]
        mov     dword [tss + TSS3_S_SP0], eax
.re_enter:                              ; 如果(k_reenter != 0),会跳转到这里
        dec     dword [k_reenter]       ; k_reenter--;

        push    1
        call delay
        add     esp, 4

        ; ----
        ; important!
        ; load new task's status!
        ; ----
        pop     gs      ; ┓
        pop     fs      ; ┃
        pop     es      ; ┣ 恢复原寄存器值
        pop     ds      ; ┃
        popad           ; ┛
        add     esp, 4

        ; do switch!
        iretd

我们修改一下上面的片段,发现不奏效了,因此关键在于如果是嵌套中断,要让他“快速”地结束,多快呢?在下一次嵌套来临之前要结束!


OK!我们已经认识了调度,知道了调度的关键点,下一节我们就引入多任务!
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柔弱胜刚强.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值