sherman@csclea.ncsu.edu (Chris Sherman) (08/22/89)
I'm using TC to rewrite a TSR that was written in MSC. The program makes use of a function called _chain_intr. TC does not have this function. _chain_intr, which is usually used in an interrupt handler, accepts the address of another interrupt handler, and jumps (not calls) over to it. It is as if the first handler was never called. What can I do in TC to achieve the same effect? I thought of calling the second interrupt handler like you would call any function, given its address, but I'm not sure this will work correctly every time. I appreciate any help. Thanx... Paul C. Sherman sherman@csclea.ncsu.edu
edb_tom@tor.nhh.no (Tom Ivar Helbekkmo) (08/23/89)
In article <3723@ncsuvx.ncsu.edu>, sherman@csclea.ncsu.edu (Chris Sherman) writes: > _chain_intr, which is usually used in an interrupt handler, accepts the > address of another interrupt handler, and jumps (not calls) over to it. > It is as if the first handler was never called. > > What can I do in TC to achieve the same effect? I thought of calling the > second interrupt handler like you would call any function, given its > address, but I'm not sure this will work correctly every time. No, you certainly can't do it that way. In MSC, when you declare a function "interrupt", you're telling the compiler that it will be used as an interrupt handler. The compiler then arranges for it to push all registers upon entry, *and restore them* on exit, then leave with an iret instead of a ret. In this scenario, the _chain_intr() function restores the registers, and then jumps to the specified place, which had better be another interrupt handler... :-) Correct me if I'm wrong, someone, but unless Turbo C has explicit support for writing interrupt handlers in C, you'll need to write your own (at the assembly level) to be able to do this sort of thing. I think the Blaise C Tools library is available for Turbo C -- it among other things helps you do interrupt processing in C. BCT is, in my opinion, a very good product, at a reasonable price. -tih -- Tom Ivar Helbekkmo, NHH, Bergen, Norway. Telephone: +47-5-959205 edb_tom@tor.nhh.no, thelbekk@norunit.bitnet, helbekkmo@nhh.uninett
jb@CSUStan.EDU (John Birchfield) (08/29/89)
In article <69@tor.nhh.no> edb_tom@tor.nhh.no (Tom Ivar Helbekkmo) writes: >In article <3723@ncsuvx.ncsu.edu>, sherman@csclea.ncsu.edu (Chris Sherman) writes: >> _chain_intr, which is usually used in an interrupt handler, accepts the >> address of another interrupt handler, and jumps (not calls) over to it. >> It is as if the first handler was never called. >> >No, you certainly can't do it that way. ... >Correct me if I'm wrong, someone, but unless Turbo C has explicit >support for writing interrupt handlers in C ... Turbo C allows writing interrupt handlers directly in C using pretty much the same mechanism as Microsoft. The following C program is provided as a very succinct example. ------------------------------------------------------------------------ /* * Turbo C Interrupt Handler Chaining Example * * You may easily see what your compiler thinks you mean for it to * do by compiling with the -S -c options and then looking at the * assembly code. * --- jb --- * Aug 28, 1989 #include <dos.h> void interrupt (*ticker_save) (); void interrupt ticker (); int count = 0; main () { ticker_save = getvect (8); setvect (8, ticker); while (count < 30); setvect (8, ticker_save); } void interrupt ticker () { count++; (ticker_save) (); } /* * The following is the pertinent assembly code generated by the * compiler inside ticker. Note that since the compiler knows about * the interrupt characteristics of the pointer ticker_save, * he pushes the flags before calling him. The only penalty you * have is the xtra registers pushed on the stack. Turbo C also * provides meta variables _AX _DX ... so that you can directly * manipulate the registers in the function. * * mov ds,bp * ; Line 17 * inc word ptr DGROUP:_count * ; Line 18 * pushf * call dword ptr DGROUP:_ticker_save * ; Line 19 */ ------------------------------------------------------------------------ - - === === John Birchfield 1575 Quail Ct. jb@koko.csustan.edu Turlock, CA 95380 (209) 634-6243
few@quad1.quad.com (Frank Whaley) (08/30/89)
In article <1098@koko.CSUStan.EDU> jb@koko.UUCP (John Birchfield) writes: >In article <3723@ncsuvx.ncsu.edu>, sherman@csclea.ncsu.edu (Chris Sherman) writes: >> _chain_intr, which is usually used in an interrupt handler, accepts the >> address of another interrupt handler, and jumps (not calls) over to it. >> It is as if the first handler was never called. >> >Turbo C allows writing interrupt handlers directly in C using >pretty much the same mechanism as Microsoft. The following C >program is provided as a very succinct example. << succinct example deleted >> While Turbo C does provide excellent interrupt handling support, the _chain_intr() function provides one capability not available from the normal Turbo C facilities: The ability to preserve original register contents when passing control to a subsequent (or original, depending on your point of view) interrupt handler. Note that the correct synopsis of an interrupt handling function is: void interrupt handler(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl) int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl; as the register contents are pushed upon entry, and popped upon exit. While within the handler, DS contains the current DGROUP value and other registers change as necessary. If the original interrupt handler is called from within our handler, it is unlikely that the correct register values will be passed. For many interrupt service routines this is inconsequential, as they do not care what the previous state of the machine was -- for example, serial port interrupt handlers are responding to a hardware interrupt and must preserve and restore the machine state at the time of the interrupt. However, when software interrupts are used for communication between processes (I use the term loosely :-), the contents of the registers is very important. The DOS Services interrupt (0x21) and the Multiplex interrupt (0x2f) are two examples that expect parameters to be provided in registers which are modified by the Turbo C interrupt service code. Fortunately (this is the part you were waiting for) the _chain_intr() function is not dificult to implement. Attached is a "dirty" version (values are popped into code-segment variables) which is missing the necessary segment/group descriptions, but which demonstrates the principles of chaining interrupts. I should note that, if desired, interrupt handlers can examine or modify the input register values. For example, to count all "open file" calls within a program: Assuming: ... long opencount = 0; void interrupt (*old21)(); ... old21 = getvect(0x21); setvect(0x21, my21); ... void interrupt my21(bp,di,si,ds,es,dx,cx,bx,ax) int bp,di,si,ds,es,dx,cx,bx,ax; { if ( (ax & 0xff00) == 0x3d00 ) opencount++; _chain_intr(old21); } ----- ;-----------------------------------------------------------------------| ; _chain_intr -- chain interrupt | ; | ; SYNOPSIS | ; void _chain_intr(target) | ; 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 __chain_intr __chain_intr Proc Near POP AX ; clear return addr ;;;;;;; POP AX ; another for large code models POP Word Ptr CS:target ; get target addr into jump POP Word Ptr CS:target + 2 POP BP ; restore saved registers POP DI POP SI POP DS POP ES POP DX POP CX POP BX POP AX ; we leave original IP, CS and flags on stack DB 0EAH ; JMPF target DD 0 ; target address __chain_intr EndP ----- -- Frank Whaley Senior Development Engineer Quadratron Systems Incorporated few@quad1.quad.com uunet!ccicpg!quad1!few Water separates the people of the world; Wine unites them.