Thread: Can't pin down bug related to timer interrupt handler.

  1. #1
    Registered User
    Join Date
    Nov 2006
    Posts
    19

    Can't pin down bug related to timer interrupt handler.

    I have run a 16 bit program using the Borland C++ 3.1 compiler. The program is supposed to replace the ISR for the system timer, without changing its frequency, the function I replaced it with is supposed to alternate a message that shows up in plain text mode. I only wanted to observe a simple message that showed the underlying timer interrupt at work. Instead, I get erratic (or so it would seem) behavior. Sometimes it works for indefinite amounts of time, and sometimes it ends, and only a fraction of those unexpected terminations are followed by the abhored message telling me that the Virtual DOS Machine has encountered an illegal operation. My question is: Am I doing something to cause this malfunction within the code that I show here? or could the restrictions that go along with running my program within the NTVDM be causing it?

    Code:
    unsigned long i;
    unsigned char t;
    
    int main()
    {
      old_timer_isr = getvect(TIMER);
    
      i = 0;
    
      setvect(TIMER, timer_isr);
    		      /*
      while(!kbhit());
    
      setvect(TIMER, old_timer_isr);
    			*/
      return 0;
    }
    
    void interrupt timer_isr(__CPPARGS)
    {
      i++;
    
      t = i % 60;
    
      if(t == 14) puts("C++");
      else if(t == 29) clrscr();
      else if(t == 44) puts("C");
      else if(t == 59) clrscr();
    }

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    You've broken one of the basic rules of using DOS interrupts: do as little as possible and return as quickly as possible. Calling functions like puts() and clrscr() can, depending on how they're implemented, do a fair amount of work involving other interrupts. If they take too long, another timer interrupt can occur before your interrupt handler returns, and interrupts are NOT reentrant.

    Another problem is that i will eventually overflow, which yields (IIRC) unspecified behaviour.

    A better way, in your case, would be to move most of the I/O out of the interrupt handler. For example;
    Code:
    /*  Warning:  untested code */
    volatile unsigned long i;
    unsigned long i2;
    unsigned char action, last_action = -1;
    
    void interrupt timer_isr(__CPPARGS)
    {
      i = (i + 1)%60;
    }
    
    int main()
    {
      old_timer_isr = getvect(TIMER);
    
      i = 0;
    
      setvect(TIMER, timer_isr);
    
      while(!kbhit())
      {
           i2= i;
           if (i2 >= 0 && i2 < 14) action = 0;     
           else if (i2 >= 14 && i2 < 29 || ) action = 1;
           else if (i2 >= 29 && i2 < 44) action = 0;
           else if (i2 >= 44 && i2 < 59) action = 2;
           else action = 0;              
    
           if (action != last_action)
           {
                if (action == 0) clrscr();
                else if (action == 1) puts("C++");
                else if (action == 2) puts("C");
               
                action = last_action;
           }      
       }
    
      setvect(TIMER, old_timer_isr);
      return 0;
    }
    If you want to be a little more paranoid, you can look into disabling interrupts during your interrupt handler. The means of doing it are compiler dependent, as you need to use assembler. Something like;
    Code:
    /*  Warning:  untested code */
    void interrupt timer_isr(__CPPARGS)
    {
       asm "cli";   /* Disable interrupts; method is compiler dependent */
      ++i;
      i = i % 60;
       asm "sti";   /* Reenable interrupts; method is compiler dependent */
    }
    I can't recall offhand if Borland 3.1 needs this (it is possible that the interrupt modifier implies this).
    Last edited by grumpy; 11-21-2006 at 04:39 AM.

  3. #3
    Registered User
    Join Date
    Nov 2006
    Posts
    19

    I ought to be more careful with interrupts

    Thanks a lot for the information. From now on I'll be a lot more careful with details that are never apparent in the code itself. There's obviously still loads I have to learn about how to work with interrupts. As for disabling and enabling interrupts, I think Borlandc 3.1 still uses the friendly enable() and disable() functions, which I will keep in mind from now on. Thanks again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How's interrupt handler?
    By lchunr in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 03-22-2003, 09:10 PM
  2. interrupt handler functions in Visual C++ 6.0
    By scromer in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 01-07-2002, 07:06 PM