Important Notice
The pages on this site contain documentation for very old MS-DOS software,
purely for historical purposes.
If you're looking for up-to-date documentation, particularly for programming,
you should not rely on the information found here, as it will be woefully
out of date.
_interrupt
◄Example► ◄Up► ◄Contents► ◄Index► ◄Back►
────────────────────────────────────────────────────────────────────────────
Keyword: _interrupt
Syntax: _interrupt declarator
Summary: Indicates that the function is an interrupt handler. The
compiler generates appropriate entry and exit sequences
for the handling function, including saving and restoring
all registers and executing an IRET instruction to return.
For compatibility with previous versions, interrupt is a
synonym for _interrupt.
See also: _chain_intr, _dos_getvect, _dos_keep, _dos_setvect
The _interrupt keyword applies to interrupt handlers written in C.
(This discussion assumes that you understand interrupts, and does
not attempt to cover the techniques for interrupt handling or
implications of incorrect interrupt handling.)
The _interrupt keyword can be applied to a function to tell the
compiler that the function is an interrupt handler. This keyword
tells the compiler to generate the entry and exit sequences
required for an interrupt-handling function, including saving and
restoring registers and executing an IRET instruction to return.
When an interrupt function is called, the DS register is
initialized to the C near data segment. This allows you to access
global variables from within an interrupt function.
In addition, all registers (except SS) are saved on the stack. You
can access these registers within the function if you declare a
function parameter list containing a formal parameter for each
saved register. The following example illustrates such a
declaration:
void _interrupt _far int_handler( unsigned _es, unsigned _ds,
unsigned _di, unsigned _si,
unsigned _bp, unsigned _sp,
unsigned _bx, unsigned _dx,
unsigned _cx, unsigned _ax,
unsigned _ip, unsigned _cs,
unsigned flags )
{
∙ ∙ ∙
}
Keyword Conflicts to Avoid
An interrupt function must be far. If you are compiling with the
small or compact memory model, you must explicitly declare the
function with the _far attribute. If you do not specify a memory
model by using the /A compiler option, small model is used and
interrupt functions must be explicitly declared with the _far
attribute.
Interrupt functions must observe the C calling convention. If you
used the /Gc compiler option to make FORTRAN/Pascal calling
conventions the default, you must explicitly declare your
interrupt-handling function with the _cdecl attribute.
You cannot declare a function with both the _interrupt and the
_saveregs attributes.
Declaring Formal Parameters
Formal parameters must be listed in the opposite order from which
they are pushed onto the stack. If you do not need access to all
of the registers, you can omit parameters from the end of the list
in your declaration.
You can not omit formal parameters from the beginning of the
parameter list. For example, if your handler needs to use only DI
and SI, you must still provide ES and DS, but not necessarily BX
or DX or those that follow.
The compiler always saves and restores registers in the same
fixed order. Thus, no matter what names you use in the formal
parameter list, the first parameter in the list refers to ES, the
second refers to DS, and so on.
Although there is technically no restriction on what you name the
register parameters, you should not give them actual register
names because they may conflict with future releases of CL or in-
line assembler code. A useful convention for avoiding the conflict
and retaining the documentation of the register names is to
precede each one with an underscore (for example, _ax, _bx).
Passing Additional Arguments
You can pass additional arguments if your interrupt handler is to
be called directly from C rather than by an INT instruction. To do
this, you must declare all register parameters and then declare
your parameter at the end of the list.
Changing Parameters
If you change any of the parameters of an interrupt function while
the function is executing, the corresponding register contains
the changed value when the function returns.
For example, the code below causes the DI register to contain -1
when the int_handler function returns. Do not modify the values of
the parameters representing the IP and CS registers in interrupt
functions. If you need to modify a particular flag, such as the
carry flag for certain DOS and BIOS interrupt routines, use the
bitwise-OR operator (|) so that other bits in the flags register
are not changed.
void _interrupt _far int_handler( unsigned _es, unsigned _ds,
unsigned _di, unsigned _si)
{
_di = -1;
}
Transferring Control to a Second Interrupt Function
Interrupt functions often need to transfer control to a second
interrupt routine. This can be done in the following two ways:
1. You can call the interrupt routine (after casting it to an
interrupt function if necessary), as shown in the code below.
Do this if you need to do further processing after the second
interrupt routine finishes.
void _interrupt _far new_int()
{
// Initial processing here
∙ ∙ ∙
(*old_int)();
∙ ∙ ∙
// Final processing here
}
2. Call _chain_intr with the interrupt routine as an argument.
The code below shows an example of this. Do this if your
routine is finished and you want the second interrupt routine
to terminate the interrupt call.
void _interrupt _far new_int()
{
∙ ∙ ∙
// Initial processing here
∙ ∙ ∙
_chain_intr( old_int );
// This is never executed
}
In general, it is not a good idea for an interrupt function to
call standard library functions, especially functions that rely on
DOS INT 21H or BIOS calls. Functions that rely on INT 21H calls
include I/O functions and _dosxxx functions. Functions that rely
on the BIOS include graphics functions and _biosxxx functions. It
may be safe to use functions that do not rely on INT 21H or BIOS,
such as string-handling functions.
Before using a standard library function in an interrupt function,
be sure that you are familiar with the library function and what
it does. Interrupt functions are primarily for the DOS
environment; they should not normally be used under OS/2.
Special Considerations
When an interrupt function is called by an INT instruction, the
interrupt enable flag is cleared. This means that no further
interrupts will be processed until your function returns
(including keyboard, time-of-day, and other crucial interrupts).
If your function needs to do significant processing, you should
use the _enable function to set the interrupt flag so that
interrupts can be handled.
Interrupt functions are special cases of C functions, since they
are potentially re-entrant. When designing an interrupt-handling
function in C, consider the following guidelines:
■ If your function does not use the _enable function to set
the interrupt flag, important interrupts may be ignored.
■ If your function does use the _enable function to set the
interrupt flag, another interrupt may take place. Make sure
that your handler takes this into account.
-♦-