中斷處理程序2...........

火星人 @ 2014-03-03 , reply:0


中斷處理程序2...........

中斷處理程序2...........





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 :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_handler269頁;
      ;    }
      ;
            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) ;
          }




[火星人 via ] 中斷處理程序2...........已經有147次圍觀

http://www.coctec.com/docs/service/show-post-1697.html