[comp.lang.pascal] TSR in Turbo Pascal

tasos@bu-cs.BU.EDU (Anastasios Kotsikonas) (09/20/89)

I am trying to write a TSR in Turbo Pascal, and I capture the $1C timer
interrupt. Once inside the interrupt routine, I switch stacks and look
for the hot key. The problem is that I cannot chain the interrupt before 
exiting. If I try:
   { code to switch stacks }
   GetIntVec ($1C, old_intr);
   SetIntVec ($1C, prev_intr); { the vector before my TSR came to life }
   Intr ($1C, Regs);
   SetIntVec ($1C, old_intr);
   { code to restore original stack configuration }
the system freezes. This technique works for the $28 interrupt, but it
is impossible to do it this way for the timer interrupt.

If anyone knows anything about it I would appreciate any comments.

Tasos

tasos@cs.bu.edu

jeff@com2serv.C2S.MN.ORG (Jeffery S. Wilson) (09/21/89)

> I am trying to write a TSR in Turbo Pascal, and I capture the $1C timer
> interrupt. Once inside the interrupt routine, I switch stacks and look
> for the hot key. The problem is that I cannot chain the interrupt before 
> exiting. If I try:
>    { code to switch stacks }
>    GetIntVec ($1C, old_intr);
>    SetIntVec ($1C, prev_intr); { the vector before my TSR came to life }
>    Intr ($1C, Regs);
>    SetIntVec ($1C, old_intr);
>    { code to restore original stack configuration }
> the system freezes.
...
> Tasos
> 
> tasos@cs.bu.edu

When you are servicing the int $1C interrupt, you are essentially servicing a 
hardware interrupt.  The int $08 handler services the IRQ 0 hardware interrupt
then does an int $1C.  You should not make int $21 calls from within a hardware
interrupt handler, because DOS is not re-entrant.  The Turbo Pascal GetIntVec 
and SetIntVec procedures use int $21 functions $35 and $25 respectively, so 
this what is hosing up your program.  

I would suggest that you get and set the interrupt vector using the MemL array:

var
    old_intr,
    prev_intr   : longint

    ...

    inline($FA);                    { disable hardware interrupt processing }
    old_intr := MemL[0:$1C * 4];    { get your interrupt vector }
    MemL[0:$1C * 4] := prev_intr;   { restore the old interrupt vector }
    inline($FB);                    { re-enable hardware interrupt processing }

    Intr($1C,regs);

    inline($FA);                    { disable hardware interrupt processing }
    MemL[0:$1C * 4] := old_intr;    { resore your interrupt vector }
    inline($FB);                    { re-enable hardware interrupt processing }

    ....


The inline instructions are used to prevent hardware interrupts from being 
serviced during the time you are fooling around with the interrupt vector, just 
to be safe.

> This technique works for the $28 interrupt, but it is impossible to do it 
> this way for the timer interrupt.  

Int $28 is generated by DOS keyboard input loop if and only if it is safe to 
use int $21 functions.  Even then, you must not use int $21 functions $00 
through $0C.

The only problem with using int $28 is that some applications bypass DOS 
for their keyboard input, therefore the DOS keyboard input loop is never 
called.  You will not be able to hot key while these sort of programs are 
running.


If you absolutely must perform DOS int $21 functions while in a hardware 
interrupt handler, you should check the DOS critical section flag and the
DOS critical error flag before doing the function call.  This is done by
doing an int $21 function $34.  A pointer to the critical section flag
will be returned in ES:BX.  In DOS 2.xx the critical error flag is the byte
after the critical section flag.  In DOS 3.xx the critical error flag is the 
byte before the critical section flag, execpt Compaq DOS 3.0, where the 
critical error flag is $1AA bytes before the critical section flag.  Both the
critical section flag and the critical error flag should be 0 before you call
an int $21 function within a hardware interrupt handler.


Jeffery S. Wilson                   |       {amdahl|hpda}!bungia!com50!jeff
Com Squared Systems, Inc.           |       jeff@c2s.mn.org
2520 Pilot Knob Road                |       (612) 452-9522 voice
Mendota Heights MN 55120            |       (612) 452-3607 fax