🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.os.msdos.programmer
Article #5851

Chaining interrupt handlers in Turbo C

#5851
From: Dave Andrews
Date: Wed, 17 Apr 1991 21:40
80 lines
4447 bytes
/*
 *  A week or so ago, someone asked:
 *    "how can I chain to the next interrupt handler in Turbo C?"  
 *
 *  Shortly after the post appeared, I needed the same function.
 *  I see from _Undocumented DOS_ that MSC has the "_chain_intr"
 *  builtin that does what you want.  Unfortunately, TC doesn't
 *  have an equivalent function (see _Undocumented DOS_ page 379).
 *
 *  Here is my solution to the problem.  It is not particularly
 *  elegant, and is HIGHLY dependent on the code TC++ 1.0 generates
 *  for INTERRUPT function epilogs.  I've only tested it on a
 *  '286 machine in the large model.  YMMV and all that.
 *
 *  Just before exit, the stack contains saved registers, CS/IP
 *  and flags.  I shift the stack, duplicating the CS/IP/flags
 *  (6 bytes) and modify the topmost CS/IP to point to the previous
 *  interrupt handler.  Then I let TC's generated exit code restore
 *  registers and IRET to the previous handler.  When the previous
 *  handler does its own IRET, it returns control to my original
 *  caller.
 *
 *  Note that the chain_intr macro destroys a number of registers
 *  rather indiscriminately.  Use chain_intr() just before your
 *  INTERRUPT function executes a return.  The stack should be
 *  the same as it was on entry, i.e. don't use chain_intr()
 *  inside a subordinate function call.
 *
 *  Hope this helps.
 *
 *  - David Andrews      bilver!dandrews
 */
 
#include <dos.h>
 
#define chain_intr(old)                                                  \
  asm {                                                                  \
    push ds;                   /* Need DS for access to "old" pointer */ \
    mov  si,sp;                /* -> current top of stack             */ \
    sub  sp,6;                 /* -> new top of stack after shift     */ \
    mov  di,ss;                /* Setup DS, ES for move               */ \
    mov  ds,di;                /*   DS:SI is source of move           */ \
    mov  es,di;                /*                                     */ \
    mov  di,sp;                /*   ES:DI is destination of move      */ \
    mov  cx,12;                /* Moving 24 bytes (12 words)          */ \
    rep  movsw;                /* Shift stack 6 bytes                 */ \
    pop  ds;                   /* Restore DS                          */ \
    cli  ;                     /* Protect stack                       */ \
    add  sp,22;                /* Zap IRET address to prior handler   */ \
    push DWORD PTR _##old;     /*     "                               */ \
    sub  sp,18;                /*     "                               */ \
    sti  ;                     /* Unprotect stack                     */ \
    }
 
void interrupt (*oldfunc) ();  /* Object of getvect(), setvect()      */
 
void interrupt first () {      /* Sample handler - installed first    */
 
  puts("First");
  }
 
void interrupt second () {     /* Sample handler - installed second   */
 
  puts("Second");
  chain_intr (oldfunc);        /* Example use of "chain_intr" macro   */
  }
 
void main() {
 
  setvect(255, first);         /* Install "first" as INT 255 handler  */
  oldfunc = getvect(255);      /* getvect() its address               */
  setvect(255, second);        /* Install the second INT 255 handler  */
  geninterrupt(255);           /* Call the second INT 255 handler.    */
                               /* It will execute and pass control to */
                               /* the previous handler (whose address */
                               /* is stored in "oldfunc").  Expected  */
                               /* output is:                          */
                               /*   Second                            */
                               /*   First                             */                                                                                                                                      
 };
Technical Details
Message-ID: <1991Apr17.214023.22334@bilver.uucp>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!wuarchive!emory!tridom!atssc!fang!tarpit!bilver!dandrews

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!wuarchive!emory!tridom!atssc!fang!tarpit!bilver!dandrews
From: dandrews@bilver.uucp (Dave Andrews)
Newsgroups: comp.os.msdos.programmer
Subject: Chaining interrupt handlers in Turbo C
Keywords: TC TURBOC interrupt _chain_intr
Message-ID: <1991Apr17.214023.22334@bilver.uucp>
Date: 17 Apr 91 21:40:23 GMT
Organization: W. J. Vermillion - Winter Park, FL
Lines: 80