qc.hlp (Table of Contents; Topic list)
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.
                                    -♦-