zyl910

优化技巧、硬件体系、图像处理、图形学、游戏编程、国际化与文本信息处理。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

File:      ThinkInt.txt
Name:      理解操作系统对中断的处理
Author:    zyl910
Blog:      http://blog.csdn.net/zyl910/
Version:   V1.01
Updata:    2006-6-20


  以前看《操作系统》时,总觉得书上说得太抽象,理解不了。但最近编写一个键盘处理的小程序时,慢慢的理解了操作系统对中断的处理的那些概念。

  本来我是使用 Int 16h 中断来接收键盘输入的,但是该方法不能很好的解析组合键,而且无法获知某个按键是否按下。所以后来我决定 挂接IRQ0、访问60h端口,自己解析扫描码来处理键盘输入。


一、中断时只接收数据

  最开始时为了研究扫描码,我在中断例程中用printf显示扫描码。但很快发现,会因printf带来的重入性问题导致程序出现许多莫名其妙的问题,而且在中断时占用太多时间会影响系统运行效率。
  于是我修改了设计,定义了一个扫描码队列,每次中断发生时向扫描码队列添加项目。然后在主函数循环检查扫描码队列,并进行处理。


二、系统分层

  最开始看到《操作系统》关于系统分层时总有点不太理解,觉得那是将简单的事情搞复杂。但是这次处理键盘扫描码时发现:必须分层!
  有两个原因。一是因为扫描码牵涉到底层细节,比如 Ex 是扩展按键前导字节,x表示后面有几个字节的数据,处理起来极其复杂。二是由于中断时修改了扫描码队列,所以访问扫描码队列必须关中断,如果老是直接访问扫描码队列会影响系统运行效率,甚至可能会导致中断丢失。

  最后觉得至少得分四层:
    扫描码队列:底层的键盘扫描码。
    键盘按键状态:记录每个键盘按键的状态。注意是指单独的按键,类似DirectInput的DK的按键处理。比如:方向键上与小键盘8是不同的按键。
    功能按键队列:解析按键功能含义,类似Windows的虚拟键码。比如:无论是方向键上,还是小键盘8都是指“上”这个功能。
    字符消息:字符消息是用于文本输入的,比如CapsLock、Shift用于切换字母大小写。为了支持多语言输入和输入法,建议使用DWord来存放31位Unicode编码。


三、内核线程

  有两种按键状态,一种是键盘按键状态,一种是输入按键状态。先前我们按队列方式实现的实际上是输入按键状态,表示当前输入队列环境下的的按键状态;而键盘按键状态是指当前键盘上的按键状态。
  比如当按下空格键时,空格键的扫描码进入扫描码队列。当程序分析扫描码队列时,肯定认为空格键时按下的,所以“输入按键状态”认为空格键处于按下状态。但是此时在键盘上的空格键很可能已经释放了,所以“键盘按键状态”认为空格键处于未按下状态。
  所以我们需要在中断后立即分析数据,以实现“键盘按键状态”。
  注意是8259发送EOI以通知中断事务结束的,所以我们可以在发送EOI后处理数据,然后再使用iret指令从中断例程中返回。
  在发送EOI后的数据操作代码是什么?就是所谓的内核线程。内核态与用户态的定义并不是那么绝对,我们可以这样定义——非中断时的操作为用户态,在中断例程中的操作为内核态。其实保护模式跟这个差不多的,只不过它有明确的“环”概念及权限保护机制。
  怎么解决内核线程重入问题呢,需要仔细设计。

变量:
bkbinkmd:处于键盘内核线程中

中断例程{
 取得按键扫描码
 向扫描码队列填充数据
 if (bkbinkmd) {
  发送EOI
  /* 仍然由内核线程处理数据 */
  iret
 }else{
  发送EOI
  bkbinkmd = TRUE
  call 键盘处理函数 //内核线程
  iret
 }
}


键盘处理函数{
 do{
  cli
   取走扫描码队列中的所有数据。假设数据长度为cbBuf
   if (cbBuf > 0) bkbinkmd = FALSE
  sti
  分析数据
 }while(cbBuf > 0) // 尝试重复,因为中断可能修改了数据
}

 

四、总结

  《操作系统》教材太过于浓缩,只讲设计思路,不讲设计细节。只有真正接触具体设计时,才能真正明白那些设计思路的作用。

 

 

 

Updata
~~~~~~
[V1.01]2006-6-20
重写“内核线程”部分

[V1.00]2006-6-17
基本内容

posted on 2006-06-26 21:23  zyl910  阅读(390)  评论(0编辑  收藏  举报