Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!dali.cs.montana.edu!caen!sdd.hp.com!mips!apple!portal!gupta!few From: few@gupta.portal.com (Frank Whaley) Newsgroups: comp.os.msdos.programmer Subject: Re: Chaining interrupt handlers in Turbo C Keywords: TC TURBOC interrupt _chain_intr Message-ID: <1991Apr24.204727.27737@gupta.portal.com> Date: 24 Apr 91 20:47:27 GMT References: <1991Apr17.214023.22334@bilver.uucp> Organization: Gupta Technologies Inc Lines: 125 In article <1991Apr17.214023.22334@bilver.uucp> dandrews@bilver.uucp (Dave Andrews) writes: > * A week or so ago, someone asked: > * "how can I chain to the next interrupt handler in Turbo C?" And Dave responded with a very interesting version of chain_intr(). I never would have thought of his method. Unfortunately there are a couple of problems. Interrupts are improperly chained if the interrupt handler function has local variables. Turbo C (2.0, I can't speak for TC++ or BC++) only sets the BP register when the interrupt function uses local variables, so it cannot be used in all cases to unroll the stack. The best way to write handlers with local data: void interrupt handler() { if ( somethingWeDo ) doIt(); else chain_intr(original); } Dave's macro can only be used before a return, either stated or implied. So: if ( notForMe ) { chain_intr(original); return; /* required */ } ... I've attached a new version of what I use. It still suffers from not working in handlers with local variables, but it can be called anywhere and is implemented as a function. PAGE 60, 132 TITLE chain 24-Apr-91 Chain interrupt | ;-----------------------------------------------------------------------| ; | ; Turbo C Library -- ChainIntr | ; Chain interrupt | ; | ;-----------------------------------------------------------------------| ; sizes LCODE = 0 IFDEF __MEDIUM__ LCODE = 1 ENDIF IFDEF __LARGE__ LCODE = 1 ENDIF IFDEF __HUGE__ LCODE = 1 ENDIF ; Code Segment IF LCODE CHAIN_TEXT Segment Byte Public 'CODE' Assume CS:CHAIN_TEXT ELSE _TEXT Segment Byte Public 'CODE' Assume CS:_TEXT ENDIF PAGE ;-----------------------------------------------------------------------| ; Chain interrupt | ; | ; SYNOPSIS | ; void ChainIntr(void (interrupt *target)()); | ; | ; DESCRIPTION | ; Chain to another interrupt handler, passing original | ; (or possibly modified) register values. | ; | ; RETURNS | ; This function returns to the original source of the | ; interrupt. | ; | ;-----------------------------------------------------------------------| Public _ChainIntr IF LCODE _ChainIntr Proc Far ELSE _ChainIntr Proc Near ENDIF POP AX ; clear return addr IF LCODE POP AX ENDIF POP BX ; get target addr POP AX MOV BP,SP ; store target addr XCHG AX,[BP + 16] XCHG BX,[BP + 14] POP BP ; restore saved registers POP DI POP SI POP DS POP ES POP DX POP CX RETF ; return to target _ChainIntr EndP IF LCODE CHAIN_TEXT EndS ELSE _TEXT EndS ENDIF END ; of chain.asm -- Frank Whaley Software Engineer Gupta Technologies few@gupta.com