现在又出现了另外一个的问题,在中断处理过程中是否应该允许下一个中断发生?

让我们修改一下代码,以便让系统可以在时钟中断的处理过程中接受下一个时钟中断。这听起来不是个很好的主意,但是可以借此来做个试验。

首先,因为CPU在响应中断的过程中会自动关闭中断,我们需要人为地打开中断,加入sti指令;然后,为保证中断处理过程足够长,以至于在它完成之前就会有下一个中断产生,我们在中断处理例程中调用一个延迟函数。代码如下:

extern	delay

hwint00:		; Interrupt routine for irq 0 (the clock).
sub esp, 4
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx mov esp, StackTop ; 切到内核栈 inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符 mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259 sti push clock_int_msg
call disp_str
add esp, 4 push 1
call delay
add esp, 4 cli mov esp, [p_proc_ready] ; 离开内核栈 lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax pop gs ; `.
pop fs ; |
pop es ; | 恢复原寄存器值
pop ds ; |
popad ; /
add esp, 4 iretd

运行如下,在打印了一个A0x0之后就不停打印“^”,再也进不到进程里面:

之所以会产生这种情况,是因为在一次中断还未处理完时,又一次中断发生了。这时程序又跳到中断处理程序的开头,如此反复,永远也执行不到中断处理程序的结尾——跳回进程继续执行。

这个问题并不难解决,只要设置一个全局变量就可以了。这个全局变量有一个初值-1,当中断处理程序开始执行时它自加,结束时自减。在处理程序开头处这个变量需要被检查一下,如果值不是0(0=-1+1),则说明在一次中断未处理完之前就又发生了一次中断,这时直接跳到最后,结束中断处理程序的执行。当然,武断地结束新的中断并不是一个好的办法,这里我们姑且先这样来做。

PUBLIC int kernel_main()
{
...
k_reenter = -1;
...
}

然后在中断例程中加入k_reenter自加以及判断是否为0的代码:

extern	k_reenter

hwint00:		; Interrupt routine for irq 0 (the clock).
sub esp, 4
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符 mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259 inc dword [k_reenter]
cmp dword [k_reenter], 0
jne .re_enter mov esp, StackTop ; 切到内核栈 sti push clock_int_msg
call disp_str
add esp, 4 push 1
call delay
add esp, 4 cli mov esp, [p_proc_ready] ; 离开内核栈 lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax .re_enter: ; 如果(k_reenter != 0),会跳转到这里
dec dword [k_reenter]
pop gs ; `.
pop fs ; |
pop es ; | 恢复原寄存器值
pop ds ; |
popad ; /
add esp, 4 iretd

运行如下,可以看到,字符A和相应的数字又在不停出现了,这说明我们的修改生效了,而且,屏幕左上角的字母跳动速度不变还是以前一样快而字符“^”打印速度变慢许多,说明有很多时候程序在执行了inc byte [gs:0]之后并没有执行disp_str,这也说明中断重入的确发生了:

好了,我们已经有了一个办法来解决中断重入这个问题,那么注释掉刚才的打印字符以及Delay等语句:

hwint00:		; Interrupt routine for irq 0 (the clock).
sub esp, 4
pushad ; `.
push ds ; |
push es ; | 保存原寄存器值
push fs ; |
push gs ; /
mov dx, ss
mov ds, dx
mov es, dx inc byte [gs:0] ; 改变屏幕第 0 行, 第 0 列的字符 mov al, EOI ; `. reenable
out INT_M_CTL, al ; / master 8259 inc dword [k_reenter]
cmp dword [k_reenter], 0
jne .re_enter mov esp, StackTop ; 切到内核栈 sti push clock_int_msg
call disp_str
add esp, 4 ;;; push 1
;;; call delay
;;; add esp, 4 cli mov esp, [p_proc_ready] ; 离开内核栈 lea eax, [esp + P_STACKTOP]
mov dword [tss + TSS3_S_SP0], eax .re_enter: ; 如果(k_reenter != 0),会跳转到这里
dec dword [k_reenter]
pop gs ; `.
pop fs ; |
pop es ; | 恢复原寄存器值
pop ds ; |
popad ; /
add esp, 4 iretd

再次运行,字符“^”打印的速度又变快了,

源码

操作系统开发系列—13.c.进程之中断重入的更多相关文章

  1. 操作系统开发系列—13.b.进程之丰富中断处理程序

    首先打开时钟中断: out_byte(INT_M_CTLMASK, 0xFE); // Master 8259, OCW1. out_byte(INT_S_CTLMASK, 0xFF); // Sla ...

  2. 操作系统开发系列—13.a.进程 ●

    进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启 ...

  3. 操作系统开发系列—13.e.三进程

    我们再来添加一个任务,首先添加一个进程体: void TestC() { int i = 0x2000; while(1){ disp_str("C"); disp_int(i++ ...

  4. 操作系统开发系列—13.g.操作系统的系统调用 ●

    在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...

  5. 操作系统开发系列—13.h.延时操作

    计数器的工作原理是这样的:它有一个输入频率,在PC上是1193180HZ.在每一个时钟周期(CLK cycle),计数器值会减1,当减到0时,就会触发一个输出.由于计数器是16位的,所以最大值是655 ...

  6. 操作系统开发系列—13.d.多进程 ●

    进程此时不仅是在运行而已,它可以随时被中断,可以在中断处理程序完成之后被恢复.进程此时已经有了两种状态:运行和睡眠.我们已经具备了处理多个进程的能力,只需要让其中一个进程处在运行态,其余进程处在睡眠态 ...

  7. 操作系统开发系列—13.i.进程调度 ●

    上面的三个进程都是延迟相同的时间,让我们修改一下,尝试让它们延迟不同的时间. void TestA() { int i = 0; while (1) { disp_str("A." ...

  8. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  9. 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示

    1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...

随机推荐

  1. Redis 集群方案

    根据一些测试整理出来的一份方案(转自http://www.cnblogs.com/lulu/): 1. Redis 性能 对于redis 的一些简单测试,仅供参考: 测试环境:Redhat6.2 , ...

  2. ORLEANS REMOTE DEPLOYMENT

    Orleans Remote Deployment Table of Contents Overview: 1 Prerequisites. 2 Deployment Steps. 2 Orleans ...

  3. Type 'Insus.NET.PictureObject' in Assembly 'App_Code, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

    昨晚想实现一个功能,需要把一个对象存储于ViewState中去,但在运行时,出现下面的异常. Type 'Insus.NET.PictureObject' in Assembly 'App_Code, ...

  4. 循序渐进开发WinForm项目(6)--开发使用混合式Winform模块

    1.Winform数据访问模式定义 传统的Winform程序模块:用于传统的数据库通讯获取数据,这种方式获取数据,方便快捷,可以用于常规的业务系统的场景,用于单机版软件或者基于局域网内的业务系统软件. ...

  5. 【人在江湖飘,哪有不带刀】神器Jumony

    大神博客:http://www.cnblogs.com/Ivony/p/3447536.html 项目地址:https://github.com/Ivony/Jumony 1.安装Jumony包 在N ...

  6. 史上最全系列Android开发环境搭建

    一.安装JDK1.JDK下载打开网站http://www.oracle.com/technetwor ... nloads-1880260.html,选择相应的操作系统下载JDK 2.安装JDK本机是 ...

  7. WIN-CE系统架构

    WIN-CE 系统架构分为素部分:硬件层.OEM 层.操作系统层.应用层 http://hovertree.com/hvtart/bjae/oy9pqb94.htm 硬件层: 由CPU .存储器.I/ ...

  8. SQL SERVER与C#中数据类型的对应关系

    对应关系表 SQL Server2000 http://hovertree.com/menu/sqlserver/ C# CodeSmith 数据类型 取值范围 数据类型 取值范围 空值代替值 数据类 ...

  9. "Hello World!" for the NetBeans IDE

    "Hello World!" for the NetBeans IDE It's time to write your first application! These detai ...

  10. 查看SQL Server多实例的版本

    通过 select @@version 查看当前的 SQL Server 安装的版本: 结果返回的是 SQL Server 2008 R2 (SP1),可安装的明明是 SQL Server 2012  ...