操作系统开发系列—13.c.进程之中断重入
现在又出现了另外一个的问题,在中断处理过程中是否应该允许下一个中断发生?
让我们修改一下代码,以便让系统可以在时钟中断的处理过程中接受下一个时钟中断。这听起来不是个很好的主意,但是可以借此来做个试验。
首先,因为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.进程之中断重入的更多相关文章
- 操作系统开发系列—13.b.进程之丰富中断处理程序
首先打开时钟中断: out_byte(INT_M_CTLMASK, 0xFE); // Master 8259, OCW1. out_byte(INT_S_CTLMASK, 0xFF); // Sla ...
- 操作系统开发系列—13.a.进程 ●
进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启 ...
- 操作系统开发系列—13.e.三进程
我们再来添加一个任务,首先添加一个进程体: void TestC() { int i = 0x2000; while(1){ disp_str("C"); disp_int(i++ ...
- 操作系统开发系列—13.g.操作系统的系统调用 ●
在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...
- 操作系统开发系列—13.h.延时操作
计数器的工作原理是这样的:它有一个输入频率,在PC上是1193180HZ.在每一个时钟周期(CLK cycle),计数器值会减1,当减到0时,就会触发一个输出.由于计数器是16位的,所以最大值是655 ...
- 操作系统开发系列—13.d.多进程 ●
进程此时不仅是在运行而已,它可以随时被中断,可以在中断处理程序完成之后被恢复.进程此时已经有了两种状态:运行和睡眠.我们已经具备了处理多个进程的能力,只需要让其中一个进程处在运行态,其余进程处在睡眠态 ...
- 操作系统开发系列—13.i.进程调度 ●
上面的三个进程都是延迟相同的时间,让我们修改一下,尝试让它们延迟不同的时间. void TestA() { int i = 0; while (1) { disp_str("A." ...
- java高并发系列 - 第12天JUC:ReentrantLock重入锁
java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...
- 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示
1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...
随机推荐
- WEB编程中获取src目录下的文件(没有src目录)
这种情况遇见的会比较多,像一个WEB工程,如果在src下面写了一个xml或者一些其它的文件,当工程发布到服务器时,web程序是在tomcat等服务器下运行这个程序的,这个时候,程序目录里面并没有src ...
- Azure ARM (4) 开始创建ARM Resource Group并创建存储账户
<Windows Azure Platform 系列文章目录> 好了,接下来我们开始创建Azure Resource Group. 1.我们先登录Azure New Portal,地址是: ...
- Elasticsearch集群配置以及REST API使用
ES安装与启动 在官网下载压缩包,解压后直接运行bin目录下的.bat文件即可.下载地址戳这里. ES配置集群 Elasticsearch配置集群很简单,只要配置一个集群的 名称 ,ES就会自动寻找并 ...
- postgres配置主从流复制
postgres主从流复制 postgres在9.0之后引入了主从的流复制机制,所谓流复制,就是从库通过tcp流从主库中同步相应的数据.postgres的主从看过一个视频,大概效率为3w多事务qps. ...
- 矢量Chart图表嵌入HTML5网络拓扑图的应用
使用 HT for Web (以下简称 HT)开发HTML5网络拓扑图的开发者有 Chart 需求的项目的时候,感觉很痛苦,HT 集成的 Chart 组件中,并不包含有坐标,在展现方面不是很直观,但是 ...
- 转[开发环境配置]在Ubuntu下配置舒服的Python开发环境
在Ubuntu下配置舒服的Python开发环境 Ubuntu 提供了一个良好的 Python 开发环境,但如果想使我们的开发效率最大化,还需要进行很多定制化的安装和配置.下面的是我们团队开发人员推荐的 ...
- Dapper学习 - Dapper的基本用法(二) - 存储过程/函数
上一篇貌似少介绍了自定义函数和存储过程, 因为这两个也可以使用查询的方式来实现功能, 这一篇就补上 一.自定义函数的创建和调用 (mysql的) Delimiter $$ drop function ...
- Socket接收大数据的方法
byte[] buffer = new byte[BufferSize]; int bytesRead; // 读取的字节数 MemoryStream msStream = new MemoryStr ...
- webservice MaxReceivedMessageSize :已超过传入消息(65536)的最大消息大小配额
在客户端的webconfig文件的webservice节点进行如下配置:(注:此处客户端为应用程序的config文件) <system.serviceModel> <bindings ...
- jQuery 3.0正式发布
jQuery 基金会刚刚发布了该 JavaScript 框架的 3.0 版本,并且首次抛弃了对老旧的 IE 浏览器的支持.jQuery 3.0 的工作始于 2014 年 10 月,其最初目标是在 2. ...