ctl8588@rigel.tamu.edu (LAUGHLIN, CHET) (09/26/90)
I have successfully written a program that uses interrupt 1Ch to beep the speaker every few seconds. However, after trying to spruce it up I have noticed that functions called by an interrupt (declared void interrupt far) cannot call other functions declared simply void or int. After reviewing the Microsoft manual I could find no clarification or discussion of what limitations are placed on a function called by an interrupt. Can anyone enlighten me?? Possibly I'm not suppose to call the C library also??? Below is a simplified code segment example. In addition, the documents on how to restore a vector after your finished with it are skimpy, I assume I'm doing the right thing. void beep() { printf("beep\n"); } void interrupt far count() { if (cbeep_count > beep_count) { beep(); /* beep ..crashes here */ cbeep_count = 0; /* reset counter */ } else ++cbeep_count; } -Chet Laughlin "I have no opinions as I do not exist - my lawyer told me so"
marcb@hp-ptp.HP.COM (Marc Brandis) (09/27/90)
>I have successfully written a program that uses interrupt 1Ch to beep >the speaker every few seconds. However, after trying to spruce it up >I have noticed that functions called by an interrupt (declared void >interrupt far) cannot call other functions declared simply void or int. >After reviewing the Microsoft manual I could find no clarification or >discussion of what limitations are placed on a function called by an >interrupt. Can anyone enlighten me?? Possibly I'm not suppose to >call the C library also??? > >Below is a simplified code segment example. In addition, the documents >on how to restore a vector after your finished with it are skimpy, I >assume I'm doing the right thing. > >void beep() >{ > printf("beep\n"); >} > >void interrupt far count() >{ > if (cbeep_count > beep_count) > { > beep(); /* beep ..crashes here */ > cbeep_count = 0; /* reset counter */ > } > else > ++cbeep_count; >} > >-Chet Laughlin I do not see any reason, why you should not be able to call any procedure that is reentrant. Reentrancy means (in this context), that you can interrupt some procedure p and then call the same procedure p from the interrupt handler. As a rule of thumb, procedures that do not use static variables (or globals, anything that is not lying on the stack) are reentrant. I think several parts of the MSC library are not (!) reentrant. Moreover, you should make sure that your interrupt handler takes only a small amount of time to execute, so printf is certainly something that you should avoid (and beep as well). Consider that you get an interrupt every x milliseconds. If your interrupt handler takes more than x milliseconds to execute, then the 2nd interrupt interrupts your handler while it is handling the first interrupt. This stacking up of interrupts continues until the system dies with a stack over- flow. If you cannot avoid to have an interrupt handler that may take more than this x milliseconds to execute, you should build in some code that detects when the handler is interrupted itself and do something reasonable with it. Make sure that these actions are atomic. For more information on how to do it, see literature about concurrent programming. (* I speak only for myself. Marc-Michael Brandis Institut fuer Computersysteme ETH Zentrum CH-8092 Zuerich, Switzerland e-mail: brandis@inf.ethz.ch brandis@iis.ethz.ch Temporarily at HP, marcb@hp-ptp.ptp.hp.com *)
stever@Octopus.COM (Steve Resnick ) (09/29/90)
In article <10850002@hp-ptp.HP.COM> marcb@hp-ptp.HP.COM (Marc Brandis) writes: >>I have successfully written a program that uses interrupt 1Ch to beep >>the speaker every few seconds. However, after trying to spruce it up >>I have noticed that functions called by an interrupt (declared void >>interrupt far) cannot call other functions declared simply void or int. >>After reviewing the Microsoft manual I could find no clarification or >>discussion of what limitations are placed on a function called by an >>interrupt. Can anyone enlighten me?? Possibly I'm not suppose to >>call the C library also??? >> >>Below is a simplified code segment example. In addition, the documents >>on how to restore a vector after your finished with it are skimpy, I >>assume I'm doing the right thing. >> >>void beep() >>{ >> printf("beep\n"); >>} >> >>void interrupt far count() >>{ >> if (cbeep_count > beep_count) >> { >> beep(); /* beep ..crashes here */ >> cbeep_count = 0; /* reset counter */ >> } >> else >> ++cbeep_count; >>} >> >>-Chet Laughlin > >I do not see any reason, why you should not be able to call any >procedure that is reentrant. Reentrancy means (in this context), >that you can interrupt some procedure p and then call the same procedure >p from the interrupt handler. As a rule of thumb, procedures that do >not use static variables (or globals, anything that is not lying on >the stack) are reentrant. I think several parts of the MSC library >are not (!) reentrant. > printf in this case is NOT re-entrant. printf() writes a string to stdout, which in turn makes a call to DOS to write the string. MS DOS is not re-entrant either. Another thing to note, if MSC uses the same stdio structures as TC does, then *any* stdio call should be considered non-reentrant. (look at stdio.h). I write a lot of concurrent code under DESQview on MS DOS. Under DESQview, the environment allows for a single .EXE file to have several concurrent tasks. The problem of re-entrancy has come up there a lot, too. MS DOS is taken into account for, but the standard library, which gets shared between 2 or more tasks, is not. The programmer has to take into account those considerations. After a couple of years of working with TC and DESQview, I have found that a large number of the standard library (especially stdio) is non-reentrant. As Mr. Brandis pointed out, the re-entrancy can be determined largely by how a function operates: If it uses static, or global variables it is not re-entrant, if it doesn't it might be. The trick is to experiment a little, or write your own re-entrant routines. Cheers! Steve -- ---------------------------------------------------------------------------- steve.resnick@f105.n143.z1.FIDONET.ORG - or - apple!camphq!105!steve.resnick Flames, grammar errors, spelling errrors >/dev/nul ----------------------------------------------------------------------------
srini@ultra.com (S. Srinivasan) (09/29/90)
>I have successfully written a program that uses interrupt 1Ch to beep >the speaker every few seconds. However, after trying to spruce it up >I have noticed that functions called by an interrupt (declared void >interrupt far) cannot call other functions declared simply void or int. > > The one thing to watch out for is that you do not overextend yourself in doing things in interrupt mode. Some of the reasons for this are: 1. some library calls may not be re-entrant. For example, a call to print something would issue another interrupt to DOS. If this print were called from within an interrupt vector, then you have an interrupt within an interrupt. Which may not be too bad, but if you don't know the OS, then dont mess with it. 2. You might be blowing your stack if interrupts nest or if you are making other function calls from your interrupt vector. Your default stack with MSC is 2K. Generally enough, but ... The solution in a single-tasking system like DOS is simple but crude. This is recommended for those who dont know DOS too well, (like me!). main() { char int_happened = FALSE; while (TRUE) { if (int_happened) { beep(); int_happened = FALSE; } } } /* No longer invoked in interrupt-mode */ void beep() { printf("beep\n"); } /* Does not call any other functions */ void interrupt far count() { if (cbeep_count > beep_count) { int_happened = TRUE; cbeep_count = 0; /* reset counter */ } else ++cbeep_count; } Depending on how your code is structured, you may not have to loop on this 'int_happened' variable everywhere in your code, but ...! srini@ultra.com