精华内容
下载资源
问答
  • _In_ PKSERVICE_ROUTINE ServiceRoutine, //中断处理例程 _In_opt_ PVOID ServiceContext, //中断处理例程的参数 _In_opt_ PKSPIN_LOCK SpinLock, //用于同步的自旋锁 _In_ ULONG Vector, //中断向量号,在PDO...
  • Shell接受处理信号

    千次阅读 2015-01-30 17:42:11
    Linux Shell接受处理信号trap指令 它有三种形式分别对应三种不同的信号回应方式.  第一种:  trap 'commands' signal-list  当脚本收到signal-list清单内列出的信号时,trap命令执行双引号中的命令.   第二种:  ...

    Linux Shell接受处理信号trap指令

    它有三种形式分别对应三种不同的信号回应方式.
     第一种:
      trap 'commands' signal-list
     当脚本收到signal-list清单内列出的信号时,trap命令执行双引号中的命令.
     
    第二种:
      trap signal-list
    trap不指定任何命令,接受信号的默认操作.默认操作是结束进程的运行.
     
    第三种:
      trap ' ' signal-list
     trap命令指定一个空命令串,允许忽视信号.


    NOTE:trap 对同种signal只能相应一种设定,如果在一个shell里面设置多个trap,如:
    trap   ' echo “aaaaaaaaaaa”  '  INT
    trap   ' echo “bbbbbbbbbbb”  '  INT
    那么它只会响应最后一个信号设定。


    信号处理(Signal Handling)在 Linux 编程中一直扮演者重要的角色,几乎每个系统工具都要用到它,最常见的功能莫过于用信号进行进程间通信(尤其是父子进程)以及捕捉SIGINT、SIGTERM之类的退出信号以做一些善后处理(cleanup)。C中自不必多说,可以使用 wait 族函数;而 shell 脚本中也有捕捉信号的 trap 功能——然而许多人在使用 trap 功能的时候却存在着这样那样的误解,这些看似无关紧要的小细节最后有可能使得你的脚本与你预想的行为完全不同。

    condition 中的信号到底应该如何书写?比如终端中断信号(一般用 CTRL-C 发出),到底是写 SIGINT 、 INT 还是2(大部分系统上该信号对应的信号数)?是大写还是小写?
     
    如果你使用最新版的 Bash ,那么这几种写法都可以。而如果你需要在不同 shell 中保持可移植性,请使用大写、不带前缀的 INT !根据 POSIX 标准, trap 的 condition 不应当加上 SIG 前缀,且必须全大写,允许带 SIG 前缀或小写是某些 shell 的扩展功能。而信号数在不同的系统上可能不同,所以也不是一个好主意。

    trap 可以根据你的需要放在脚本中的任何位置。脚本中也可以有多个 trap ,可以为不同的信号定义不同的行为,或是修改、删除已定义的 trap 。更进一步地, trap 也有作用范围,你可以把它放在函数中,它将只在这个函数里起效!

    如果当前正有一个外部命令在前台执行,那么 trap 会等待当前命令结束以后再处理信号队列中的信号。

    for file in $(ls)
    do
         trap 'echo "testing..." ; exit' INT
         echo "sleeping"
         sleep 2
    done
    


     

    信号分类

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

    名称       默认动作            说明
    SIGHUP   终止进程          终端线路挂断
    SIGINT   终止进程          中断进程
    SIGQUIT  建立CORE文件      终止进程,并且生成core文件
    SIGILL   建立CORE文件      非法指令
    SIGTRAP  建立CORE文件      跟踪自陷
    SIGBUS   建立CORE文件      总线错误
    SIGSEGV  建立CORE文件      段非法错误
    SIGFPE   建立CORE文件      浮点异常
    SIGIOT   建立CORE文件      执行I/O自陷
    SIGKILL  终止进程       杀死进程
    SIGPIPE  终止进程       向一个没有读进程的管道写数据
    SIGALARM 终止进程       计时器到时
    SIGTERM  终止进程       软件终止信号
    SIGSTOP  停止进程       非终端来的停止信号
    SIGTSTP  停止进程       终端来的停止信号
    SIGCONT  忽略信号       继续执行一个停止的进程
    SIGURG   忽略信号       I/O紧急信号
    SIGIO    忽略信号       描述符上可以进行I/O
    SIGCHLD  忽略信号       当子进程停止或退出时通知父进程
    SIGTTOU  停止进程       后台进程写终端
    SIGTTIN  停止进程       后台进程读终端
    SIGXGPU  终止进程       CPU时限超时
    SIGXFSZ  终止进程       文件长度过长
    SIGWINCH 忽略信号       窗口大小发生变化
    SIGPROF  终止进程       统计分布图用计时器到时
    SIGUSR1  终止进程       用户定义信号1
    SIGUSR2  终止进程       用户定义信号2
    SIGVTALRM  终止进程     虚拟计时器到时

     

    展开全文
  • shell浅谈之九子shell与进程处理

    万次阅读 多人点赞 2014-09-26 16:56:01
    一、简介 ...了解Bash Shell在多作业管理和进程处理方面的命名和机制有助于理解多用户、多作业的系统。 二、详解 1、子Shell (1)父子Shell是相对的,它描述了两个Shell进程的fork关系,父Shel...

    一、简介

          Linux是一种用户控制的多作业操作系统,系统允许多个系统用户同时提交作业,而一个系统用户又可能用多个shell登录,每个系统用户可以用一个shell提交多个作业。了解Bash Shell在多作业管理和进程处理方面的命名和机制有助于理解多用户、多作业的系统。

    二、详解

    1、子Shell

    (1)父子Shell是相对的,它描述了两个Shell进程的fork关系,父Shell指在控制终端或xterm窗口给出提示符的进程,子Shell是由父Shell创建的进程。父Shell创建子Shell调用的是fork函数。

          Shell命令可以分为内建命令(Shell本身执行的命令)和外部命令(fork创建出来的子shell执行的命名),内建命令不创建子Shell而外部命令创建子Shell。

    (2) 内建命令是包含在Shell工具包中的命令,其中保留字对Shell有特殊含义,保留字本身不是一个命令而是命令结构的一部分。

          冒号是Shell中一个特殊的符号,首先冒号可以表示永真(相当于TRUE关键字)如while :;do...done(while循环的条件始终为真);其次冒号可以清空一个文件,:>log将冒号重定向到文件,log文件内容被清空,所以:>命名是常用的清空文件的命令;接着冒号最重要的用法是:不做任何事,只做参数展开。

    (3)圆括号结构,能强制将其中的命令运行在子shell中,bash3后定义了内部变量BASH_SUBSHELL记录子shell的层次。

     

    #圆括号结构用法
    #!/bin/bash
    
    echo "Father Shell is: $BASH_SUBSHELL"      #打印父shell的层次,为0
    outervar=OUTER                              #父shell的变量outervar
    
    (                                           #利用圆括号结构创建子shell
    	echo "SubShell is: $BASH_SUBSHELL"        #子shell的层次为1
    	(
    		echo "GrandSubShell is: $BASH_SUBSHELL" #孙shell的层次为2
    	) 
    	innervar=INNER                            #子shell的变量
    	echo "innervar=$innervar"
    	echo "outervar=$outervar"                 #outervar继承了符shell所赋给它的值
    )                                           #回到父shell
    
    echo "Father Shell is: $BASH_SUBSHELL"   
    
    if [ -z "$innervar" ]                      #子shell中定义变量为空,则说明
    then
      echo "The \$innervar is not defined in main body."
    else
       echo "The \$innervar is defined in main body."
    fi


          innervar为空值,说明子shell中变量的作用域不能在父Shell中生效。在子shell中将变量export成环境变量,子shell对变量的更改仍然对父shell不可见。

     

          子shell是允许嵌套调用的,可以在函数或圆括号结构内再次调用圆括号结构创建子shell。

          子shell只能继承父shell的一些属性,而子shell不可能反过来改变父shell的属性。子shell能够从父shell继承得来的属性有:当前的工作目录、环境变量、标准输入输出和错误输出、所有已打开的文件描述符、忽略的信号。子shell不能从父shell继承得来的属性是:除了环境变量和.bashrc文件中定义变量之外的shell变量、未被忽略的信号处理。

           利用子shell测试变量是否已经定义的例子:

    #!/bin/bash
    
    if (set -u; : $var)  #冒号与$间有空格
    then 
      echo "Variable is set."
    fi

          其中set -u命令用于设置shell选项,u是nounset表示当使用未定义的变量时,输出错误信息并强制退出。: $var中冒号是不做任何事只是参数展开,若没有冒号则$var被解释成shell命令,shell试图去执行var变量的值。加上冒号,shell试图将var变量进行参数展开但不会试图去执行var变量的值。

     

           子shell还可以接收到父shell从管道传送过来的数据,例:cat /etc/passwd | (grep 'root'),使用管道符向子shell发送数据,符shell将cat的结果通过管道发送给子shell,子shell执行grep命令。

            shell应用将一个计算量较大的任务分成若干个小任务并行执行。

     

    #子shell用于并行计算的用法
    #!/bin/bash
    
    #用圆括号结构创建三个子shell同时执行
    (grep -r "root" /etc/* | sort > part1)       &       #与root关键字匹配的行,排序后输出到某文件
    (grep -r "root" /usr/local/* | sort > part2) &
    (grep -r "root" /lib/* | sort > part3)       &
    
    wait                                                 #等待后台执行的作业全部完成
    cat part1 part2 part3 | sort > parttotal
    echo "Run time of this script is:$SECONDS"           #输出该脚本执行时间

          grep -r递归搜索,搜索时的计算量比较大,对每个目录创建一个子shell进行并行处理,然后合并。每个圆括号之外有一个&符号,表示此命令放在后台执行,继续执行下一条命令;若无&符号则需要一条命令执行完毕后再执行下一条命令,就没真正实现并行计算。wait是一个内建命令,用于等待后台执行的作业全部完成后再执行下面的命令;若没有wait,脚本将三个子shell放在后台执行后直接执行合并临时文件的命令,三个子shell可能并未执行完毕,此时临时文件中的结果不完整,合并后也将产生不完整的结果。

     

     

    2、Shell的限制模式

     

           处于限制模式下的shell运行一个脚本或脚本片段,将会禁用一些命令或操作。shell的限制模式是Linux系统基于安全方面的考虑,目的为了限制脚本用户的权限,并尽可能地减小脚本所带来的危害。

           Shell的限制模式限制的操作有:用cd命令更改当前工作目录、更改重要的环境变量的值($PATH、$SHELL、$BASH_ENV、$ENV和$SHELLOPTS)、输出重定向符号(>、>>、>|、>&、<>和&>)、调用含有一个或多个斜杠的命令名称、使用内建命令exec、使用set+r等命令关闭限制模式。

     

    #正常模式和限制模式的区别
    #!/bin/bash
    
    echo "Changing current work directory" 
    cd /etc                                    #正常模式下改变当前工作目录
    echo "Now in $PWD"
    
    set -r                                     #shell选项使代码运行在限制模式下(r是restricted)
    echo "------IN RESTRICTED MODE---------"   #开始运行在限制模式下
    echo "Trying to change directory"
    cd /usr/local                              #cd命令出错,被限制了
    echo "\$SHELLOPTS=$SHELLOPTS"              #可以读取$SHELLOPTS变量的值
    echo "Now in `pwd`"                        #还是/etc为当前目录
    echo
    echo "Trying to change \$SHELL"
    SHELL="/bin/sh"                            #$SHELL变量在限制模式下只读
    echo "\$SHELL=$SHELL"              
    echo
    echo "Trying to redirect output to a file"
    who > outputnull                          #输出重定向失败,被限制了
    ls -l outputnull                          #outputnull没有被创建

        set -r开启shell的restricted选项进入限制模式,还有一种以限制模式运行脚本的方式,就是#!/bin/bash -r,-r表示在限制模式下运行该脚本。

     

     

    3、进程处理

    (1)进程角度看shell执行

    内建命令是由shell本身执行的命令,而外部命令则需要创建新的进程来执行。从进程角度归纳shell执行内建命令和外部命令的过程。

          当shell命令不是内建命令时,linux利用fork对一个子进程执行该命令,父进程处于等待状态。若该命令或脚本中包含编译过的可执行文件,则内核将新程序装载到内存,并覆盖子进程,执行结束退出子进程,父进程被重新激活开始读取shell的后一条命令。

          fork是系统调用,fork创建的子进程是父进程的副本,两个进程具有同样的环境、打开的文件、用户标志符、当前工作目录和信号等。

    (2)进程和作业

          作业是用户层面的概念,而进程是操作系统层面的概念。其区别:一个正在执行的进程称为作业,一个作业可以包含多个进程,用户提交作业到操作系统,作业的完成可能依赖于启动多个进程。

          进程的三种基本状态:

          作业号标识的是在该shell下运行的所有进程,而进程号就标识整个系统下正在运行的所有进程。

    其中[1]是作业号,7574是进程号。

    (3)作业控制

    作业是针对shell而言的,有前台运行和后台运行。内建命令fg可将后台运行的作业放到前台,而&符号使得作业在后台运行。

    fg可以指定作业的方法(Ctrl+Z组合键可将正在运行的作业阻塞):

           bg命令可将阻塞状态的作业转入后台运行。jobs查看作业列表。disown用于从shell的作业表中删除作业。wait命令用与等待后台作业完成。

    (4)信号

          信号是在软件层次上对中断机制的一种模拟,原理上一个进程收到一个信号与处理器收到一个中断请求是一样的。信号事件的来源:硬件来源(比如按下键盘或其他硬件故障)、软件来源(比如系统函数kill、raise、alarm、setitimer和sigqueue函数)。信号是进程间通信机制中唯一的异步通信机制。

          shell向进程发送信号大多通过Ctrl键加上一些功能键来实现。

           除了利用组合键发送信号外,内建命令kill可用于向进程发送TERM(即terminal)信号,功能和INT信号类似用于停止进程。kill可以通过进程号、作业号(kill  %n)或进程命令名想任何作业发送信号。kill $$杀掉自己本身的进程($$记录了运行该脚本的进程号),其中大于128的退出码表示脚本是被系统强行结束的。kill -l可看出,kill命令一共能发出64种信号。

    (5)trap命令

          trap是Linux的内建命令,用于捕捉信号,trap命令可以指定收到某种信号时所执行的命令。trap命令的格式如下:trap command sig1 sig2 ... sigN,当接收到sinN中任意一个信号时,执行command命令,command命令完成后继续接收到信号前的操作,直到脚本结束。

     

    #!/bin/bash
    
    trap "echo 'You hit Ctrl+c!'" INT
    
    while :; do
      let count=count+1
      echo "This is the $count sleep"
      sleep 5
    done

     

          利用trap命令捕捉INT信号(即与Ctrl+c绑定的中断信号)。trap还可以忽略某些信号,将command用空字符串代替即可,如trap "" TERM INT,忽略kill %n和Ctrl+c发送的信号(kill发送的是TERM信号)。LInux更强劲的杀死进程的命令:kill -9 进程号(或kill -9 %n作业号)等价与kill -KILL 进程号。

     (6)子shell的信号

    子shell能继承父shell所忽略的信号,但是不能继承父shell未忽略的信号。

    #!/bin/bash
    
    trap "" QUIT            #忽略kill -3信号,并且子shell能继承父shell所忽略的信号
    trap "echo 'You want to kill me'" TERM    #父shell处理的信号,子shell不能继承
    (                       #子shell,子进程号比父进程号大1
    	while :; do
    		let count=count+1
    		echo "This is the $count sleep"
    		sleep 5
    	done
    )

     

           父shell忽略QUIT信号但不忽略TERM信号,9987为父shell进程号9988为子shell进程号,kill -3 9987向父shell发送3信号和kill -3 9988向子shell发送3信号,均未退出,可以看出子shell对QUIT的忽略是从父shell继承而来的。

           kill 9987向父shell发送TERM信号,父shell仍存活(因处理了TERM信号),kill 9988向子shell发送TERM信号,子shell退出,随后父shell执行完毕结束。TERM信号能杀掉子shell,说明子shell不能继承父shel未忽略的信号。

          最后出现父shell响应TERM信号的输出,是因为子shell执行fork一个子进程后父shell处于等待状态,只有子shell退出后父shell才会被激活执行输出。

    三、总结

    (1)理解shell在多作业管理和进程处理方面的命名和机制,有助于控制和管理Linux中的进程和作业。

    (2)父shell和子shell的继承特性因充分了解,以及shell的限制模式。

    (3)有很多的细节问题还需不断的总结归纳。

    (3)在shell编程中不断强化其中的概念,进一步消化。

    展开全文
  • 中断处理程序!

    万次阅读 2011-11-19 11:20:55
    本章将深入到DOS系统内部探讨中断处理程序的内容。与其他计算机编程不一样,中断处理程序这个名词听起来就很难懂。用最简单的话来说,中断处理程序就是对应于中断激活的程序。  读者可能已发现,中断处理实际上并...
      
    
    本章将深入到DOS系统内部探讨中断处理程序的内容。与其他计算机编程不一样,中断处理程序这个名词听起来就很难懂。用最简单的话来说,中断处理程序就是对应于中断激活的程序。
        读者可能已发现,中断处理实际上并不是件很难办的事。事实上,在某些地方中断处理很容易管理。但是,其中仍然有些“黑洞”,一旦陷入便不能自拔。本章的信息可让你不致于迷失在黑洞中。
          人们谈论中断已有好多年了。当它第一次作为系统设计的主要部分而应用到计算机上时,它就获得了不安全的名声。在早期的计算机系统上,中断常常很令人头痛,因为那时程序员们没有处理它们的经验,并不公正地将它们视为捷径。
          长久以来,中断一直是系统程序员、各种硬件工程人员未攻克的难题,许多程序员对此是谈虎色变。幸好,PC机为处理中断提供了一个相对宽松的环境,如果你按照一些通用的准则编写中断处理程序的话,则你所遇到的问题也就迎刃而解。一旦你掌握了足够的经验,你就能够毫不费力地控制中断。
        本章首先介绍中断。除了讨论软件中产生的中断外,还讨论了内部和外部硬件产生的中断。在介绍这些之前,应该先考虑一下中断是怎样为你服务的。围绕着中断处理的讨论,本章还介绍了几个实际操作中的例子。
          了解了中断以后,本章还将回头接着谈上一章巳开始的话题——终止并驻留(TSR)程序。几乎每种TSR都按某种方式把自己与某一中断连接在一起,形成中断服务例程。本章将介绍制作好的TSR的方法,并在介绍读者不太熟悉或不大容易理解的内容时穿插一些实例。
        让我们先开始最基本的内容——探讨什么是中断。
                          11.1什么是中断
          “中断”是一种信号,它告诉处理器已发生了某件需要特别注意的事情。它用于让处理器集中注意力来处理某件重要的事情。如果没有中断,就必须周期性地查询每一设备,并检查设备上是否有所需要的东西。
          如果在一个查询系统上共有60种设备,并且每检查一种设备要用1秒钟,那么,每分钟内每台设备只能检查1次。若在这种情况需要更快速的响应,那么很显然,查询方法不适合。使用中断的原因就在于消除查询的需要,并延缓对外部事件的服务。
                                                                               
          例如,当磁盘驱动器发生信号,告诉系统它准备把一个信息扇区传送到主内存时,中断就会产生。如果处理器对中断的响应太慢,则此块被丢失,这样,强迫处理器把所进行的一切搁到一边,立即执行中断。
          上例中的这类中断是由外部事件产生的。内部事件也能产生中断,如计算机中出现被零除错误或程序发出指定的执行软件中断请求,包括广泛地用于每一虚拟DOS功能的
    Int 21h。
          无论计算机何时收到中断信息,它都会停下自己正在进行的一切,在程序中“标记它
    的位置”,并把控制权交给中断程序,然后,中断处理程序处理急待处理的事件,并随即返
    回。有些处理器只提供严格限制的中断标识,并依靠中断处理程序识别中断以及随后采取
    相应的处理措施。
          通过使用中断向量来缩短启用特定中断处理程序的时间,这样便可在处理器的8086
    系列上更有效地处理中断。一个中断向量就是一个指向实际处理程序例程的远指针(32
    位,采用偏移值:段格式);在8086系列里,RAM的头1024个字节专门用于提供256个处
    理器能识别的中断向量。
          为中断处理程序编程曾经是一种多少带点神秘色彩的艺术,很少有人知道它,在一些
    较旧的系统上知之者更是廖廖无几。在一些系统上,中断处理涉及精确的定时问题,以及
    处理器和计算机设计的错综复杂的知识,这些知识远远超出了经典的编程员们曾涉足过
    的范围。在能产生中断的系统上,多级中断出错是威协程序员们生存的祸根,因为查找错
    误的途径毫无规律可循,并且几乎不可能找到。
          然而,PC机上的中断相对来说要好处理得多,原因有两方面。一方面是因为PC类是
    单用户单进程的系统,另一方面其中断结构要完善得多。虽然小心谨慎是必不可少的,但
    可用这种标准的中断结构来处理下述情况的中断:
          1.当中断产生时,把处理器没有自动保存的一切内容保存起来(这意味着在处理程
    序的操作期间,PC机上的全部寄存器都可能会被改变;最安全的办法就是将它们全部保
    存起来,但CS、IP、SS和SP除外,可将它们压入堆栈)。
          2.禁止出现可能干涉处理程序操作的所有中断。
          3.允许在处理程序的操作期间可安全地出现的中断。
          4.处理中断。
          5.把保存的处理器寄存器恢复到步骤1。
          6.重新启用中断。
          7.返回到正常的进程。
          虽然这些信息不一定能处理好中断,但它的确能引导你小心地渡过难关。
          许多人曾遇到过这种情况——串行I/O,这种情况很难处理,除非把中断处理程序与
        串行端口连接在一起。Microsoft BASIC提供了一种用于通信的内部中断处理程序,该程
        序允许进行串行I/O操作。使用C语言、Pascal或汇编语言时,必须编写自己的处理程序。
          Ctrl-Break/Ctrl-C处理程序也是一种有用的中断处理程序,对许多程序而言,Ctrl-
    Break让它们处于一种糟糕的境地——不更新文件以及等等。要按正常的方式关闭此种

    259页
    程序,Ctrl-Break处理程序会让你的程序控制退出。
                      11.2中断的工作方式
        中断产生时,处理器可处于任何状态。处理器被设计成在响应中断之前,它总是能完
    成进程中的任何步骤。当处理器识别了中断时,它迅速作出响应:把标志寄存器(程序状态
    字)、指令指针(IP)和代码段寄存器(CS)压到堆栈上,并禁止中断。
        保存了关键机器状态信息之后,处理器在系统总线中查找一个8位数——中断请求
    级(IQR)。该级能准确地识别是哪一设备发出了中断,并让处理器知道用哪一向量作出响
    应。前面已解释过,中断向量是指向用于指定功能的实际处理程序例程的指针。
        8086 PC(和它的后续系列)把一个固定为8的偏移值加上中断的设备提供的数字来
    确定中断信号是否已发出。例如,IRQ 0级产生Int 08h,并且IRQ第7级产生Int 0Fh(在
    AT和PS/2设计中,把这一处理进行了修改,它们能识别超过8个的中断请求级,但原理
    仍然相同)。
        处理器把Int号乘以4来把其偏移值保存到中断向量表(interrupt vector table)中。然
    后查看段0000h以找到该向量。该向量的内容被置入CS : IP,并自动地控制处理中断的
    程序(中断处理程序)第一道指令的发出。
        在处理器使用中断处理程序期间,中断处理程序便控制着该处理器。大多数处理程序
    首先重新启用中断以便能服务于有更大优先权的中断。它们还保存它们使用的全部寄存
    器,然后尽快地执行它们自己的操作。对于有些设备,必须传送特殊的接收信号,以便让该
    设备知道它已被服务过。处理程序必须在需要的地方提供这种特殊信号。
        通常情况下,必须把中断处理程序尽可能地编写得既精简又快速,其中大多数是用汇
    编语言写成的,这样可消除所有多余的开销,并确保该程序尽可能快速地运行。也可以用
    C语言编写处理程序(本章列举了几个C语言的例子),但是必须用尽量少的开销来处理
    关键时间(time—critical)中断。
        通过8259A可编程的中断控制器(PIC)引发的中断(IRQ产生的硬件中断)必须在处
    理完毕时把一个终止中断的信号发送给PIC。中断处理完毕后,所有的中断处理程序都必
    须恢复机器的状态,具体步骤是先恢复全部保存的寄存器,然后执行中断返回(IRET)指
    令来把标志寄存器、CS和IP恢复到中断产生前的值。
                  11.3 Intel 8086系列的中断类型
        8086微处理器系列上的中断可分为三种基本类型。这一节将分别讨论这三种中断类
    型:
          ·内部硬件中断
          ·外部硬件中断
          ·软件中断

    260页
    11.3.1内部硬件中断
          在处理器中设计内部硬件中断是为了处理一些特殊的情况,诸如被零除出错或其它
    一些处理器已意识到出错的情况。这些情况列于表11.1中。
                                        表11.1内部硬件中断
                                        (a)8086处理器硬件中断
    中断级                  向里偏移值(地址)        含义
        00h                        00h                    被零除
        01h                        04h                    单步
        02h                        08h                    不可屏蔽中断
        03h                        0Ch                    断点
        04h                        10h                    溢出
    (b)80286处理器硬件中断
    中断级                  向里偏移值(地址)          含义
        05h                      14                     超出界限范围
        06h                      18h                    无效的操作码
        07h                      1Ch                    处理器扩展不可用
        08h                      20h                    双重异常
        09h                     2411                    段超限
        0Ah                      28h                    非法任务状态段
       0Bh                     2Ch                     不存在的段
        0Ch                      30h                    堆栈段超限
       0Dh                     34h                     通用保护故障
          不能把这些中断直接用于程序。在基本的PC机设计中,IBM重新安排了其中的一些
    中断(8086/80286的最初设计中没有用到,但出现在后来的扩展版本中)来处理其它的情
    况。在下代芯片(80186)问世时,冲突出现了,并且一直延续到今天,这种冲突源于8086系
    列芯片的设计与IBM对中断向量的使用。出现这种情况并不是什么好事,但我们必须处
    理它。表11.2列出了IBM指定的中断向量。比较表11.1和11.2,不难看出其中相冲突
    的地方。
    11.3.2外部硬件中断
          处理器可连接外部硬件中断来允许设备发出中断信号。早期大多数使用中断的微型
    计算机就是按这种方式建成的。有两种连接方式可用:不可屏蔽的中断(NMI)和可屏蔽
    的中断(INTR)。仅仅从名字上判断,应该可以关掉INTR,但不能切断NMI。
          当不想因为任何理由而终止中断时,可使用NMI中断。在一些系统上,把物理重设置
    开关以线接的方式连接上NMI中断,操作员便能获知处理器的全部动向。
          把INTR中断线接到8259A PIC中可利用芯片的优先列入功能,并可在软件控制下

    261页
    控制中断。处理器指令能直接允许和禁止中断,并且加给PIC的指令能有选择地允许和
    禁止中断。
        但是,中断是设置在硬件层上的。在某些产品中,生产厂商还设置了中断级,并且丝毫
    无法改变它们。一些设置提供开关或跳转程序,它们只能在有限范围值内重新设置中断
    级。
                            表11.2中断向量
    向量         行    为
    00h           被零除
    01h           单步
    02h           不可屏蔽中断
    03h           断点
    04h           溢出
    05h           打印屏幕
    06h           未使用
    07h           未使用
    08h           硬件IRQ0(计时器计时)
    09h           键盘输入中断
    0Ah           保留
    0Bh           异步端口控制卡1(COM2
    0Ch           异步端口控制卡0(COM1
    0Dh           硬盘控制卡
    0Eh           软盘控制卡
    0Fh           打印机控制卡
    10h         视频驱动程序
    11h           设备配置检查
    12h           内存大小检查
    13h           软盘/硬盘(PC/XT)
    14h           通信端口驱动程序
    15h           磁盘/网络服务
    16h           键盘驱动程序
    17h           打印机驱动程序
    18h             ROMBASIC
    19h           重启动系统
    1Ah           设置/读实时时钟
    1Bh          Ctrl-Break处理程序
    1Ch           计时器计时(用户定义)
    1Dh           视频参数表
    1Eh           磁盘参数表
    1Fh           图形字符表(字符80h-FFh)
    20h           程序终止
    21h            DOS功能调度程序
    22h           终止向量
    23h            Ctrl-C向量
    24h           关键出错向量
    25h           绝对磁盘读
    26h           绝对磁盘写
    27h           终止并驻留
    28h           DOSOK中断
    2Fh           多路复用中断(见参考手册部分)
    40h           软盘驱动程序(PC/XT)
    41h           硬盘参数表
    43h           图形字符表
    11.3.3软件中断
        软件中断是这样产生的:程序发出软件中断指令给处理器,使得处理器像接收到硬件
    中断一样采取行动。这种方法通常用来访问与程序无关的DOS和BIOS服务程序。根据
    需要,可把这两种服务程序链接到指定的中断上,然后改变它们,并丝毫不影响调用它们
    的应用程序。

    262页
                           11.4中断向量
            中断向量表被保存在系统内存中最低的1024个字节中,每个中断向量占用四个字
        节,一共有256个不同的中断向量。相应功能中断处理程序的偏移值和段地址组成了每个
        四字节的项。在有些情况下,向量也包含数据值表的地址,而不是程序的地址,如Int 1Fh
        所指的图形字符表。
                        11.5获取和设置中断向量
            有关中断向量的所有警告会让你警觉到中断量可能具有的任何影响都有其破坏性的
        一面。设想某一程序正在改变四字节中断向量中的两个字节,那么,需要使用正在改变的
        中断向量的另一进程的中断使正在执行的用户程序暂停,并使CPU跳转到一个未完成的
        向量地址上,从而可能在内存中的任何地方不可预知地中止。这种情况常常导致“挂起”你
        的计算机,有时甚至会冲掉你的硬盘。
            这一过程是如何实现的呢? DOS是一种单任务系统,一次只能进行一种操作。但是,
        对应于硬件中断的另一种中断服务例程会简单地采取控制并让你的程序半路上接通它。
        许多TSR在被激活时就获得了控制权,并在任务完成后把中断归还给它们的初始设置,
        这种情况确实可以出现。在编程过程中,任何实际将发生的事情都能够发生;问题只在于
        它发生得早或迟。
            更为重要的是向上兼容性的问题。直接修改中断向量与后来的DOS升级版本不兼容
        (如果把OS/2看作是一种升级的话,那么也包括它)。虽然目前已能直接进行修改,但绝
        对不能在多任务系统上进行。倒是DOS提供了改变一个中断向量的安全途径—使用
        Int 21h的功能25h(设置中断向量)和35h(获取中断向量)。
            1.使用功能35h来获取当前向量值,并把此值保存起来,留待以后在链接已使用中
        断的程序以及保存此中断时使用。
            2.使用功能25h来设置中断向量。
            这一过程简单地采用了汇编语言来编写(参见列表11.1)。
            列表11.1
                  ; GetSet.asm
                  ;----Get the Ctrl-C vector----
                      mov        ah, 35h         ;Get vector
                      mov        al , 23h        ;Ctrl-C
                      int        21h
                  mov      oldseg ,es   ; Store old vector
                  mov      oldoff,bx
              ;----Set the Ctrl-C vector----

    263页
           mov    ah,25         ;set vector
                mov      al,23h        ;Ctrl-C
                mov      dx , seg c_hand
                mov     ds,dX
                mov     dx,offset c_hand
          int 21h
        无须在DOS层上设置中断。可用的高级语言服务程序有助于清晰地设置中断,并消
    除它们在遇到问题时可能分散注意力。这些高级语言程序在执行Int 21h的功能25h和
    35h服务时显得更方便。
        Borland C/C++提供了两种函数—getvect()和setvect(),它们在不调用DOS功能
    的情况下,就能做到与DOS功能35h和25h一样的事情。在MicrosoftC/C++中,
    dos_getvect和_dos_setvect函数也执行同样的操作,而在Turbo Pascal中,执行这些操作
    的是GetlatVec和SetIntVec函数。
              11.6什么时候必须写一个中断处理程序
          在下述几种情况下,有必要创建自己的中断处理程序:
          ·必须捕获中断并防止程序在不正常情况下失败。编写商用程序时,决不能让用户在
            出现被零除错误或其它一些错误时“炸毁”于应用程序。应用程序必须处理出错。进一
          步地讲,若程序在执行任何“令它喜爱的”操作时,必须捕获Ctrl-C和Ctrl-Break事
          件,并处理它们,而不能让系统中断。
          ·必须链接到中断链中。在这方面的两个例子是:编写在某些固定击键上执行的TSR
          和编写希望在程序中用到的特殊定时程序。
          ·必须控制串行端口。前面曾提到,DOS并不为串行端口提供充足的服务。若想编写
            实际用的终端程序,那么,它必须具有中断驱动的、串行端口的服务例程。
          在除此之外的情况下,必须尽可能地用高级语言编写代码。如果能用高级语言编写中
    断处理程序的代码,那么无论如何都得这样作,除非该中断处理程序在程序中运行得不够
    快。用高级语言进行调试比用汇编语言要容易得多。若处理程序运行得不够快,可随时将
    它重新进行编码。
          只要有可能,应尽量使用高级语言函数来处理中断。Borland C/C++提供的ctrlbrk
    ()函数可用于从高级代码模式中设置Ctrl-C中断处理程序。Microsoft C/C++提供的
    UNIX兼容的signal()函数用于处理信号捕获。除了其它命令之外,QuickBASIC还提供了
    用于处理事件的ON KEY和TIMER命令。Turbo Pascal能处理那些有直接插入的汇编
    代码或使用Interrupt伪指令的中断。因此,应尽可能地选择能完成这项工作的高级语言。
          编写中断处理程序时,若无特殊的需要,一般不要使用DOS型的功能。DOS是不可
    重入的;若DOS在进行某件事时被中断,那么当再次调用DOS功能时,会很容易锁定系
    统。
          有一种方法可不调用DOS功能,即让中断处理程序做些设置进程的工作(例如把数

    264页
        据复制到缓冲区内)。中断处理程序可设置一种标志,当前正在使用系统去做其它处理的
        程序能识别此标志,从而可防止它可能去调用DOS功能。更透彻地讲,DOS用一些隐藏
        的方法来确定DOS调用在什么时候是安全的。那些花大量的时间去猜测别人是如何执行
    计算机技术的人已发现并公布了一些学习DOS所作的方法。
            首先,Int 21h功能(功能34h)通过ES:BX寄存器返回一个指针,该指针指向一个
        DOS忙碌标志,我们称此标志为InDOS标志。此标志是深藏在操作系统内核中的一个单
        字节。不管Int 21h功能何时启动,此标志都减去1;当这一功能终止时,该标志001。当该标
        志为0时,就表示没有执行任何DOS功能。
          无论什么时候按下TSR的热键,它都检查InDOS标志。若此标志非零,TSR在其自
        身内设置一热键标志。然后这样做的TSR连接时钟中断,并且每秒检查InDOS标志18.2
        次,直至该标志清除。当InDOS被清除而此热键标志还设置着的时候,TSR开始它自己的
        操作。
            这种处理虽然好,只是在命令处理器等待用户敲入命令行时,它让用户干等着。因为
        命令处理器使用DOS功能来进行命令行输入,在DOS等待字符时,InDOS标志已设置。
        很明显,DOS正处于安全的位置,如果不用这些DOS功能进行控制台I/O操作的话,那
        么,其它的操作就能中断DOS。为了允许控制台I/O操作的进行,DOS使用了另一种中断
    功能—28h,当控制冶输入程序在等待输入时,它们会重复地调用这一功能。这种中断
    为DOS空闲(或DOSOK)中断。
          DOS空闲中断通常执行中断返回(IRET),IRET返回控制权给控制台输入程序。如
    果将TSR链接上这种中断,并注意到热键标志已打开时,那么就可以立即执行TSR。
          使用中断时,应确保遵循这样一条规则——应一直假设可以调用其它程序。例如,绝
    对不能直接设置中断向量。Int 21h的功能25h就是用于这一目的的服务,并防止两种程
    序在设置中断向量时出现混淆。除非编写像Ctrl-C处理程序之类的内容,否则,必须保存
    初始的处理程序向量,并在完成进程时才能对它进行分支。也可以安装另一种需要激活的
    处理程序。若不遵守这种简单的规则,在实际操作中就会遇到麻烦。
        程序终止时,它必须清除它曾设置的所有中断处理程序(系统自动地清除关键出错和
    Ctrl-C处理程序)。例如,若编写终端程序,那么在终止此程序之前,必须恢复初始的中断
    处理程序,从而防止中断出现在处理程序所在的地方。若程序将设置常驻程序,则必须使
    用TSR终止,以便处理程序能永久地获得它所需的内存,并不致于被改写。
                    11.7编写Ctrl-C处理程序
          简单的Ctrl-C处理程序可作为中断处理的范例。该处理程序所表现出的几个阶段说
    明,有几种方法可处理中断问题。
          在第一个例子中,Borland C/C++使用ctrlbrk()函数来创建完全使用C语言的处理
    程序(见列表11.2)。Handle.c 允许中断正在进行的进程,并确定是否取消中断。因为ctrl-
    brk()函数处理异常中止,并根据对提示问题的回答返回适当的代码。这种编写程序的方
    法特别简单方便,因为它使用高级语言,编完就能用,并且不涉及太复杂的编程。更进一步

    265页
    讲,Borland C/C++显示出此程序可以使用longjmp(长跳转)和其它一些功能来直接与
    高层的程序发生交互作用。
        列表11.2
              /* handler.c
                  Listing 11.2 of DOS Programmer's Reference*/
              #include<stdlib.h>
              #include<stdio.h>
              #include<conio.h>
              #include<dos.h>
              #define         CR   0x0D
              #define         LF   0x0A
              int handler(void);
              void main()
              {
                  int      c;
                  int     i;
                  if(getcbrk()==0)
                      printf("BREAK checking is 0FF\n");
                  else
                      printf("BREAK checking is ON\n");
                  ctrlbrk(handler);
                  for(i=0;  i<250;  i++){
                      printf("%4.4d : Testing Ctrl-Break\n",i);
                  }
                  printf("\nCharacter input\n");
                  printf("press any key;  test Ctrl-Break\n");
                printf("if all else fails, press Esc to exit)\n\n");
              while((c=getche())!=27)
                  if(C==CR||c==LF)
                      putchar(LF);
            }
            handler()
            {
                int    c;
              printf("\nCtrl-Break handler\n");
              printf("Do you want to quit?");
              while((c=getch())!='y' && c!'Y'&& c!'n' && c!='N');
              printf("\n");
              return ((C=='Y'||c=='y':)?0:1));
            }
        Handler.c 做了两件事来允许你测试Ctrl-C处理:
        1.在屏幕上,它显示出可以用Ctrl-C或Ctrl-Break中断的250行重复内容。
        2.它接收键盘敲入的字符信息,这样,在键盘输入期间,可以使用ctrl-C或ctrl-
    Break。
        虽然汇编语言函数简单得多,但直接用汇编语言编码的函数使用起来几乎能使ctrl-
    brk()函数以假乱真。之所以必须使用汇编语言,是因为必须通过中断返回(JRET)而不是
    普通函数返回来完成处理程序。虽然可在此处理程序中来用直接插入码(嵌入式汇编),只
    是其效果没有采用汇编语言那么好。

    266页
          优秀的汇编语言编程人员能直接编写出中断处理程序,但是大多数人可能不知道怎
        样去拼凑出中断处理程序。要创建这种汇编语言程序,可从一道空的C程序开始,并把它
        编译成汇编语言源代码:
              set_brk()
              {
              }
              brk()
              {
              handler();
              }
          通过Borland C/C++,我们就可以这样来编译此代码:
              C>bcc.s set_brk.c
            获取汇编语言源码的过程列于列表11.3。
        列表11.3
                      ifndef ??version
          ?debug macro
                      endm
          publicdll macro name
                      public     name
                      endm
          $ comm      macro     name  ,dist, size,conunt
                      comm dist name:BYTE:count*size
                      endm
                      else
          $comm     macro     name,dist,size ,  count
                      comm      dist name [size]:BYTE : count
                      endm
                      endif
                      ?debug V  300h
                      ?debug S "set_brk.c"
                  ?debug C E9EC837A1A097365745F62726B2E63
          TEXT     segment byte public'CODE'
           _TEXT      ends
          DGROUP  group  _DATA,_BSS
                  assume  cs:_TEXT,ds :DGROUP
          DATA     segment word public 'DATA'
          d@    label    byte
          d@w  label word
           _DATA      ends
         _BSS    segment word public 'BSS'
          b@      label    byte
          b@w     label word
           _BSS      ends
         _TEXT     segment byte public 'CODE'
                            ;
              ;   set_brk()
                              ;
                      assume    CS:_TEXT
           _set_brk            proc        near
                      push       bp
                      nov       bp,sp
                              ;

    267页
          ;    {
          ;    }
                      ;
                pop       bp
                    ret
         _set_brk                 endp
                      ,
          ;    brk()
                      ;
                  assume    cs :_TEXT
         _brk    proc         near
                  push         bp
                  mov         bp,sp
                      ;
            ;  {
            ;       handler();
                      ;
                call     nearptr_handler
                      ;
            ;    }
                        ;
                pop       bp
                ret
       _brk    endp
                ?debug C E9
                ?debug C FA00000000
       _TEXT   ends
        DATA     segment word public 'DATA'
        s@      label      byte
       _DATA    ends
        TEXT     segment byte public 'CODE'
       _TEXT    ends
                extrn   _handler:near
                public   _brk
                public   _set_prk
       _s@      equ        s@
                end
        这个空的C程序(有时叫做NULL程序)产生了一种空例程,用它可建立中断处理程
    序。我们可能需要跋涉过C编译程序所插入的不重要信息(如调试信息),但是,如果对汇
    编语言不熟悉,则这类信息会节约一点时间。一些汇编语言“高手”也许会嘲笑这种方式,
    但专业化的程序员已多年利用这种方法来了解编译程序产生代码的方式,或者提供一种
    方式,用汇编语言重新编码某个功能,以便节省处理时间。
                                  建立汇编语言例程
            一本正经的汇编语言程序员可能害怕这种想法,但确实可以这样准备一个
        汇编语言例程:首先用高级语言如C编写一个例程,然后用可以产生汇编语言
        源代码的选项来编译该例程。列表11.3的实例中,开发时间已显著减少,因为该
        例程的骨架是从编译程序产生的。
          如果必须产生汇编语言程序或者如果想优化用高级语言编写的程序,那么
        这项技术是不错的。把程序转换成汇编码,并编辑所形成的文件,这可以在最小
        量的时间内提供一个工作程序。
    268页
          在Turbo Pascal 4.0及更高版本中,可以声明带有interrupt指令的程序为中断处理程
        序。编译程序自动操纵寄存器和IRET指令。该程序可保存所有寄存器;如果只需要保存
        几个,那么自己直接写的汇编代码可能更有效。
          列表11.4
       _TEXT       segment byte public 'code'
         _TEXT         ends
        DGROUP group  _DATA,_BSS
                assume CS:_TEXT , ds : DGROUP
        DATA     segment wordpublic'DATA'
        d@       label     byte
        d@w         label    word
         _DATA    ends
        _BSS       segment word public 'BSS'
        b@          label        byte
        b@w         label    word
         _BSS      ends
        _TEXT       segment byte public 'CODE'
                        ;
            ;  set_brk()
                          ;
                      assume       cs :_TEXT
       _set_brk          proc      near
                        ;
            ;    {
                    push      bp            ;save the registers
                    push       ds
                    push       di
                    push       si
                    mov        dx , CS
                    mov        ds , dX
                    mov        dx , offset_brk
                    mov        ah , 25h    ;Set interrupt vector
                    mov        al , 23h    ;Ctrl-C handler
                    int       21h
                    pop        si           ;Retrieve the registers
                    pop        di
                    pop        ds
                    pop        bp
                        ret
            ;  }
                        ;
       _set_brk          endp
                        ;
            ;    brk()
                        ;
                    assume cs :_TEXT
         _brk      proc         near
                  push       ax            ; Save the registers
                  push       bx
                  push       cx
                  push       dx
                  push       di
                  push       si
                  push       bp
                          ;
            ;    {
            ;        handler();
                          ;
                call      near ptr_handler

    269页
          ;
          ;    }
          ;
                pop     bp          ;Retrieve the registers
                      pop         si
                      pop          di
                      pop          dx
                      pop          cx
                      pop          bx
                      pop         aX
                      iret
         _brk    endp
          _TEXT     ends
        DATA     segment word public‘ DATA’
        s@      label   byte
         _DATA    ends
        TEXT     segment byte public'CODE'
          TEXT      ends
                    extrn     _handler:near
              public        _brk
                public_set_brk
       _s@      equ      s@
                end
        注意除编译程序提供的代码以外,没有清除别的代码;不过,它移动了调试码。一些附
    加的技巧已经被去掉(汇编语言编程高手会做到这一点),但这并非必不可少。唯一的要求
    是代码能工作。它做得到这一点。
        最后,修改的handler.c程序见列表11.5。
        列表11.5
            /* handler2.c
            Listing 11.5 of DOS Programmer's Reference*/
            #include<stdlib.h>
            #include<stdio.h>
            #include<conio.h>
            #include<dos.h>
            #define          CR     0x0D
            #define        LF    0x0A
            int  handler(void);
            void main()
            {
                void     set_brk(void);
                int      c;
                int      i;
                if(getcbrk()==0)
              printf("BREAK checking is OFF\n");
                else
                printf("BREAK checking is ON\n");
            set_brk();
            for(i=0; i<250; i++){
                printf("%4.4d:Testing Ctrl-Break\n", i) ;
              }

     
    2010-6-11 10:04:05 2#
    printf("\ncharacter input\n");
              printf("Press any key; test Ctrl-Break\n");
            printf("(if all else fails, press Esc to exit)\n\n");
              while((c=getche())!=27)
                  if(c==CR||c==LF)
                      putchar(LF);
            }
            handler()
            {
                int    c;
                printf("\nCtrl-Break handler\n");
                printf( "Do you want to quit?");
              while((c=getch())!='y' && c!='Y'  && c!='n' && c!='n');
                printf("\n");
                if(c=='y'||c=='y')
                  exit(0);
                return (0);
            }
          编译该程序,并把它连接到汇编语言例程上,这样就能产生一个可以工作的Ctrl-C
    处理程序。应该用下列命令行来使用BorlandC/C++编译程序来编译该程序:
            bcc handler2.c set_brk2.asm
                  11.8编写一个关键出错处理程序
          关键出错处理程序可能是我们能编写的最复杂的中断处理程序。错误出现时,DOS
    引入该程序并给用户某种能力决定越过这个问题还是中止程序。标准的DOS表示就是
    Abort,Retry,Fail?(退出,重试,失败)提示。程序员应将这个信息看作大祸临头,它不注意
    我们细心设计的屏幕,并且只略微注意已发生的事情。其实DOS已向关键出错处理程序
    提供有关已发生事情的大量信息。
          列表11.6中的代码是能综合进一个完全的应用程序中的TASM模型;它利用了这笔
    信息财富。
        列表11.6
          page55,132
            ;CritErr.asm
            ;functions for creating a pop- up critical error handler
          criterr_data      segment
          .MAXLIHES  equ 19
                oldcritErroffset                 dw   (?);Old critical error address
                oldCritErrSegment                   dw   (?)
                DeviceDriverHeaderoffset            dw   (?) ; Device driver address
                DeviceDriverHeaderSegment            dw   (?)
                ErrorCode                          dw   (?) ; Error code on entry
                Line                                 dw MAXLINES dup(?);Pointers tO menu lines
          、     ooS*3j oPVersion                    db   (?)  f DOSmajor versiOn
                10 Type                              db   (?) ; I/O type of error
                DriveNuntber                        db   (7) ;Which drive had error
                *enuLines                           db   (?) ;Number of lines on screen- 1
                Currentoption                        db   (?)  ;  Currently selected option

    271页
    MaximumOption     db (?) ; Number of valid options - 1
    ReturnCodes       dw (?) ; Pointer to list of valid return codes
    TopLine           db (?) ; Top line of window
    BottomLine         db (?) ; Bottom line of window
    LeftRow            db (?) ; Left line of window
    RightRow          db (?) ; Right line of window
    ActiveDisplaypage  db (?) ; Active display video page
    originalRow        db (?) ; Where cursor was
    originalColumn    db - l ? j ,
    set_2_       db 2
    Set23           db 2 , 3
    Set_12_         db 1 , 2
    Sett_123        db 1 , 2 , 3
    Set0_2_        db 0 , 2
    Set0_23        db 0 , 2 , 3
    Set012_        db 0 , 1 , 2
    Set0123        db 0 , 1 , 2 , 3
    ATTRIBUTE equ 17H ; WHITE ON BLUE
    TopMenu                db     "          Critical Error               "
    UnknownFunction        db     "          Unknown    DOS Function      "
    Fn_00                  db     "           Terminate Program Line      "
    fn_01                  db     "           keyboard Input With Echo    "
    fn_02                  db     "                Display Output         "
    fn_03                  db     "                 Auxiliary Input       "
    fn_04                  db     "               Auxiliary Output        "
    fn_05                  db     "           Printer Output              "
    fn_06                  db     "          Display Console I/O           "
    fn_07                  db     "          Direct STDIN Input           "
    fn_08                  db     "             STDIN Input               "
    fn_09                  db     "                Display String         "
    fn_0a                  db     "             Buffered STDIN Input      "
    fn_0b                  db     "          Check STDIN Status           "
    fn_0c                  db     "        Clear Buffer And Input         "
    fn_0d                  db     "                 Reset Disk            "
    fn_0e                  db     "             Select Disk               "
    fn_0f                  db     "                 Open File(FCB)        "
    fn_10                  db     "                Close File (FCB)       "
    fn_11                  db     "     earch For First Entry (FCB)       "
    fn_12                  db     "      Search For Next Entry (FCB)      "
    Fn_13                  db     "                 Delete File(FCB)      "
    Fn_14                  db     "       Read Sequential File(FCB)       "
    fn_15                  db     "     Write Sequential File (FCB)       "
    fn_16                  db      "     Create File (FCB)                "
    fn_17                  db     "             Rename File(FCB)          "
    fn_19                  db    "            Get Default Drive           "
    fn_1A                  db     "                Set DTA Address        "
    fn_1b                  db     " Get Allocation Table Information        "
    fn_1c                 db     " Get Allocation Table Information For Specific Drive "
    fn_1f                  db "     Get Default Disk Parameter Block       "
    fn_21              db "Random File Read (FCB)       "
    fn_22        db  "Random File Write (FCB)         "
    fn_23         db " Get File Size(FCB)          "
    fn_24        db " Set Random Record Field (FCB)        "
    fn_25      db   "Set Interrupt Vector          "
    fn_26            db "Create PSP              "
    fn_27        db "Random Block Read(FCB)            "
    fn_28         db  " Random Block Write(FCB)         "
    fn_29          db "Parse File Name           "
    fn_2A             db "Get System Date            "
    fn_2B          db "Set System Date               "272页
    Fn_3C db                "Get System Time"                              
    Fn_2D db                "Set system Time"                  
    Fn_2E db                "Set verify Flag"                  
    Fn_2F db                "Get DTA Address"                  
    Fn_30 db                "Get DOS Version Number"            
    Fn_31 db                "Terminate And stay Resident"      
    Fn_32 db                "Get Drive Parameter slock"         
    Fn_3300 db              "Get Ctrl-Break Flag"               
    Fn_3301 db              "Set Ctrl-Break Flag"               
    Fn_3305 db              "Get Boot Drive Code"               
    Fn_34 db                "Return Address of InDOS Flag"      
    Fn_35 db                "Get interrupt Vector"              
    Fn_36 db                "Get Free DiSk Space"               
    Fn_3700 db              "Get Switchchar"                    
    Fn_3701 db              "Set Switchchar"                    
    Fn_3702 db              "Read DeviCe AVailability"         
    Fn_3703 db              "set Device AVailability"           
    Fn_38 db                "Get Set Country information"      
    Fn_39 db                "Create Subdirectory"               
    Fn_3A db                "Remove Subdirectory"               
    Fn_3B db                "Set Directory"                     
    Fn_3C db                "Create Truncate File Handle"      
    Fn_3D db                "open File Handle"                  
    Fn_3E   db              "Close File Handle"                 
    Fn_3F db                "Read File or Device Handle"        
    Fn_40 db                "Write TO File or Device Handle"   
    Fn_41 db                "Delete File"                       
    Fn_42 db                "Move File Pointer"                 
    Fn_4300 db              "Get File Attributes"               
    Fn_4301 db              "Set File Attributes"               
    Fn_4400 db              "Get Device information"            
    Fn_4401 db              "Set Device information"            
    Fn_4402 db              "Device IOCTL Read"                 
    Fn_4403 db              "Device IOCTL Write"               
    Fn_4404 db              "Block Driver IOCTL Read"           
    Fn_4405 db              "Block Driver IOCTL Write"         
    Fn_4406 db              "Get input Status"                  
    Fn_4407 db              "Get output status"                 
    Fn_4408 db              "Block Device Removable"            
    Fn_4409 db              "Block Device Local"               
    Fn_440A db              "Handle Local"                     
    Fn_440B db              "Set Sharing Retry Count"           
    Fn_440C db              "Generic IOCTL Handles"            
    Fn_440D db              "Generic IOCTL Block Devices"      
    Fn_440E db              "Get Logical Drive Map"            
    Fn_440F db              "Set Logical Drive Map"            
    Fn_4410 db              "Query IOCTL Handle"               
    Fn_4411 db              "QUery IOCTL Device"               
    Fn_45 db                "Duplicate Handle"                  
    Fn_46 db                "Force Duplicate Handle"            
    Fn_47   db              "Get Current Directory"            
    Fn_48 db                "Allocate Memory"                  
    Fn_49 db                "Release Memory"                    
    Fn_4A db                "Modify Memory Allocation"         
    Fn_4B00 db              "Execute Program"                  
    Fn_4B01 db              "Load Program"                     
    Fn_4B03 db              "Load overlay"                     
    Fn_4B05 db              "Enter Exec State"                  
    Fn_4c db                "Terminate With Return Code"        
    Fn_4D db                "Get Return Code"                  
    Fn_4E db                "Search For First Match"            
    Fn_4F db                "Search For Next Match"            
    273页
    Fn_50 db              "Set PSP Segment "                                                                                                  
    Fn_51 db              "Get PSP Segment"                                                                                             
    Fn_52 db              "Get Disk LiSt"                                                                                               
    Fn_53 db              "Translate BPB To DPB"                                                                                       
    Fn_54 db              "Get Verify Flag"                                                                                             
    Fn_55 db              "create PSP"                                                                                                  
    Fn_56 db              "Rename File"                                                                                                
    Fn_5700 db            "Get File Date And Time"                                                                                      
    Fn_5701 db            "Set File Date And Time"                                                                                      
    Fn_5800 db            "Get Allocation Strategy"                                                                                    
    Fn_5801 db            "Set Allocation Strategy"                                                                                    
    Fn_5802 db            "Get UMB Link Status"                                                                                         
    Fn_5803 db            "set UMB Link"                                                                                                
    Fn_59 db              "Get Extended Error information"                                                                              
    Fn_5A db              "Create Uniquely Named File"                                                                                 
    Fn_SB db              "Create New File"                                                                                             
    Fn_5C00 db            "Set File Access Locks"                                                                                       
    Fn_5C01 db            "clear File Access Locks"                                                                                    
    Fn_5D00 db            "Copy Data TO DOS Save Area"                                                                                 
    Fn_5D06 db            "Get Critical Error Flag Address"                                                                             
    Fn_5D0A db            "Set Error Data Values"                                                                                       
    Fn_5E00 db            "Get Machine Name"                                                                                            
    Fn_5E01 db            "Set Machine Name"                                                                                            
    Fn_5E02 db            "Set Network Printer Setup"                                                                                   
    Fn_5E03 db            "Get Network Printer Setup"                                                                                   
    Fn_5F02 db            "Get Redirection LiSt Entry"                                                                                 
    Fn_5F03 db            "set Redirection LiSt Entry"                                                                                 
    Fn_5F04 db            "Cancel Redirection List Entry"                                                                              
    Fn_60 db              "Expand Path Name string"                                                                                    
    Fn_62 db              "Get PSP Address"                                                                                             
    Fn_6300 db            "Get system Lead Byte Table"                                                                                 
    Fn_6301 db            "Set/Clear Interim Console Flag"                                                                              
    Fn_6302 db            "Get Value of interim Console Flag"                                                                           
    Fn_64 db              "Set Current Country Byte"                                                                                    
    Fn_65   db            "Set Extended Country information"                                                                           
    Fn_6600 db            "Get Global Code Page"                                                                                       
    Fn_6602 db            "Set Global Code Page"                                                                                       
    Fn_67 db              "Set Handle Count"                                                                                            
    Fn_68 db              "Flush Buffer"                                                                                                
    Fn_6A db              "Extended open Create"                                                                                       
    Fn_6C db              "Error Code: Unknown"                                                                                         
    UnknownErrorCode db   "Error Code: Write Protect Error"                                                                             
    ErrorCOde00 db        "Error Code: Unknown Unit"                                                                                    
    ErrorCode01 db        "Error Code: Drive Not Ready"                                                                                 
    ErrorCode02 db        "Error Code: Unknown Command"                                                                                 
    ErrorCode03 db        "Error Code: Data Error"                                                                                      
    ErrorCode04 db        "Error Code: Bad Request Structure Length"                                                                    
    ErrorCode05 db        "Error Code: Seek Error"                                                                                      
    ErrorCode06  db       "Error Code: Unknown Media Type"                                                                              
    ErrorCode07 db        "Error Code: Sector Not Found"                                                                                
    ErrorCode08 db        "Error Code: Printer out Of Paper"                                                                           
    ErrorCode09 db        "Error Code: Write Fault"                                                                                    
    ErrorCode0A db        "Error Code: Read Fault"                                                                                      
    ErrorCode0B db        "Error Code: General Failure"                                                                                 
    ErrorCode0C db        "Error Code: Invalid Disk Change"                                                                             
    ErrorCode0F db        "AX = "                                                                                                      
    L2 db                 "0000 BX ="                                                                                                   
    L2AX db               "0000 CX = "                                                                                                  
    L2BX db               "0000 DX = "                                                                                                  
    L2CX db               "0000     "                                                                                                   
    L2DX db               DI = "                                                                                                        
    L3 db                 "0000 BP = "                                                                                                  
    L3DI db
    L3SI  db
    274页
    L3BP db "                         "00000 SP = "  
    L3SP db "                         "0000   "        
    L4   db "                         "        DS = "  
    L4DS db "                         "0000 ES = "      
    L4ES db "                         "0000 SS = "      
    L4SS db "                         "0000      "     
    L5   db "                         "CS : IP = "      
    LSCS db "                         "0000: "         
    L5IP db "                         "0000 Flags = "  
    LSFlags db "                      "------- "      
    L7_Char db "                      "Device:  "      
    L7_DeVice db "                                    
    L7_UnknownChar db "               "Unknown Character (?) Device            "  
    DiskError0  db "                  "Drive : Error Reading MS-DOS Area       "  
    DiskError1 db "                   "Drive : Error Writing MS-DOS Area       "  
    DiskError2  db "                 "Drive : Error Reading FAT               "  
    DiskError3 db "                   "Drive : Error Writing FAT               "  
    DiskError4   db "                 "Drive : Error Reading Root Directory    "  
    Diskerror5   db    "              "Drive : Error Writing Root Directory    "  
    DiskErrOr6 db "                   "Drive : Error Reading Files Area        "  
    DiskError7 db "                   "Drive : Error Writing Files Area        "  
    DRIVE_OFFSET equ 7                                                        
    Bridge2Line db "                                         
    EEC_01 db "                      "Extended Error Code Invalid Function Number     "                             
    EEC_02 db "                      "Extended Error Code File Not Found              "                           
    EEC_03 db "                      "Extended Error Code Path Not Found              "                              
    EEC_04 db "                      "Extended Error Code No Handles Available        "                                   
    EEC_05 db "                      "Extended Error Code Access Denied               "                                                               
    EEC_06 db "                      "Extended Error Code Invalid Handle              "                                                               
    EEC_07 db "                      "Extended Error Code Memory Ctrl Blocks Destroyed"                                                               
    EEC_08 db "                      "Extended Error Code Insufficient Memory         "                                                              
    EEC_09 db "                      "Extended Error Code Invalid Memory Block Address"                                                               
    EEC_0A db "                      "Extended Error Code Invalid Environment         "                                                               
    EEC_0B db "                      "Extended Error Code Invalid Format              "                                                                 
    EEC_0C db "                      "Extended Error Code Invalid Access Code         "                                                                 
    EEC_0D db "                      "Extended Error Code Invalid Data                "                                                               
    EEC_0F db "                      "Extended Error Code Invalid Drive               "                                                         
    EEC_10 db "                      "Extended Error Code Remove Current Directory    "                                                                 
    EEC_11 db "                      "Extended Eeror Code Not the Same Device         "                                                              
    EEC_12 db "                      "Extended Error Code No More Files               "                                                               
    EEC_13 db "                      "Extended Error Code Disk write - Protected      "                                                               
    EEC_14 db "                      "Extended Error Code Unknown Unit                "                                                                 
    EEC_15 db "                      "Extended Error Code Drive Not Ready             "                                                                 
    EEC_16 db "                      "Extended Error Code Unknown Command             "                                                                 
    EEC_17 db "                      "Extended Error Code CRC Error                   "                                                                 
    EEC_18 db "                      "Extended Error Code Bad Request Structure Length"                                                                  
    EEC_19 db "                      "Extended Error Code Seek Error                  "                                                               
    EEC_1A db "                      "Extended Error Code Unknown Media Type          "                                                               
    EEC_1B db "                      "Extended Error Code Sector Not Found            "                                                                 
    EEC_1C db "                      "Extended Error Code Out of Paper                "                                                                 
    EEC_1D db "                      "Extended Erroc Code Write Fault                 "                                                                 
    EEC_1E db "                      "Extended Error Code Read Fault                  "                                                                 
    EEC_1F db "                      "Extended Error Code General Failure             "                                                                 
    EEC_20 db "                      "Extended Error Code sharing violation           "                                                                 
    EEC_21 db "                      "Extended Error Code Lock Violation              "                                                                 
    EEC_22 db "                      "Extended Error Code Invalid Disk change         "                                                                 
    EEC_23 db "                      "Extended Error Code FCB Unavailable             "                                                                  
    EEC_24 db "                      "Extended Error Code Sharing Buffer overflow     "                                                               
    EEC_26 db "                      "Extended Error Code Can't Complete File operation"                                                               
    EEC_32 db "                      "Extended Error Code Network Request Not Supported"                                                               
    EEC_33 db "                      "Extended Error Code Remote Computer Not Listening                                                                 
    EEC_34 db "                      "Extended Error Code Duplicate Name on Netwirk    "                                                               
    EEC_35 db "                      "Extended Error Code Network Name Not Found       "                                          
    275页
    EEC_36 db         "Extended Error Code        Network Busy"                                                   
    EEC_37 db         "Extended Error Code        Network Device No Longer Exists"                                 
    EEC_38 db         "Extended Error Code        NetBIOS Command Limit  Exceeded"                                 
    EEC_39 db         "Extended Error Code        Network Adapter Error"                                          
    EEC_3A db         "Extended Error Code        Incorrect Network Response"                                      
    EEC_3B db         "Extended Error Code        Unexpected Network Error"                                       
    EEC_3c db         "Extended Error code        Incompatible Remote Adapter"                                    
    EEC_3D db         "Extended Error Code         Print Queue Full"                                                

    EEC_3E db         "Extended Error Code         NOt Enough Room For Print File"                                   
    EEC_3F db         "Extended Error Code         Print File Deleted"                                               
    EEC_40 db         "Extended Error Code         Network Name Deleted"                                             
    EEC_41 db         "Extended Error Code         Access Denied"                                                   
    EEC_42 db         "Extended Error Code         Network Device Type Incorrect"                                    
    EEC_43 db         "Extended Error Code         Network Name Not Found"                                          
    EEC_44 db         "Extended Error Code         Network Name Limit Exceeded"                                      
    EEC_45 db         "Extended Error Code         NetBIOS Session Limit Exceeded"                                   
    EEC_46 db         "Extended Error Code         Sharing Temporarily Paused"                                       
    EEC_47 db         "Extended Error Code         Network Request NOt Accepted"                                    
    EEC_48   db       "Extended Error Code         Print/DiSk Redirection Paused"                                    
    EEC_50 db         "Extended Error Code         File Already EXiSts"                                             
    EEC_52 db         "Extended Error Code         Cannot Make Directory Entry"                                      
    EEC_53 db         "Extended Error Code         Fail on int 24"                                                   
    EEC_54 db         "Extended Error Code         Too Many Redirections"                                            
    EEC_55 db         "Extended Error Code         Duplicate Redirection"                                            
    EEC_56 db         "Extended Error Code         Invalid Password"                                                
    EEC_57 db         "Extended Error Code         Invalid Parameter"                                                
    EEC_58 db         "Extended Error Code         Network Data Fault"                                               
    EEC_59 db         "Extended Error Code         Fn NOt supported By Network"                                      
    EEC_5A db         "Extended Error Code         Req'd Sys. Comp. Not installed"                                   
    EEC_Unknown db    "Error Class Code            Unknown"                                                         
    ECC_01 db         "Error Class Code            out of Resource"                                                  
    ECC_02 db         "Error Class Code            Temporary Situation"                                             
    ECC_03 db         "Error Class Code            Authorization"                                                   
    ECC_04 db         "Error Class Code            Internal"                                                         
    ECC_05 db         "Error Class Code            Hardware Failure"                                                
    ECC_06 db         "Error Class Code            System Failure"                                                   
    ECC_07 db         "Error Class Code            Application Program Error"                                       
    ECC_08 db         "Error Class Code            NOt Found"                                                        
    ECC_09 db         "Error Class Code            Bad Format"                                                      
    ECC_0A db         "Error Class Code            Locked"                                                           
    ECC_0B db         "Error Class Code            Media"                                                            
    ECC_0C db         "Error Class Code            Already Exists"                                                   
    ECC_Unknown db    "Recommended Action          Unknown"                                                         
    RAC_1 db          "Recommended Action          Retry Then Abort/Ignore"                                          
    RAC_2   db        "Recommended Action          Delay & Retry Then Abort/Ignore"                                 
    RAC_3 db          "Recommended Action          Get Correct Data From User"                                       
    RAC_4 db          "Recommended Action          Abort Application with cleanup"                                   
    RAC_5 db          "Recommended Action          Abort Without Cleanup Attempt"                                    
    RAC_6 db          "Recommended Action          Ignore Error"                                                     
    RAC_7 db          "Recommended Action          Correct Error Then Retry"                                       
    RAC_Unknown db    "Locus                       Unknown"                                                         
    LOCus_2 db        "Locus                       Block Device"                                                   
    Locus_3 db        "Locus                       Network"                                                         
    Locus_4 db        "Locus                       Serial Device"                                                   
    Locus_5 db        "Locus                      Memory Related"                                                  
    Locus_Unknown db                              "Unknown"                              
    Bridgeline  db
    Ignoreoption db        Ignore Error        
    Retryoption   db       Retry Function Call
    Terminateoption db     Terminate Program   
    FailCalloption db      Fail Function Call  
    BottomMenu db
    276页
    LINEWIDTH equ $-BottomMenu
    ScreenSave db(LINEWIDTH*MAXLINES*2)dup(?)
    MainTable dw Fn_00
    dw Fn_01
    dW Fn_02
    dW Fn_03
    dw Fn_04
    dw Fn_05
    dw Fn_06
    dw Fn_07
    dw Fn_08
    dw Fn_09
    dw Fn_0A
    dw Fn_0B
    dw Fn_0C
    dw Fn_0D
    dw Fn_0E
    dw Fn_0F
    dw Fn_10
    dw Fn_11
    dw Fn_12
    dw Fn_13
    dw Fn_14
    dw Fn_15
    dw Fn_16
    dw Fn_17
    dw UnknownFunction
    dw Fn_19
    dw Fn_1A
    dw Fn_1B
    dw Fn_1C
    dw UnknownFunction
    dw UnknownFunction
    dw Fn_1F
    dw UnknownFunction
    dw Fn_21
    dw Fn_22
    dw Fn_23
    dw Fn_24
    dw Fn_25
    dw Fn_26
    dw Fn_27
    dw Fn_28
    dw Fn_29
    dw Fn_2A
    dW Fn_2B
    dw Fn_2C
    dw Fn_2D
    dw Fn_2E
    dw Fn_2F
    dw Fn_30
    dw Fn_31
    dw Fn_32
    dw -1
    dw Fn_34
    dw Fn_35
    dw Fn_36
    dw -1
    dw Fn_38
    dw Fn_39
    dw Fn_3A
    dw Fn_3B
    dw Fn_3C
    277页
    dw Fn_3D
    dw Fn_3E
    dw Fn_3F
    dw Fn_40
    dw Fn_41
    dw Fn_42
    dW -1
    dW -1
    dw Fn_45
    dw Fn_46
    dw Fn_47
    dw Fn_48
    dw Fn_49
    dw Fn_4A
    dW -1
    dw Fn_4C
    dw Fn_4D
    dw Fn_4E
    dW Fn_4F
    dw Fn_50
    dw Fn_51
    dW Fn_52
    dw Fn_53
    dW Fn_54
    dw Fn_55
    dw Fn_56
    dW -1
    dW -1
    dW Fn_59
    dW Fn_5A
    dw Fn_5B
    dw -1
    dw -1
    dw -1
    dw -1
    dw Fn_60
    dw UnknownFunction
    dw Fn_62
    dw -1
    dw Fn_64
    dw Fn_65
    dW -1
    dw Fn_67
    dw Fn_68
    dw UnknownFunction
    dw Fn_6A
    dw UnknownFunction
    dw Fn_6C
    Table33 dw Fn_3300
    dw Fn_3301
    dw UnknownFunction
    dW UnknOWnFunction
    dw UnknownFunction
    dw Fn_3305
    Table37 dw Fn_3700
    dw Fn_3701
    dw Fn_3702
    dw Fn_3703
    Table43 dw Fn_4300
    dw Fn_4301
    Table44 dw Fn_4400
    dW Fn_4401
    278页
    dw Fn_4402
    dw Fn_4403
    dw Fn_4404
    dw Fn_4405
    dw Fn_4406
    dw Fn_4407
    dw Fn_4408
    dw Fn_4409
    dW Fn_440A
    dw Fn_440B
    dw Fn_440C
    dw Fn_440d
    dw Fn_440E
    dw Fn_440F
    dw Fn_4410
    dw Fn_4411
    Table4B dw Fn_4B00
    dW Fn_4B01
    dw UnknownFunction
    dw Fn_4b03
    dw UnknownFunction
    dw Fn_4B05
    Table57 dw Fn_5700
    dw Fn_5701
    Table58 dw Fn_5800
    dw Fn_5801
    dw Fn_5802
    dw Fn_5803
    Table5c dw Fn_5C00
    dw Fn_5C01
    Table5D dw Fn_5D00
    dw UnknownFunction
    dw UnknownFunction
    dw UnknownFunction
    dw UnknownFunction
    dw UnknownFunction
    dw Fn_5D06
    dw UnknownFunction
    dw UnknownFunction
    dw UnknownFunction
    dW Fn_5D0A
    Table5E dw Fn_5E00
    dw Fn_5E01
    dw Fn_5E02
    dw Fn_5E03
    Table5F dw UnknownFunction
    dw UnknownFunction
    dw Fn_5F02
    dw Fn_5F03 .
    dw Fn_5F04
    Table63 dW Fn_6300
    dw Fn_6301
    dw Fn_6302
    Table66 dw Fn_6600
    dw UnknownFunction
    dw Fn_6602
    ECTable dW ErrorCOde00
    dw ErrorCode01
    dw ErrorCode02
    dw ErrorCode03
    dw ErrorCode04
    dw ErrorCode05
    279页
    dw ErrorCode06
    dw ErrorCode07
    dw ErrorCode08
    dw ErrorCode09
    dw ErrorCode0A
    dw ErrorCode0B
    dw ErrorCode0C
    dw UnknownErrorCode
    dw UnknownErrorCode
    dw ErrorCode0F
    DiSkErrorTable dw DiSkErrOr0
    dw DiskError1
    dw DiskError2
    dw DiskError3
    dw DiSkError4
    dw DiskError5
    dw DiskError6
    dw DiskError7
    EEC_Table dw EEC_Unknown
    dw EEC_01
    dw EEC_02
    dw EEC_03
    dw EEC_04
    dw EEC_05
    dw EEC_06
    dw EEC_07
    dw EEC_08
    dw EEC_09
    dw EEC_0A
    dw EEC_0B
    dw EEC_0C
    dW EEC_0D
    dw EEC_Unknown
    dw EEC_0F
    dw EEC_10
    dw EEC_11
    dw EEC_12
    dW EEC_13
    dw EEC_14
    dw EEC_15
    dw EEC_16
    dW EEC_17
    dw EEC_18
    dw EEC_19
    dw EEC_1A
    dw EEC_1B
    dw EEC_1C
    dw EEC_1D
    dw EEC_1E
    dw EEC_1F
    dw EEC_20
    dw EEC_21
    dw EEC_22
    dw EEC_23
    dw EEC_24
    dw EEC_Unknown
    dw EEC_26
    dw EEC_Unknown
    dw EEC_UnknOwn
    dw EEC_UnknOwn
    dw EEC_Unknown
    dw EEC_Unknown
    280页
    dw EEC_Unknown
    dw EEC_UnknOwn
    dw EEC_UnknOWn
    dw EEC_Unknown
    dw EEC_Unknown
    dw EEC_Unknown
    dw EEC_32
    dw EEC_33
    dw EEC_34
    dw EEC_35
    dw EEC_36
    dw EEC_37
    dw EEC_38
    dw EEC_39
    dw EEC_3A
    dw EEC_3B
    dw EEC_3C
    dw EEC_3D
    dw EEC_3E
    dw EEC_3F
    dw EEC_40
    dw EEC_41
    dw EEC_42
    dw EEC_43
    dw EEC_44
    dw EEC_45
    dW EEC_46
    dw EEC_47
    dw EEC_48
    dw EEC_Unknown
    dw EEC_Unknown
    dw EEC_Unknown
    dw EEC_Unknown
    dw EEC_Unknown
    dw EEC_UnknOWn
    dw EEC_Unknown
    dw EEC_50
    dw EEC_Unknown
    dW EEC_52
    dw EEC_53
    dw EEC_54
    dw EEC_55
    dw EEC_56
    dw EEC_57
    dw EEC_58
    dw EEC_59
    dw EEC_5A
    ECC_Table dw ECC_Unknown
    dw ECC_01
    dw ECC_02
    dw ECC_03
    dw ECC_04
    dw ECC_05
    dw ECC_06
    dw ECC_07
    dw ECC_08
    dw ECC_09
    dw ECC_0A
    dw ECC_0B
    dw ECC_0C
    RAC_Table dw RAC_Unknown
    dw RAC_1
    281页
    dw RAC 2
    dw RAC 3
    dw RAC 4
    dw RAC 5
    dw RAC 6
    dW RAC 7
    Locus_Table dw Locus_Unknown
    dw Locus_Unknown
    dw Locus_2
    dw Locus_3 .
    dw Locus_4
    dw Locus_5
    criterr_data ends
    ; Stack structure in CritErr
    CE_CallerStack struc
    01dDS dw(?); DS on entry
    01dES dw(?); ES on entry
    01dBP dw(?); BP on entry
    01dSI dw(?); SI on entry
    01dDI dw(?); DI on entry
    01dBX dw(?); BX on entry
    01dCX dw(?); CX on entry
    01dDX dw(?); DX on entry
    Int21iP dw(?); Int 21 IP
    Int21CS dw(?); Int 21 cs
    Int21Flags dw(?); int 21 Flags
    UsersAX dw(?); Caller's AX
    UsersBX dw(?); Caller's BX
    UsersCX dw(?); Caller's CX
    UsersDX dw(?); Caller's DX
    UsersSI dw(?); Caller's Si
    UsersDI dw(?); Caller's Di
    UsersBP dw(?); Caller's BP
    UsersDS dw(?); Caller's DS
    UsersES dw(?); Caller's ES
    UsersIP dw(?); Caller's IP
    UsersCS dw(?); Caller's CS
    UsersFlags dw(?); Caller's Flags
    CE_CallerStack ends
    criterr_code segment
    assume CS: criterr code
    assume DS : nothing
    assume ES : nothing
    assume SS : nothing
    CritErr proc
    push DX ; Save registers
    push CX
    puSh BX
    puSh DI
    puSh si
    push BP
    push ES
    pUSh DS
    mov BX,seg criterr_data ; Set DS to local data
    mov DS,BX
    assume DS : Criterr data
    mov IO_Type,AH ; Save special values
    282页
    mov DriveNumber,AL
    mov ErrorCode,DI
    mov DeviceDriverHeaderSegment,BP
    mov DeviceDriverHeaderOffset,SI
    mov BP,SP,Let BP point to stack structure
    mov Line,offset DS:TOPMenu
    mov Line+2,offset DS:UnknownFunction
    mov AX,[BP-UsersAX]; Get caller's AX value
    cmp AH,6CH ; Out of knOwn range?
    jbe ValidFunction
    jmp DumpRegistersIsle
    ValidFunction:
    cmp AH,33H;Identify subfunction?
    jne NOt_Fn33
    jmp Fn33
    NOt_Fn33:
    cmp AH,37H
    jne Not_Fn37
    jmp Fn37
    NOt_Fn37:
    Cmp AH,43H
    jne Not_Fn43
    jmp Fn43
    Not_Fn43:
    cmp AH,44H
    jne NOt_Fn44
    jmp fn44
    NOt_Fn44:
    cmp AH,4BH
    jne NOt_Fn48
    jmp Fn4B
    NOt_Fn4B:
    cmp AH,57H
    jne NOt_Fn57
    jmp Fn57
    NOt_Fn57:
    cmp AH,58H
    jne NOt_Fn58
    jmp Fn58
    NOt_Fn58:
    cmp AH,5CH
    je Fn5C
    cmp AH,5DH
    je Fn5D
    cmp AH,5EH
    je Fn5E
    cmp AH,5FH
    je Fn5F
    cmp AH,63H -
    je Fn63
    cmp AH,66H
    je Fn66
    Shl AH,1;Double the index
    mov BL,AH ; Put in BX
    xor BH,BH
    mov AX,MainTable[BX]
    jmp SetFunction
    Fn66:
    cmp AL,02H;Undefined?
    ja DumpRegistersIsle
    Shl AL,1
    mov BL,AL
    xOr BH,BH
    283页
    mov AX,Table66[BX]
    jmp SetFunction
    Fn63:
    cmp AL,02H;Undefined?
    ja DumpRegistersIsle
    Shl AL,1
    mOv Si,AL
    XOr BH,BH
    mov AX,Table63[BX]
    jmp SetFunction
    Fn5F:
    cmp AL,04H;Undefined?
    ja DumpRegistersIsle
    Shl AL,1
    mov BL,AL
    xor BH,BH
    mov AX,Table5F[BX]
    Jmp SetFunction
    Fn5E:
    cmp AL,03H;Undefined?
    ja DumpRegistersIsle
    Shl AL,1
    mOv BL,AL
    XOr BH,bH
    mov AX,Table5E[BX]
    jmp SetFunction
    Fn5D:
    cmp AL,0AH ; Undefined?
    jbe Fn5D_1
    DumpRegistersIsle:
    jmp DumpRegisters
    Fn5D_1:
    Shl AL,1
    mOv BL,AL
    xor BH,BH
    mov AX,Table5D[BX]
    jmp short SetFunction
    Fn5C:
    cmp AL,01H ; Undefined?
    ja DumpRegisters
    Shl AL,1
    mOv BL,AL
    xOr BH,BH
    mov AX,Table5C[BX]
    jmp short SetFunction

     
    2010-6-11 10:06:20 3#
    Fn58:
    cmp AL,03H;Undefined?
    ja DumpRegisters
    shl AL,1
    mOv BL,AL
    xOr BH,BH
    mov AX,Table58[BX]
    jmp short SetFunction
    Fn57:
    cmp AL,01H ; Undefined?
    ja DumpRegisters
    Shl AL,1
    mOv BL,AL
    xOr BH,BH
    mov AX,Table57[BX]
    jmp short SetFunction
    Fn4B:
    cmp AL,05H ; Undefined?
    284页
    ja DumpRegisters
    Shl AL,1
    mOv BL,AL
    xOr BH,BH
    mov AX,Table4B[BX]
    jmp short SetFunction
    Fn44:
    cmp AL,11H;Undefined?
    ja DumpRegisters
    Shl AL,1
    mOv BL,AL
    xOr BH,BH
    mov AX,Table44[BX]
    jmp short SetFunction
    Fn43:
    cmp AL,01H;Undefined?
    ja DumpRegisters
    Shl AL,1
    mOv BL,AL
    xOr BH,BH
    mov AX,Table43[BX]
    jmp short SetFunction
    Fn37:
    cmp AL,03H;Undefined?
    ja DumpRegisters
    shl AL,1
    mOv BL,AL
    xor BH,BH
    mov AX,Table37[BX]
    jmp short SetFunction
    Fn33:
    cmp AL_05H ; Undefined?
    ja DumpRegisters
    shl AL,1
    mOv BL,AL
    xor BH,BH
    mov AX,Table33[BX]
    SetFunction:
    mov Line+2,AX
    DumpRegisters:
    mov BX,offset L2AX
    mov AX,[BP.UsersAX]
    call Fillword
    mOv BX,offset L2BX
    mov AX,[BP.UsersBX]
    call FillWOrd
    mov BX,offset L2CX
    mov AX,[BP.UsersCX]
    Call FillWOrd
    mOv BX,Offset L2DX
    mov AX,[BP.UsersDX]
    call FillWord
    mOv Line+4,offSet L2
    mOv BX,Offset L3DI
    mov AX,[BP.UsersDI]
    call FillWOrd
    mov BX,offset L3SI
    mov AX,[BP.UsersSI]
    call FillWOrd
    mOv BX,offset L3BP
    mov AX,[BP.UsersBP]
    call FillWord
    285页
    mov BX,offset L3SP
    mov AX,BP
    add AX,size CE_CallerStack
    call FillWord
    mov Line+6,offset L3
    mov BX,offset L4DS
    mov AX,[SP.UsersDS]
    call FillWord
    mov BX,offset L4ES
    mov AX,[BP.UsersES]
    call FillWOrd
    mov BX,Offset L4SS
    mov AX,SS
    call FillWord
    mov Line+8,offset L4
    mov BX,offset LSCS
    mov AX,[BP.UsersCS]
    call FillWord
    mov BX,offset L5IP
    mov AX,[BP.UsersIP]
    call FillWord
    mov BX,offset L5Flags
    mov AX,[BP.UsersFlags]
    teSt AX,0800H
    jz OF_Clear
    mOv byte ptr [BX],'O'
    OF_Clear:
    inc BX
    teSt AX,0400H
    jz DF_Clear
    mOv byte ptr[BX],'D'
    DF_Clear:
    inc BX
    teSt AX,0200H
    jZ IF_Clear
    mov byte ptr[BX],'I'
    IF_Clear:
    inc BX
    test AX,0100H
    ji TF_Clear
    mov byte ptr[BX],'T'
    TF_Clear:
    inc BX
    teSt AX,0080H
    jz SF_Clear
    mov byte ptr[BX],'S'
    SF_Clear:
    inc BX
    teSt AX,0040H
    jz ZF_Clear
    mOv byte ptr[BX],'Z'
    ZF_Clear:
    inc BX
    teSt AX,0010H
    jz AF_Clear
    mov byte ptr[BX],'A'
    AF_Clear:
    inc BX
    test AX,0004H
    jz PF_Clear
    mov byte ptr[BX],'P'
    286页
    PF_Clear:
    inc BX
    teSt AX,0001H
    jz CF_Clear
    mov byte ptr[BX],'C'
    CF_Clear:
    mov Line+10,offset L5
    mov AX,Offset UnknownErrorCode
    mov BX,ErrorCode
    xOr BH,BH
    cmp BX,0FH
    ja SetErrorCode
    Shl BX,1
    mov AX,ECTable[BX]
    SetErrorCode:
    mOv Line+12,AX
    test IO_Type,80H
    jz DiskError
    mov AX,DeviceDriverHeaderSegment
    mOv ES,AX
    mov BX,DeviceDriverHeaderOffset
    test wOrd ptr ES:[BX+4],8000H
    jz UnknownDevice
    push DS
    push ES
    mOv DS,AX
    lea SI,[BX+10]
    mov AX,seg criterr_data
    mov ES,AX
    mOv DI,offSet criterr_data7_Device
    mov CX,8
    cld
    rep movsb
    pop ES
    pop DS
    mOv Line+14,OffSet L7_Char
    jmp short SetBridge
    UnknownDeVice:
    mOv Line+14,offset L7_UnknownChar
    jmp short SetBridge
    DiskError:
    mov BL,IO_Type
    and BL,7
    xor BH,BH
    Shl BX,1
    mov BX,DiskErrorTable[BX]
    mov Line+14,BX
    mov AL,DriveNumber
    add AL,'A'
    mov [BX+DRIVE_OFFSET],AL
    SetBridge:
    mov Line+16,offset BridgeZLine
    push DS
    mov AH,59H
    xor BX,BX
    int 21H
    pOp DS
    mOv Line+18,Offset EEC_Unknown
    cmp AX,5AH
    ja NO_EEC
    puSh BX
    287页
    mov BX,AX
    shl BX,1
    mOv AX,EEC_Table[BX]
    pOp BX
    mov Line+18,AX
    No_EEC:
    mov Line+20,offset ECC_Unknown
    Cmp BH,0CH
    ja NO_ECC
    push BX
    mov BL,BH
    xor BH,BH
    Shl BX,1
    mov AX,ECC_Table[BX]
    mov Line+20,AX
    pop BX
    NO_ECC:
    mov Line+22,offSet RAC_Unknown
    cmp BL,7
    ja No_RAC
    xor BH,BH
    Shl BX,1
    mOV AX,RAC_Table[BX]
    mov Line+22,AX
    NO_RAC:
    mOv Line+24,offset Locus_Unknown
    cmp CH,5
    ja No_Locus
    mov BL,CH
    xOr BH,BH
    Shl BX,1
    mov AX,Locus_Table[BX]
    mOv Line+24,AX
    No_Locus:
    mov Line+26,OffSet BridgeLine
    cmp DOS_MajorVersion,2
    ja NOtARF
    jmD SetARF
    NOtARF:
    mov AL,IO_Type
    and AL,38H
    cmp AL,00H
    jne Notoption0
    mov Line+28,offset Terminateoption
    mov Line+30,offset BottomMenu
    mov MenuLines,15
    mov Maximumoption,0
    mov ReturnCOdes,offset Set__2_
    jmp DrawScreen
    NOtoption0:
    cmp AL,08H
    jne Notoption1
    mov Line+28,offset Terminateoption
    mov Line+30,offSet FaiLCalloption
    mov Line+32,offset BottomMenu
    mOv MenuLineS,16
    mov Maximumoption,1
    mov ReturnCodes,offset Set_23
    jmp DrawScreen
    NOtOptiOn1:
    cmp AL,10H
    288页
    jne Notoption2
    mov Line + 28,offset Retryoption
    mov Line + 30,Offset Terminateoption
    mov Line + 32,Offset BottomMenu
    mov MenuLines,16
    mov Maximumoption,1
    mov ReturnCodes,offset Set_12_
    jmp DrawScreen
    Notoption2 :
    cmp AL,18H
    jne NotOption3
    mov Line + 28,offset RetryOption
    mov Line + 30,offset Terminateoption
    mov Line + 32,offset FailCallOption
    mov Line + 34,offset BottomMenu
    mov MenuLines, 17
    mov MaximumOption,2
    mov ReturnCodes,offset Set_123
    jmp DrawScreen
    Notoption3 :
    cmp AL,20H
    jne Notoption4
    mov Line + 28,offset Ignoreoption
    mov Line + 30,offset TerminateOption
    mov Line + 32,Offset BottomMenu
    mov MenuLines,16
    mov MaximumOption,1
    mov   ReturnCodes,Offset Set0_2_
    jmp DrawScreen
    Notoption4 :
    cmp AL,28H
    jne Notoption5
    mov Line + 28,offset Ignoreoption
    mov Line + 30,Offset Terminateoption
    mov Line + 32,offset FailCallOption
    mov Line + 34,offset BottomMenu
    mov MenuLines, 17
    mov MaximumOption,2
    mov ReturnCodes,offset Set0_23
    jmp short DrawScreen
    NotOption5 :
    cmp AL,30H
    jne NotOption6
    SetARF :
    mov Line + 28,offset IgnoreOption
    mov Line + 30,offset RetryOption
    mov Line + 32,offset TerminateOption
    mov Line + 34,offset BottomMenu
    mov MenuLines, 17
    mov MaximumOption,2
    mov ReturnCodes,offset Set012_
    jmp short DrawScreen
    Notoption6 :
    mov Line + 28,offset Ignoreoption
    mov Line + 36,offset Retryoption
    mov Line + 32,offset Terminateoption
    mov Line + 34,offset FailCallOption
    mov Line + 36,offset BottomMenu
    mov MenuLines, 18
    mov Maximumoption,3
    mov ReturnCodes,offset Set0123
    289页
    Drawscreen :
    mov AX,0040H
    mov ES,AX
    mov AL ,ES:84H
    sub AL,MenuLines
    Shr AL,1
    mov TopLine,AL
    add AL,MenuLines
    mov BottomLine,AL
    mov AL,ES:4AH
    sub AL,LINEWIDTH
    shr AL,1
    mov LeftROw,AL
    add AL,LINEWIDTH - 1
    mov RightRow,AL
    mov AH,0FH ; Get current display mode
    int 10H
    mov ActiveDisplaypage,BH
    mov AH,3 ; Read cursor position and configuration
    int 10
    mov originalRow,DH
    mov originalColumn,DL
    mov SI,offset ScreenSave
    mov DI,Offset Line
    mov DH,TopLine
    outerLoop :
    mov DL,LeftRow
    InnerLoop :
    mov AH,2 ; Set cursor position
    int 10H
    mov AH,8 ; Read character and attribute
    int 10H
    mov [SI],AH
    inc SI
    mov [ SI ],AL
    inc sI
    mov AH,9 ; Write character and attribute
    push SI
    mov SI,DS:[ DI ]
    mov AL,[SI ]
    inc SI
    mov  DS:[ DI ],SI
    pop SI
    mov BL,ATTRIBUTE
    mov CX,1
    int 10H
    inc DL ; Next row
    Cmp DL,RightRow
    jbe innerLoop
    inc DI
    inc DI
    inc DH ; Next line
    cmp DH,BottomLine
    jbe outerLoop
    mov Currentoption,0
    mov AH,2 ; Set cursor position
    mov DH,TopLine
    add DH,14
    mov DL,LeftROw
    inc DL
    int 10H
    mov AH,9 ; Write character and attribute
    290页
    mov AL,10H
    mov BL,ATTRIBUTE
    mov CX,1
    int 10H
    GetKey :
    xor AH,AH ; Get keyboard character
    int 16H
    or AL,AL ; Character Code 0?
    jz Checkscancode
    cmp AL,13 ; Return?
    jne GetKey
    jmp Return
    CheckScanCode :
    cmp AH,47H ; Home?
    je  GoHome
    cmp AH,48H ; CursorUp?
    je GoUp
    cmp AH,49H ; PageUp?
    je Goup
    cmp AH,4BH ; CursorLeft?
    je GoUp
    cmp AH,4DH ; CursorRight?
    je GoDown
    cmp AH,4FH ; End?
    je GoEnd
    cmp AH,50H ; CursorDown?
    je GoDown
    cmp AH,51H ; PageDown?
    jne GetKey
    GoDown :
    mov AH,9 ; Write character and attribute
    mov AL,' '
    mov BL,ATTRIBUTE
    mov CX,1
    int 10H
    mov AL,Currentoption
    cmp AL,MaximumOption
    jne MoveDown
    xor AL,AL
    MoveCur sor :
    mov CurrentOption,AL
    mov AH,2
    mov BH,ActiveDisplaypage
    mov DH,TopLine
    add DH,14
    add DH,AL
    mov DL,LeftRow
    inc DL
    int 10H
    mov AH,9 ; Write character and attribute
    mov AL,10H
    mov BL,ATTRIBUTE
    mov CX,1
    int 10H
    jmp GetKey
    MoveDown :
    inc AL
    jmp MoveCursor
    GoHome :
    cmp Currentoption,0
    je GetKey
    mov AH,9 ; Write character and attribute
    mov  AL,' '

    291页
    mov BL,ATTRIBUTE
    mov CX,1
    int 10H
    xor AL,Al
    jmp MoveCursor
    GoUp :
    mov AH,9 ; Write character and attribute
    mov  AL,' '
    mov BL,ATTRIBUTE
    mov CX,1
    int 10H
    mov AL,Currentoption
    or AL , AL
    jnz MoveUp
    mov AL,MaximumOption
    jmp MoveCursor
    MoveUp :
    dec AL
    jmp MoveCursor
    GoEnd :
    mov AL,MaximumOption
    cmp AL,CurrentOption
    jne Eraseoption
    jmp GetKey
    Eraseoption :
    mov AH,9 ; Write character and attribute
    mov   AL,' '
    mov BL,ATTRIBUTE
    mov CX,1
    int 10H
    mov AL,Maximumoption
    jmp MoveCursor
    Return :
    mov SI,offset ScreenSave
    mov DH,TopLine
    OuterLoop2 :
    mov DL,LeftRow
    InnerLoop2 :
    mov AH,2 ; Set cursor position
    int 10H
    mov AH,9 ; Write character and attribute
    mov BH,ActiveDisplaypage
    mov BL,[ SI ]
    inc SI
    mov AL,[ SI ]
    inc SI
    mov CX,1
    int 10H
    inc DL , Next row
    cmp DL,RightRow
    jbe InnerLoop2
    inc DI
    inc DI
    inc DH ; Next line
    cmp DH,BottomLine
    jbe outerLoop2
    mov AH,2
    mov BH,ActiveDisplaypage
    mov DH,originalRow
    mov DL,originalColumn
    int 10H
    mov AL,Currentoption
    xor AH,AH

    292页
    mov BX,ReturnCodes
    add BX,AX
    mov AL,[ BX ]
    pop DS ; Restore registers
    pop ES
    pop SP
    pop SI
    pop DI
    pop BX
    pop CX
    pop DX
    iret ; interrupt return
    CritErr    endp
    assume DS : criterr_data
    FillWord proc near
    xChg AH ,AL
    call FillByte
    xchg AH ,AL
    call FillByte
    ret
    Fillword  endp
    FillByte proc near
    push CX
    push AX
    mov   CL,4
    Shr AL,CL
    call FillNibble
    pop AX
    Call FillNibble
    pop CX
    ret
    FillByte    endp
    FillNibble proc near
    push AX
    and AL,0FH
    Cmp AL,9
    jbe FillNibble_1
    add AL,7
    FillNibble_1 :
    add AL,'0'
    mov [BX ],AL
    inc BX
    pop AX
    ret
    FillNibble endp
    assume DS : nothing
    assume ES : nothing
    assume SS : nothing
    ; Install the new critical error handler
    _CritErrInit proc far
    push DS ; Save old registers
    push ES
    push AX
    push BX
    push cx
    push DX
    mov AX,Seg criterr_data
    mov DS,AX ; Set DS to local data

    293页
    assume DS: criterr_data
    mov AH,30H ; Get DOS version
    int 21H
    mov DOS_MajorVersion,AL
    mov AH,35H ; Get old critical error handler address
    mov AL,24H
    int 21H
    mov 01dCritErroffset,BX
    mov 01dCritErrSegment,ES
    mov AH,25H ; Set new critical error handler address
    mov AL,24H
    mov DX,seg criterr_code
    mov DS,DX
    mov DX,offset CS:CritErr
    int 21H
    pop DX ; Restore old registers
    pop cx
    pop BX
    pop AX
    pop ES
    pop DS
    ret  ; Return to Caller
    _CritErrInit    endp
    assume DS : nothing
    ; Reinstall the critical error handler (as after
    ; returning from a DOS shell)
    _CritErrReInit proc far
    push DS ; Save old registers
    push AX
    push DX
    mov AH,25H ;  Set new critical error handler address
    mov AL,24H
    mov DX,seg criterr_code
    mov DS,DX
    mov DX,offSet CS:CritErr
    int 21H
    pop DX ; Restore old registers
    pop AX
    pop DS
    ret ; Return to caller
    _CritErrReInit endp
    ; Uninstall the critical error handler (as before,
    ; invoking a DOS shell)
    _CritErrUnInit proc far
    push DS ; Save old registers
    push AX
    push DX
    mov AX,seg criterr_data
    mov DS,AX ; Set DS to local data
    assume DS : criterr_data
    mov AX,01dCritErroffset
    mov DX,01dCritErrSegment
    mov DS , DX
    assume DS : nothing
    294页
                  mov AH,25H;   Set old critical error handler address
                  mov AL,24H
                        int    21H
                  pop DX;         Restore old registers
                  pop AX
                  pop DS
                  ret;            Return to caller
        一CritErrUnInit endp
        public     CritErrInit
        public     CritErrReInit
        public     CritEPrUnInit
        criterr_code         ends
                      end
          我们已了解了有关中断的一些情况,并了解了TSR的激活方式,接下来让我们看看
        TSR的工作方式。
                            11.9TSR综述
          起初,人们试图f使TsR成为一个便利的方式,允许程序自我初始化并链接到系统中
    断结构中,从而将TSR加到DOs上。有人曾经希望那些整理、搜寻和执行其他实用程序
    功能的服务例程能像通常的功能那么使用——并且有很好的理由说明这种设想是可行
        的。
          DOS最初进入市场时,操作系统如CP/M和TRSDOS没有TSR功能。但程序员已发
    现建立实用程序并把它们储存在存储器中以备其它程序使用的方式。那时许多带有整理
    实用程序、显示控制实用程序和程序员编程工具包都投入使用;看起来MS-DOS设计
    者很赞赏这些程序包,并想简化建立这些实用程序的过程。
          用户获得DOS的经验以后,他们知道能把中断服务例程结合到键盘中断之中,然后
    看看所发生的事情。因为《PC技术参考手册》的早期版本包括一个ROM BIOS清单,所以
    很容易看到这些事情的工作方式,以及链接到键盘中断之上所带来的效果。在PC机上,
    用户看不到任何效果;而对于TSR,就是另外一回事了。
          TSR链接到键盘中断之上时,它不再是一个被动的TSR。它变得活跃了,因为它能依
    据自己的意愿来决定做事情的时间;一个活动TSR能显示它自己的存在。
          被动TSR会静静地呆在内存中,并且只在程序传递某个特定服务请求时才发生反
    应。这类TSR易于编写,因为不需特殊的编码技巧。调用TSR时会知道DOS并非活跃
    的,因为引入了中断的应用程序不得不控制机器。在这种情况下,机器能做的任何事情都
    是合法的。但那会与活动的TSR一起停止。
          活动TSR能在任何时候中断机器。TSR获得控制时,不可能知道机器所执行的内
    容。DOS和PC都设计成单用户、单任务系统,所以没有规定一个人可能同时运行多个程
    序。于是BIOS和DOS在全局表中贮存大量信息。数据项和计算的中间结果都使用相同
    的缓冲区。中断系统时,控制可能在DOS内部。然后如果再次调用DOS,就会失去DOS正
    在做的事情并可能损坏系统。

    295页
          早期TSR总是不断地导致系统损坏。它们不仅干扰DOS而且还相互干扰。一些
    TSR在控制机器时就像硬汉那样顽固。人们辛苦得到的经验形成了编写TSR的非正式
    规则:
          ·从不调用DOS功能,除非没有别的方式来获得所需的内容(文件系统访问是不调
          用DOS的主要原因)。                                             !
          ·如果必须完成I/O,那么可按下述方式进行:
              利用DOS控制台I/O功能(Int 21h,功能01h~0Ch)以外的功能。使用利用控
          制台的更好方式。
              处理InDOS标记。如果该标记非零,那么DOS正在执行一个Int 21h功能。此
          时不要运行自己的程序(参见“DOS参考手册”一章中讨论Int 21h的功能34h的内
          容,以及访问该标记的方式
              处理Int 28h。该中断会告知即使DOS在执行Int 21h功能,它也正在“忙着等
          待”控制台I/O。如果在DOS之下完成自己的控制台I/O,就能安全地执行任何其
          它的内容(参见第五部分“DOS参考手册”一章中的Int 28h)。
              提供一项检查功能让TSR指示它自己是否已安装。链接未用的中断向量,让
          TSR检查内存中TSR早期拷贝存在与否,但这样做充满危险,因为机器只有有限
          的向量。但若链接到DOS为它自己的TSR(PRINT、APPEND、SHARE等)使用而
          提供的Multiplex(多路复用)中断链上就会安全得多。可参考附录C,“标准的TSR
          识别技术”,那里介绍了使用多路复用中断2Fh来识别TSR的标准化方法。
              将一个符号放进可执行的代码内部告知TSR是否存在。
              总是假定存在其它TSR。把控制传递给自己的TSR启动时找到的中断向量,
          这样可将此TSR所使用的中断链接起来。
              使用自己的堆栈而不是中断程序所控制的堆栈。因为没有办法知道系统堆栈
          里可能有什么,在摧毁系统中某样东西之前,并不知道堆栈的大小和剩下的空间大
          小。
          鉴于这些矛盾,一批独立TSR作者1986年就联合起来努力开发TSR标准。尽管可能
    没有达到最初的目的(提供完整的应用程序包接口,它能为所有经销商和独立作者所接
    受),但其中一些成员仍在继续干,1988年,他们公布了一套库函数——与C、Turbo Pascal
    4.0和更高版本以及汇编程序兼容——能处理TSR设计的复杂部分。
        TesSeRact能在CompuServe上用作共享软件包并且可来自许多本地布告栏系统。附
    录C包含了这方面的纵览,即有标准化的、清楚地标明了冲突的方法。在这里有必要指出
    的是,Jim Kyle是这个队伍中的一员,并且是仍然参加这个项目的两个人之一。
          虽然许多商业开发者都编写他们自己的内部例程而不是使用该函数库,但他们已接
    受了这个接口标准。这个队伍鼓励这样做:就是要达成一个标准来避免冲突,而不是鼓励
    使用任何单一编码的软件包却排斥别的软件。
    296页
                        11.10 TSR的中断基础
          很多中断备有文档记录。对于任何想编写TSR的人,中断是很重要的。“DOS参考手
    册”一章提供了详细内容。这一章还使我们能看到了中断所能提供的各种帮助。
    11.10.1键盘中断
          键盘中断(Int 09h)是TSR获得控制的一种途径。通过操纵键盘操作,TSR就能告知
    按热键和激活它们的时间。下列程序显示了基本方法:
              Int 09h activates on keystroke
              Handler activateS and reads keystrOke
              if(hot key has been found){
                  throw away the keystroke
                  check DOS
                  if(in DOS){
                      set a hot key flag
                      return from the interrupt
                  }else{
                      actiVate the TSR
                      when the TSR is done,return
                          from the interrupt
                  }
              }else{
                 Chain to the next handler on Int 09h
              }
          “Check DOS”是什么?记住DOS是不能重入的。如果调用DOS就会损坏系统。可用
    Int 21h,功能34h来检查DOS。
    11.10.2 InDOS标志、DOSOK中断和定时器中断
          调用(Int 21h的功能34h,可以返回指向InDOS标志(DOS忙标志)的指针。如果该标
    志非零,就中断DOS来执行功能。若TSR确实中断了DOS,该功能常常在四分之一秒内
    返回。前面的Int 09h的伪代码已显示出检查InDOS标志的地方。设置热键标志后,必须
    有办法找到它。为此,就有了DOSOK中断和定时器中断。
          当程序启动时,它必须为Int 28h而初始化一个特殊的中断处理程序,如下所示:
              Int 28h activates
            check hot key flag
            if (hot key flag is set ){
                turn hot key flag off
                    activate the TSR
              }
              call the next Int 28h service routine
            return from interrupt
         
    297页
        DOS在Int 21h的功能01h-0Ch中等待控制台输入时,Int 28h(DOSOK中断)就会激
    活。看到这个中断就知道能安全使用别的DOS功能(在DOS V2下运行时有两个例外,即
    未公开的功能50h和51h;详细情况可参看“参考手册”一节)。
        如果DOS不在等待输入,就可用定时器中断。该中断(1Ch)每秒跳动18.2次。可将下
    列也检查热键标志的服务例程附加到这个中断上:
          Timer interrupt activates
          call next timer interrupt service
          check hot key flag
          if(hot key flag is set){
              turn hot key flag off
              activate the TSR
          }
          return from the interrupt
        获得控制后,会出现别的问题。我们自己的TSR想尽可能简单地工作,但我们并不知
    道中断的机器状态。堆栈有多深?堆栈指针下有多少自由空间能用于扩展?更重要的是,我
    们不希望系统错误会缠住TSR。
        要使TSR尽可能健全,就要让它控制关键出错中断(Int 24h)和Ctrl-Break中断(Int
    23h)。TSR也能把自己插入BIOS磁盘驱动程序(Int 13h)的中断链中,或插入可能带来问
    题的别的例程中。然后,如果出了问题,TSR能纠正它,我们移到内部堆栈上并执行功能。
        一些程序员提倡上下文切换。在这里,指向活动进程PSP的DOS的指针会变成指向
    TSR的PSP指针。可利用Int 21h,功能51h来获得中断的程序的段地址;保存该地址,然
    后使用Int 21h的功能50h告诉DOS:TSR的程序段前缀(PSP是当前活动进程。在V2之
    下,如果在Int 28h服务过程中执行该进程,它就会充满危险,因为50h和51h使用与28h
    一样的DOS堆栈空间。结果,系统就会死锁。
        如果进行文件输入/输出,或者想获得全部控制,那么上下文切换是很有用的技术。在
    V2中调用一个功能(于是就导致DOS使用一个替代的堆栈区)之前设置DOS关键出错
    标记,然后在功能返回时清除该标志,以便DOS能正常运行,这些操作能避免危险。遗憾
    的是,这个过程反而产生了更多的问题,因为DOS的不同版本中关键出错标志的位置不
    同。最好的解决方法是避免上下文切换,除非绝对必需(如用于以句柄为基础的文件I/
    O);如果必须使用,可参看“参考手册”一节中有关功能50h和51h的内容。
        TSR结束主要事务时,它必须“清除自己”,恢复中断并将堆栈设置到正常状态。然后
    它才能返回到被中断的程序中。
        为了说明基本的TSR操作,我们将一些概念性东西用于简单的时钟程序(clock.c)
    中,该程序先自我设置好,然后等待下一个时钟的节拍来激活(列表11.7)。
      列表11.7
              /*Clock.c
                  Listing 11.7 of DoS Programmer's Reference*/

    298页
    #include <stdio.h>
    #include <stdlib.h>
    #include <dos.h>
    #include <string.h>
    /* Define needed constants */
    #define BOOL int
    #define FALSE 0
    #define TRUE !FALSE
    /* Define program size for the system */
    #define PGMSIZE 3000
    /* Define base address for video display */
    #define MONOBASE 0xb000
    #define COLORBASE 0xb800
    /* Define interrupt vectors for BIOS and DOS needed by program */
    #define GOTOXY 0x02
    #define GETXY 0x03
    #define TELETYPE 0x0e
    #define VIDEO 0x10
    #define CLOCK 0x1a
    #define TIMER 0x1C
    #define DOS 0x21
    #define TSR 0x31
    #define TEST 0x66
    void interrupt clock(); /* Declare clock() */
    void  interrupt (*orig_clock)(); /* original clock vector */
    void interrupt test(); /* Declare test()*/
    BOOL inclock = FALSE; /* Clock processing flag */
    BOOL extra = FALSE; /* Extra tick flag */
    int count = 0;   /* Clock tick Counter */
    char buf[20]; /* Time buffer */
    char far *clkptr; /* Pointer to screen location */
    int sp; /* Stack pointer */
    int ss;  /* Stack segment */
    int hr, min, sec; /* Current time */
    void main(argc, argv)
    char argc;
    char *argv[];
    {
    union REGS regs;
    int mode;
    int streql(char *str1, char *str2);
    void readclock(int *hr, int *min, int *sec);
    void tsrexit(void);
    int getmode(void);
    /* Initialize clock output buffer with a string for printing */
    Strcpy(buf, " TEST");
    orig_clock = getvect(TEST);
    if(streql(argv[1], "-u") && orig_Clock!=0) {
    printf("Updating the clock\n");

    299页
    int86(TEST, &regs, &regs);
    exit(0);
    }
    if(orig_clock!=0) {
    printf("Already installed ... exiting\n");
    exit(0);
    }
    setvect(TEST, test);
    /* Read the initial value of the clock at start-up, and
    then set the clock pointer to the screen address */
    Orig_clock = getvect(CLOCK);
    setvect(CLOCK, clock);
    readclock(&hr, &min, &sec);
    mode = getmode();
    printf("Display mode is %d\n",mode);
    if(mode==7)
    clkptr = MK_FP(MONOBASE, 120);
    else
    clkptr = MK_FP(COLORBASE, 120);
    /* TSR exit to save the memory for the program */
    tsrexit();
    }
    void interrupt clock()
    {
    void displayclk(char *str);
    (*orig_clock)();
    count++;
    if(sec%5==0 && count%18==0 && !extra) {
    extra=TRUE;
    count--;
    } else {
    extra=FALSE;
    }
    if(count%18 == 0) {
    disable();
    SP  = _SP;
    SS = _SS;
    _SS =_CS;
    _SP = PGMSIZE;
    enable();
    sec++;
    if(sec>=60) {
    Sec=0; min++;
    }
    if(min>=60) {
    min=0; hr++;
    }
    if(hr>=24) hr=0;
    if(!inclock) {
    inclock = TRUE;
    Sprintf(buf+6, "%02.2d:%02.2d:%02.2d", hr, min, sec);
    displayclk(buf);
    inclock = FALSE;
    300页
    }
    disable();
    _SP = sp;
    _SS = ss;
    enable();
    }
    }
    void tsrexit(void)
    {
    union REGS regs;
    regs.h.ah = TSR;
    regs.h.al = 0;
    regs.x.dx = PGMSIZE;
    int86(DOS, &regs, &regs);
    }
    void displayclk(str)
    char * str;
    {
    char far *ptr;
    ptr = clkptr;
    while(*str) {
    *ptr++ = *Str++;
    ptr++;
    }
    }
    void readclock(hr, min, sec)
    int  *hr, *min, *sec;
    {
    union REGS regs;
    unsigned long clock;
    unsigned long remain;
    unsigned long x1, x2;
    regs.h.ah = 0;
    int86(CLOCK, &regs, &regs);
    x1 = regs.x.cx*65536L; x2 = regs.x.dx;
    clock=x1+x2;
    *hr = (int)(clock/65543L);
    remain = clock%65543L;
    *min = (int)(remain/1092);
    remain = remain%1092;
    *sec = remain/18.21;
    }
    void interrupt test()
    {
    register int ds;
    disable();
    SP = _SP;
    SS = _SS;
    _SS = _CS;
    _SP = PGMSIZE;
    ds=_DS;
    _DS = _CS;
    readclock(&hr, &min, &sec);
    _DS = ds;
    301页
               _SP=sp;
               _SS=SS;
              enable();
          }
    int streql(str1,str2)
        char *str1, *str2;
          {
              return(Strcmp(str1,str2)==0);
          }
    int getmode()
          {
              union REGS regs;
              regs.h.ah = 0x0f;
              int86(VIDEO, &regs,&regs);
              return (regs.h.al);
          }
      让我们复习一下,看看该程序的工作方式。
        注意该设置的一部分是将字TEST放在时钟输出缓冲区的开始,以便时钟更新时显
    示这个字(这只是说明程序的一种便利)。
        采用标准的Turbo C函数,用于访问中断向量表(而不是直接进行调用)。但首先必须
    看看TSR是否安装好。简单的方法就是:把Int 66h用作标记,因为大多数TSR都不用
    它,而且它的值通常是零。如果Int 66h非零,程序就假定TSR已设置了它。如果为0,就没
    有设置。
        Int 66h还用来迫使时钟程序通过系统来重新设置当前时间。要做到这一点,不用编
    写一个新程序,而只需用-u标志来启动TSR。若第一个参数是-u,那么请重新设置时钟并
    离开它。
        Turbo C的getvect()函数用来获得向量值。然后如果设置了Int 66h向量,程序就检
    查-u标志。若找到了-u标志,并且该向量非零,那么就调用Int 66h来重新设置时钟并退
    出。
        如果没有-u标志,程序就检查向量是否非零。是非零的话,程序假定时钟程序已经启
    动。若别的使用Int 66h的TSR是活跃的,就不能启动时钟程序(因为Int 66h向量)。
        检查完后,若发现向量是0,那么可设置向量来指向test()中断函数(它迫使TSR读
    取BIOS时钟)并建立时钟功能。
        要建立时钟功能,首先要获得原始的时钟向量,保存起来以备将来使用,并重新设置
    该向量指向clock()中断函数。然后从BIOS时钟功能读取初始时钟时间,获得当前显示模
    式来识别单色监视器的单色,并建立指针(clkptr)指向将要写时钟的屏幕位置。在TSR正
    常操作时要消除使用BIOS或DOS功能,可直接将时钟放在屏幕显示缓冲区里。这个过
    程只在文本方式中运行;若程序把显示器移到图形方式下,就会显示一堆废物。
        建立好各种环境后,调用TSR出口,程序驻留原处。时钟中断处理程序clock()是
    TSR的心脏。让我们来逐步地细致地看看它的操作方式。
        首先,调用原始时钟定时器,以便它能完成每次时钟计数时所需做的所有事情。然后

    302页
    才能向前推进。count变量是跟踪定时器的跳动(每秒18.2次)。时钟则每计数18次就前进1
    秒。每5秒钟就允许一次额外的计数使平均值经过5秒时间达到每秒18.2次。计数以后,检
    查看看是否在5秒间隔之上。若是就减去1,然后等待一次额外的跳动(在这一秒中有19次
    跳动)。额外标记会告诉用户正在进行额外跳动,并防止返回第5秒时递减计数。
          秒之间的时间可用来检查第18次计数。找到了可把堆栈重新设置成内部堆栈,并把定
    时器向前拨1秒(sec++)。然后,要保持时钟正确运行,就要检查60秒、60分及24小时等时
    间的情况。所有其它事情都结束时,显示时间。
          如果不处在时钟显示部分中(inclock设置为FALSE),就进入程序的这个部分,把in-
    clock设置成TRUE,并建立和显示时钟。最后,重新把堆栈设置成调用clock()函数时的
    状态。
          时钟显示很简单。可直接向屏幕内存书写并把屏幕缓冲区指针前移2位,把属性字节
    传给屏幕时钟的每个字节。时钟程序的余下部分由一些简单的、自我注解的功能组成。
          Borland C/C++编译程序来编译该程序,使用软件提供的MAKE实用程序。列表
    11.8显示了编译该程序的makefile。
        列表11.8
              #clock.mak
              clock.exe:        clock.obj
                    tlink /x c0t clock,clock,, emu maths cs
              clock.obj       clock.c
                    bcc-c -mt clock.c
          MAKE实用程序只在必要时才重新编译这个程序。这类实用程序尽管在这里用得很
    少,但在大型项目中却是特别有用的。用下列命令行执行MAKE实用程序:
              make        -fclock
          编译的重要事情就是用TINY内存模型(与COM程序相同,以便代码、数据和堆栈
    段都相同)来编译该程序。可参看Borland C/C++用户指南中有关这个编译程序开关的
    使用方式。
          如果使用Microsoft C,就可以修改这个程序来在Microsoft系统的限制内,处理段寄
    存器并建立相似的编译开关以便控制对程序的编译。
                         11.11小    结
          本章介绍了用中断来工作的方式。使用作为DOS Int 21h的一部分的实用程序,就可
    以把中断向量变成指向所设计的功能。我们已经用C编写了样本处理程序,它带有汇编
    语言的前端,可用它来处理接口。Turbo Pascal 4.0提供了一种特定的方法来创建一个中
    断处理程序,并把它作为Pascal函数来使用。
          TSR实用程序能编写成以中断来触发的程序(例如,键盘和时钟中断)。这些实用程
    序对用户程序却是极其危险的,因为DOS从未打算操纵多任务操作。DOS是一个不能重

    303页
    入的系统,TSR控制计算机时,如果调用了正在进行中的功能,DOS就会失败。
        我们了解了减少TSR所带来问题的许多方式。不要去调用DOS功能,除非绝对需
    要;要和BIOS或直接的调用来进行键盘和屏幕输入/输出。我们也知道监视InDOS标志
    来看看何时执行DOS功能是安全的;并且还应监视Int 28h来确定系统何时在等待键盘
    输入。我们知道了提供检查功能让TSR检查一下它自己是否已安装好,并且总是假定存
    在另一个TSR。另外,使用内部堆栈是防止堆栈操作问题的一条好的途径。

    展开全文
  • unsigned long flags; local_irq_save(flags);//禁止中断,保存状态 local_irq_restore(flags);//恢复状态
  • typedef irqreturn_t (*irq_handler_t)(int, void *);
  • unsigned long flags; local_irq_save(flags); /* 禁止中断 */ local_irq_restore(flags) ; /* 中断被恢复到他们原来的状态 */
  • enum { HI_SOFTIRQ=0, TIMER_SOFTIRQ, ... BLOCK_SOFTIRQ, BLOCK_IOPOLL_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ ...
  • linux 信号中断处理

    千次阅读 2012-01-07 16:38:14
    信号可以导致一个正在运行的进程被另一个异步进程中断,转而处理某一个突发事件。每个信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD、SIGINT等,它们在系统头文件中定义,也可以通过在shell下键入kill –l查看...
     
    linux提供的信号机制是一种进程间异步的通信机制,在实现上是一种软中断。信号可以导致一个正在运行的进程被另一个异步进程中断,转而处理某一个突发事件。每个信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD、SIGINT等,它们在系统头文件<signal.h>中定义,
    也可以通过在shell下键入kill –l查看信号列表,
    或者键入man 7 signal查看更详细的说明。
    
    信号的生成来自内核,让内核生成信号的请求来自3个地方:
    1     用户:用户能够通过输入CTRL+c、Ctrl+\,或者是终端驱动程序分配给信号控制字符的其他任何键来请求内核产生信号;
    2      内核:当进程执行出错时,内核会给进程发送一个信号,例如非法段存取(内存访问违规)、浮点数溢出等;
    3      进程:一个进程可以通过系统调用kill给另一个进程发送信号,一个进程可以通过信号和另外一个进程进行通信。

    同步信号和移步信号

        由进程的某个操作产生的信号称为同步信号(synchronous signals),例如除0;由象用户击键这样的进程外部事件产生的信号叫做异步信号。(asynchronous signals)。

    进程接收到信号以后,可以有如下3种选择进行处理:
    1, 接收默认处理 :接收默认处理的进程通常会导致进程本身消亡。例如连接到终端的进程,用户按下CTRL+c,将导致内核向进程发送一个SIGINT的信号,进程如果不对该信号做特殊的处理,系统将采用默认的方式处理该信号,即终止进程的执行;
    2, 忽略信号 :进程可以通过代码,显示地忽略某个信号的处理,例如:signal(SIGINT,SIGDEF);但是某些信号是不能被忽略的,

    3,捕捉信号并处理:进程可以事先注册信号处理函数,当接收到信号时,由信号处理函数自动捕捉并且处理信号。

    下面详细介绍:

    信号的产生:

    1,kill:用法:kill [信号代码]    进程ID

          注:信号代码可以省略;我们常用的信号代码是 -9 ,表示强制终止

         而kill()函数定义为:

        int kill(_pid_t  _pid , int _sig);

       用法:

       #include <sys/types.h>
         #include <signal.h>

         int kill(pid_t pid, int sig);

         参数:
    pid:可能选择有以下四种

    1. pid大于零时,pid是信号欲送往的进程的标识。
    2. pid等于零时,信号将送往所有与调用kill()的那个进程属同一个使用组的进程。
    3. pid等于-1时,信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。
    4. pid小于-1时,信号将送往以-pid为组标识的进程。

    sig:准备发送的信号代码,假如其值为零则没有任何信号送出,但是系统会执行错误检查,通常会利用sig值为零来检验某个进程是否仍在执行。
    返回说明:
    成功执行时,返回0。失败返回-1,errno被设为以下的某个值
    EINVAL:指定的信号码无效
    EPERM;没有给任何目标进程发送信号的权限
    ESRCH:目标进程或进程组不存在

     

    2,alarm()定时

    alarm函数可以设置一个计时器,计时器超时时,产生SIGALRM信号给当前进程。每个进程只能有一个闹钟时钟。

                              unsigned int alarm(unsigned int seconds);

    3,raise()自举一个信号。函数则允许进程向自身发送信号。

                             int raise(int signo);
                              raise(signo)
                           等价于
                              kill(getpid(),signo);


    信号的安装

        linux主要有两个函数实现信号的安装:signal()、sigaction()。其中signal()在可靠信号系统调用的基础上实现,是库函数。它只有两个参数,不支持信号传递信息,主要是用于前32种非实时信号的安装;而sigaction()是较新的函数(由两个系统调用实现:sys_signal以及sys_rt_sigaction),有三个参数,支持信号传递信息,主要用来与 sigqueue()系统调用配合使用,当然,sigaction()同样支持非实时信号的安装。sigaction()优于signal()主要体现在支持信号带有参数。

    1、signal()

      void   signal(int signum, void (*handler));

       第一个参数指定信号的值,第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。

        如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。

    2,sigaction()

         int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

        sigaction函数用于改变进程接收到特定信号后的行为。该函数的第一个参数为信号的值(即接受到的信号),可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction 的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理;第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定 oldact为NULL。如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等。

     

    信号集及屏蔽信号:

        中断可以被屏蔽,linux的信号是可以被屏蔽的,即阻塞信号。与信号的忽略操作不同,在这里系统不传递阻塞信号,而忽略信号是系统传递信号,只是不处理。

        linux用信号集来管理阻塞信号,可以设置某个进程阻塞某个集合中的信号。

    (1)清空信号集:sigemptyset()

      (2)  完全填充信号集:sigfillset()  设置完成之后,阻塞所有的信号

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

    还有很多函数,这里不一一介绍了。

     

    等待信号

           进程可以因等待信号而暂停当前运行,Pause()函数用来等待除当前进程阻塞信号外的任意信号,而sigsupend()函数用来等待除指定信号外的任意信号

           int   pause(void);

    下面给出linux中的常见信号:

    此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
    1) SIGHUP
    本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。
    2) SIGINT
    程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。
    3) SIGQUIT
    和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。
    4) SIGILL
    执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。
    5) SIGTRAP
    由断点指令或其它trap指令产生. 由debugger使用。
    6) SIGABRT
    调用abort函数生成的信号。
    7) SIGBUS
    非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。
    8)SIGFPE
    在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。
    9) SIGKILL
    用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。
    10) SIGUSR1
    留给用户使用
    11) SIGSEGV
    试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
    12) SIGUSR2
    留给用户使用
    13) SIGPIPE
    管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止。
    14) SIGALRM
    时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.
    15) SIGTERM
    程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。
    17) SIGCHLD
    子进程结束时, 父进程会收到这个信号。
    如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程来接管)。
    1 SIGCONT
    让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符
    19) SIGSTOP
    停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.
    20) SIGTSTP
    停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号
    21) SIGTTIN
    当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行.
    22) SIGTTOU
    类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.
    23) SIGURG
    有"紧急"数据或out-of-band数据到达socket时产生.
    24) SIGXCPU
    超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。
    25) SIGXFSZ
    当进程企图扩大文件以至于超过文件大小资源限制。
    26) SIGVTALRM
    虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.
    27) SIGPROF
    类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.
    28) SIGWINCH
    窗口大小改变时发出.
    29) SIGIO
    文件描述符准备就绪, 可以开始进行输入/输出操作.
    30) SIGPWR
    Power failure
    31) SIGSYS
    非法的系统调用。
    (清悠我心:http://hi.baidu.com/%E6%B8%85%E6%82%A0%E6%88%91%E5%BF%83/home)

    展开全文
  • shell trap信号处理

    千次阅读 2013-12-11 14:18:36
    shell中trap可设置脚本的信号处理函数,格式如下: trap signal_handler HUP INT QUIT TSTP TERM EXIT 注: 1、signal_handler 是信号处理函数; 2、HUP INT QUIT TSTP TERM EXIT 是相关信号。 3、如果要重置...
  • 388 * handle_level_irq - Level type irq handler //电平触发的中断处理函数 389 * @irq: the interrupt number 390 * @desc: the interrupt description structure for this irq 391 * 392 * Level type ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 52,135
精华内容 20,854
关键字:

shell中断处理