[comp.lang.pascal] Problems with timer interrupts

ballerup@diku.dk (Per Goetterup) (01/06/91)

CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl Brendel) writes:

=> In article <1991Jan4.145541.17737@odin.diku.dk>, I wrote:

=> ...
=> >        I'm having some rather weird problems with a program of mine
=> >which needs to get something updated on the screen no matter what
=> >else the program might be doing.
=> >        I'm using interrupt 1C (User Timer Tick) to call my procedure which
=> >by the way DOESN'T call DOS (common error) - it only modifies the screen
=> >memory.
=> >        The problem is not to get it to work (it does) but what
=> >happens next. I start it up by saving the old vector then
=> >re-assigning it to point at my handler (procedure). This does indeed
=> >work and the screen get modified as it should while my is running
=> >happily along. So far so good. Then something might happen because
=> >sometimes the computer simply stops in the middle of the program and
=> >lock up (refusing warm-boots), other times it runs all the way to
=> >
=> [remainder deleted]

=> Your description (sans code) doesn't indicate whether you are
=> providing for a repeat of the interrupt while you are servicing it.
=> I.e., if you are still inside your routine when another 1C or 08
=> call occurs, what happens? While I don't think this question
=> addresses the problem with lockups that occur after exiting your
=> program, it may yield clues to some of the other behavior you
=> describe.

I think you're right Karl. I didn't provide for the possibility that another
interrupt might occur while I was servicing the previous interrupt, thus
creating a recursive routine that fast messed the stack up completely.

One of the answers I got indicated this and I've tried it. Now everything
runs, if it runs, because now the program either will run flawlessly until
(intended) termination when it (again) freezes the machine, or it will crash
on my very first append-to-pointer-chain call. This last action ONLY happens
when run from an EXE-file (as far as I've seen).

I've tried to see if I somehow didn't reach the point where I reset the
vector to its old value, by simply omitting the reset to see what happens,
and still the machine crashed at the end of the program, only now the
interrupt kept on running, updating the screen! - The machine still refused
warm-boots! - What happens here?

I've created a small test program that, using a simple clock, tests the
various solutions I get or think of. Unfortunately I didn't bring it with me
today, but I can provide it if nessesary.

I've also got suggestions (from elsewhere) to use interrupt 16h (keyboard
I/O) which gets called every time the machine isn't too busy doing hard CPU
or disk work. Anybody got expirences in using this???

Also, when should I call the old service routine from within my new one? -
First, last or in the middle?

	All help very appreciated!

		Per.

PS: I'm using an IBM PS/2 model 80 (386) running PC-DOS 3.30 and TP 6.0

-- 
| Per Gotterup                        | "The most merciful thing in the    |
| Student, DIKU (Dept. of Comp. Sci.) | world, I think, is the inability   |
| University of Copenhagen, Denmark   | of the human mind to correlate all |
| Internet: ballerup@freja.diku.dk    | its contents."  - H.P. Lovecraft - |

ftpam1@acad3.alaska.edu (MUNTS PHILLIP A) (01/08/91)

In article <1991Jan6.150656.8281@odin.diku.dk>, ballerup@diku.dk (Per Goetterup) writes...

[much deleted]

>Also, when should I call the old service routine from within my new one? -
>First, last or in the middle?

     Unless you run your program from another that uses INT 1CH, there won't
BE any old routine.  The vector points to an IRET in ROM on my machine (286
with DOS 3.3) unless changed by the user program.

     If you are simply running one program from DOS, just point the vector
to an interrupt procedure in the TP6 program.  You should reset the vector in
an exit routine (Programmer's Guide p. 247), not just at the end of the main
program.  Otherwise, abnormal program exit (like HALT, run time error, or
^C) will hash DOS for you by leaving vectors pointing into never never land
(where your program used to be).

     If you are nesting programs that use INT 1CH, you will need to carefully
consider what you want to happen before chaining the INT 1CH interrupt
procedures.  Should you decide to chain, you should do it at the end of the
interrupt procedure, after saved registers have been unstacked (but leave flags
and return address) and before the final IRET, which should be replaced by a
long jump to the original service procedure.  This all requires a lot of
inline machine code to get the stack in the right state before the long jump.

     If you think this is bad, just wait until you try ^C and/or BREAK handlers.

Philip Munts N7AHL
NRA Extremist, etc.
University of Alaska, Fairbanks

dave@tygra.ddmi.com (David Conrad) (01/09/91)

In article <1991Jan6.150656.8281@odin.diku.dk> ballerup@diku.dk (Per Goetterup) writes:
>I've also got suggestions (from elsewhere) to use interrupt 16h (keyboard
>I/O) which gets called every time the machine isn't too busy doing hard CPU
>or disk work. Anybody got expirences in using this???

This is not true.  16h is called by the running program to get keystrokes
from the keyboard or to check to see if any are waiting in the buffer.  It's
called as often as the running program calls it - no more and no less.  This
is usually fairly frequently, but can be arbitrarily infrequent if the
program is busy, or worse, stuck.

There is an interrupt which is called when the computer is idle, 28h, called
the DOS Idle interrupt.  The only place I know of this being called from is
interrupt 21h function 1, get keyboard input.  DOS calls 28h in a loop while
waiting for keystrokes.  If a program does its input via the BIOS (16h)
instead of DOS (21h) then 28h won't normally be called.

>Also, when should I call the old service routine from within my new one? -
>First, last or in the middle?

Last.  You want to do a far jump to the old handler instead of an iret to
exit your handler.  The old handler will either do the iret or a far jump
to an even 'older' handler.  Somewhere down the line the iret will be done
(otherwise the computer wouldn't have been working before you installed your
handler).  Exiting your handler in this way allows all the handlers which
are chained to the interrupt to 'see' it and get their crack at servicing
it.  This makes your handler 'well behaved'.

>-- 
>| Per Gotterup                        | "The most merciful thing in the    |
>| Student, DIKU (Dept. of Comp. Sci.) | world, I think, is the inability   |
>| University of Copenhagen, Denmark   | of the human mind to correlate all |
>| Internet: ballerup@freja.diku.dk    | its contents."  - H.P. Lovecraft - |
--
David R. Conrad		dave@tygra.ddmi.com		uunet!tygra!dave
-- 
=  CAT-TALK Conferencing Network, Computer Conferencing and File Archive  =
-  1-313-343-0800, 300/1200/2400/9600 baud, 8/N/1. New users use 'new'    - 
=  as a login id.  AVAILABLE VIA PC-PURSUIT!!! (City code "MIDET")        =
   E-MAIL Address: dave@DDMI.COM

dave@tygra.ddmi.com (David Conrad) (01/09/91)

In article <1991Jan8.034315.15222@ims.alaska.edu> ftpam1@acad3.alaska.edu writes:
>In article <1991Jan6.150656.8281@odin.diku.dk>, ballerup@diku.dk (Per Goetterup) writes...
>
>>Also, when should I call the old service routine from within my new one? -
>>First, last or in the middle?
>
>     Unless you run your program from another that uses INT 1CH, there won't
>BE any old routine.  The vector points to an IRET in ROM on my machine (286
>with DOS 3.3) unless changed by the user program.

The iret in ROM *is* the old routine.  Nothing wrong with chaining to the
default handler and letting it do the iret for you.  Safest way to do it.

>Should you decide to chain, you should do it at the end of the
>interrupt procedure, after saved registers have been unstacked (but leave flags
>and return address) and before the final IRET, which should be replaced by a
>long jump to the original service procedure.  This all requires a lot of
>inline machine code to get the stack in the right state before the long jump.

Once you've popped anything (registers, locals) you pushed onto the stack,
it should be in the right state for the far jump.  And you have to pop what
you pushed anyway.  You just don't get to let Turbo generate the code for
you.  I'd write an interrupt handler in asm to begin with, anyway.

>Philip Munts N7AHL
>NRA Extremist, etc.
>University of Alaska, Fairbanks

--
David R. Conrad
dave@tygra.ddmi.com
-- 
=  CAT-TALK Conferencing Network, Computer Conferencing and File Archive  =
-  1-313-343-0800, 300/1200/2400/9600 baud, 8/N/1. New users use 'new'    - 
=  as a login id.  AVAILABLE VIA PC-PURSUIT!!! (City code "MIDET")        =
   E-MAIL Address: dave@DDMI.COM

reino@cs.eur.nl (Reino de Boer) (01/10/91)

dave@tygra.ddmi.com (David Conrad) writes:

>>Also, when should I call the old service routine from within my new one? -
>>First, last or in the middle?

>Last.  

Except when taking over the timer interrupt(s) ?

>>-- 
>>| Per Gotterup                        | "The most merciful thing in the    |
>--
>David R. Conrad		dave@tygra.ddmi.com		uunet!tygra!dave
-- 
Reino R. A. de Boer     "We want to build the right product right, right?"
Erasmus University Rotterdam ( Informatica )
e-mail: reino@cs.eur.nl