Here is an interrupt handler running in protected mode using DJGPP. This is modified slightly from the DJGPP User's Guide


//Simple Example of chaining interrupt handlers
//Adopted from Matthew Mastracci's code 

#include <stdio.h>
#include <pc.h>
#include <dpmi.h>
#include <go32.h>

//macros by Shawn Hargreaves from the Allegro library for locking
//functions and variables.
#define LOCK_VARIABLE(x)    _go32_dpmi_lock_data((void *)&x,(long)sizeof(x));
#define LOCK_FUNCTION(x)    _go32_dpmi_lock_code(x,(long)sizeof(x));

//timer interrupt 8 is generated every 18.2 ms
#define TIMER 8

//global counter
int counter = 0;

//the new ISR, will be called automatically every 18.2 ms once installed

void TickHandler(void)
{
  counter++;
}

void junk(void)
{
}


int main(void)
{
//structures to hold selector:offset info for the ISRs 
   _go32_dpmi_seginfo OldISR, NewISR;
   int old_counter = 0;

   printf("About to chain the new ISR onto the old timer ISR..\n");
   getkey();

//lock the functions and variables
   LOCK_FUNCTION(TickHandler);
   LOCK_VARIABLE(counter);

//load the address of the old timer ISR into the OldISR structure
   _go32_dpmi_get_protected_mode_interrupt_vector(TIMER, &OldISR);
   
//point NewISR to the proper selector:offset for handler
//function
   NewISR.pm_offset = (int)TickHandler;
   NewISR.pm_selector = _go32_my_cs();

//chain the new ISR onto the old one so that first the old
//timer ISR
//will be called, then the new timer ISR
   _go32_dpmi_chain_protected_mode_interrupt_vector(TIMER,&NewISR);
  
//notice no changes to counter in this loop- the interrupt changes it
   while (!kbhit())
   {
	    while(old_counter == counter) ;
   		printf("%d\n",counter);
		old_counter = counter;
   }

   printf("Removing new ISR from the timer ISR chain\n");

//load the old timer ISR back without the new ISR chained on
   _go32_dpmi_set_protected_mode_interrupt_vector(TIMER,&OldISR);

    return 0;
}