[comp.os.msdos.programmer] using int's in C

jmbj@grebyn.com (Jim Bittman) (03/23/91)

I learned something quite interesting from Microsoft Tech Support today.
It turns out that "outport(PORTID,PORTVALUE)" is not a "nice" function.
They said it must access the BIOS or DOS or something which makes it
non re-entrant (i.e. unavailable for interrupt routines).
Excuse me?  Shouldn't this just translate to:
  mov dx,PORTID
  mov ax,PORTVALUE
  out dx,ax

Not to mention the fact that for a hardware interrupt, an outport(20,20)
needs to be executed to "EOI" the 8259.  Anyway, this was their excuse
for the fact that hardware ints don't seem to work properly.  I'm sorry
that I haven't verified this yet, but I do know that a very simple
program works just fine with Borland, but dies miserably with Microsoft.

I hope this saves someone else the many, many, many, frustrating hours
I have spent dealing with this problem.

Jim Bittman, jmbj@grebyn.com

gag@marlin.NOSC.MIL (Gary A. Gilbreath) (03/23/91)

From article <1991Mar23.021231.21131@grebyn.com>, by jmbj@grebyn.com (Jim Bittman):
> I learned something quite interesting from Microsoft Tech Support today.
> It turns out that "outport(PORTID,PORTVALUE)" is not a "nice" function.
> They said it must access the BIOS or DOS or something which makes it
> non re-entrant (i.e. unavailable for interrupt routines).
> Excuse me?  Shouldn't this just translate to:
>   mov dx,PORTID
>   mov ax,PORTVALUE
>   out dx,ax

I have found just the opposite.  Both MSC 5.1 and 6.00A library routines
for inp(), inpw(), outp(), and outpw() are re-entrant.  If you want
in-line routines you can either enable intrinsics with a command line
option, or put "#pragma intrinsic(inp, inpw, outp, outpw)" in the
source file.

> Not to mention the fact that for a hardware interrupt, an outport(20,20)
> needs to be executed to "EOI" the 8259.  Anyway, this was their excuse
> for the fact that hardware ints don't seem to work properly.

I have just completed a program that uses both DMA and interrupts
without a single line of assembly.  You do have to remember to turn off
run-time stack overflow checking and be very careful about which library
routines (if any) you call while in the interrupt routine, but it
does work.

Gary Gilbreath, Naval Ocean Systems Center, San Diego, CA
Internet: gag@manta.nosc.mil
uucp: {ihnp4,akgua,decvax,dcdwest,ucbvax}!sdcsvax!nosc!gag

tabu6@CCVAX.IASTATE.EDU (Adam Goldberg) (03/25/91)

In article <1991Mar23.021231.21131@grebyn.com>,
 jmbj@grebyn.com (Jim Bittman) writes:
>I learned something quite interesting from Microsoft Tech Support today.
>It turns out that "outport(PORTID,PORTVALUE)" is not a "nice" function.
>They said it must access the BIOS or DOS or something which makes it
>non re-entrant (i.e. unavailable for interrupt routines).
>Excuse me?  Shouldn't this just translate to:
>  mov dx,PORTID
>  mov ax,PORTVALUE
>  out dx,ax

Yeah for Microsoft.  TurboC's outportb() function turns out to actually be
a macro (well, if you #undef it, it's a function), that does compile to
exactly the above code.

>
>Not to mention the fact that for a hardware interrupt, an outport(20,20)
>needs to be executed to "EOI" the 8259.  Anyway, this was their excuse
>for the fact that hardware ints don't seem to work properly.  I'm sorry
>that I haven't verified this yet, but I do know that a very simple
>program works just fine with Borland, but dies miserably with Microsoft.
>
>I hope this saves someone else the many, many, many, frustrating hours
>I have spent dealing with this problem.
>
>Jim Bittman, jmbj@grebyn.com

I'm not sure how you can do this (or if) with Microsoft C, but with TurboC,
you can use the command-line version of the compiler and do:

   tcc -S mysource.c

and it will create MYSOURCE.ASM, an MASM-compatible assembly listing of your
code with original source line numbers included as comments (I sure would like
the actual C source as comments, but you take what you can get).  Looking
at this code, a function of type INTERRUPT does something like this:

      1 - save all registers
      2 - change to a local stack
      3 - your code goes here (careful you don't use long-running DOS/BIOS
          calls--also realize that your interrupt routine MAY GET CONTROL
          DURING a DOS/BIOS routine, therefore you may be violating the
          non-reentrancy of DOS/BIOS)
      4 - change back to previous stack
      5 - pop all registers
      6 - IRET

Maybe Microsoft C will let you look at the code it compiles for you, and maybe
this will give you some light as to what the H*ll it's doing.


+----------------------------------------------------------------------------+
+ Adam Goldberg                         Bitnet:   tabu6@ISUVAX.BITNET        +
+ Iowa State University                 Internet: tabu6@CCVAX.IASTATE.EDU    +
+ H: (515) 233-5135
+          "It's simple!  Even a Pascal programmer could do it!"             +
+----------------------------------------------------------------------------+

jmbj@grebyn.com (Jim Bittman) (03/25/91)

I'm kind of embarrassed to point out that the *entire* problem was due
to not turning off run-time stack checking.  I can use the exact same
code as Borland, but compile with /Gs, and it works!

But:
 - Why isn't outp (MicroSoft) a "nice" function?
 - We checked the MS documentation and several other books, but
   nothing mentioned the /Gs switch (in relation to HW ints),
   any reasons why?

I must thank the net, because that is where the answer came from!

Jim Bittman, jmbj@grebyn.com

rkl@cbnewsh.att.com (kevin.laux) (03/25/91)

In article <1991Mar25.005251.12943@grebyn.com>, jmbj@grebyn.com (Jim Bittman) writes:
> I'm kind of embarrassed to point out that the *entire* problem was due
> to not turning off run-time stack checking.  I can use the exact same
> code as Borland, but compile with /Gs, and it works!
> 
> But:
>  - Why isn't outp (MicroSoft) a "nice" function?
>  - We checked the MS documentation and several other books, but
>    nothing mentioned the /Gs switch (in relation to HW ints),
>    any reasons why?

	The outp () function is a nice function.  *Any* function with arguments
could have caused the stack problem because arguments are (normally, except for
fastcall) pushed onto the stack.  Interrupts occur asynchronously and the ISR
gets whatever stack is in effect.  When you use the interrupt keyword all the
registers are pushed onto the current stack and it's up to the ISR to provide
it's own stack if necessary.  It's not a failing (per se) on the MSC
documentation, because writing an ISR is an advanced topic dealing with the
system and not any particular C compiler.

	Actually, getting caught with the run-time stack checking is a fairly
common occurence when writing ISR's; common enough that MS should say a few
words about it in their Advanced Programming Techniques manual.  Alas, stuff
like this tends to fall into the cracks and one has to find out the hard way.
:-(

-- 
________________________________________________________________________________
	R. Kevin Laux				Email: rkl1@hound.att.com
	AT&T Bell Labs				Voice: (908) 949-1160
	Holmdel, NJ 07733			Fax:   (908) 949-0959