DOS/4G

Tenberry Home

Consulting Services

Order DOS/4G

DOS/4G FAQ

Release Notes

DPMI Spec

* * *

DOS/4GW

DOS/4GW Pro

DOS/4G
for Watcom

DOS/16M

DOS/4G and DOS/4GW FAQ:
Interrupt Handling


[Previous Section] * [Index of FAQ] * [Next Section]
  1. My program installs a hardware interrupt handler. The program runs fine under plain DOS but crashes under DPMI. What might be happening?
  2. Why can't I get the WATCOM library signal() function to work with Ctrl-Break?
  3. I'm writing a hardware interrupt handler. Can you give me some tips?
  4. Does DOS/4G support VESA Int 10h Function 4F00?
  5. Is it true that the Watcom function _disable() only disables interrupts for the process, and not the processor?
  6. Is there any way around this, for example, using an asm 'cli' call?
  7. Can all published DOS interrupts be emulated with protected-mode code?
  8. So, what DOS interrupts are handled by protected-mode code?

1. My program installs a hardware interrupt handler. The program runs fine under plain DOS but crashes under DPMI. What might be happening?

Have you locked your handler in memory? The DPMI specification requires that all code and data referenced by a hardware interrupt handler MUST be locked at interrupt time. A DPMI virtual memory manager can use the DOS file system to swap pages out of memory to and from the disk; because DOS is not reentrant, a DPMI host is not required to be able to handle page faults during asynchronous interrupts. Use Interrupt 31h/600h (Lock Linear Region) to lock an address range in memory.

If you fail to lock all of your code and data, your program may run under DOS/4G, but fail under the DOS/4G Virtual Memory Manager or under another DPMI host, such as Windows or OS/2

You should also lock the code and data of a mouse callback function.


2. Why can't I get the WATCOM library signal() function to work with Ctrl-Break?

The signal function in some versions of the WATCOM C/C++ library had a bug that causes signal(SIGBREAK) not to work. Calling signal(SIGBREAK) installs a null interrupt handler for Crtl-Break (Interrupt 1Bh), instead of installing your handler.

You can work around this problem by hooking Interrupt 1Bh directly.


3. I'm writing a hardware interrupt handler. Can you give me some tips?

* It's more like handling interrupts in real mode than not.

The same problems arise when writing hardware interrupt handlers for protected mode as arise for real mode. We assume you know how to write real mode handlers; if our suggestions don't seem clear, you might want to brush up on real mode interrupt programming.

* Minimize the amount of time spent in your interrupt handlers.

When your interrupt handlers are called, interrupts are disabled. This means that no other system tasks can be performed until you enable interrupts (an STI instruction) or until you handler returns. In general, it's a good idea to handle interrupts as quickly as possible.

* To support high (greater than 1000 per second) interrupt rates, minimize the amount of time spent in the DOS extender as a result of interrupt-related mode switches by installing separate real mode and protected mode handlers.

If you use a passup interrupt handler, so that interrupts received in real mode are resignaled in protected mode by the extender, your application has to switch from real mode to protected mode to real mode once per interrupt. Mode switching is a time-consuming process, and interrupts are disabled during a mode switch. Therefore, if you're concerned about performance, you should install separate handlers for real mode and protected mode interrupts, eliminating the mode switch.

* If you can't just set a flag and return, STI.

Handlers that do more than just set a flag or store data in a buffer should re-enable interrupts as soon as it's safe to do so. In other words, save your registers on the stack, establish your addressing conventions, switch stacks if you're going to - and then STI, to give priority to other hardware interrupts.

* If you STI, you should CLI.

Because some DPMI hosts virtualize the interrupt flag, if you do an STI in your handler, be sure to do a CLI before you return. (CLI, then switch back to the original stack if you switched away, then restore registers, then IRET). If you don't do this, the IRET will not necessarily restore the previous interrupt flag state, and your program might crash. This is a difference from real mode programming, and it tends to show up as a problem when you try running your program in a Windows or OS/2 DOS box for the first time (but not before).

* Add a reentrancy check.

If your handler doesn't complete its work by the time the next interrupt is signaled, then the interrupts can quickly nest to the point of overflowing the transfer stack. This is a design flaw in your program, not in the DOS extender; a real mode DOS program can have exactly the same behavior. If you can conceive of a situation where your interrupt handler can be called again before the first instance returns, you need to code in a reentrancy check of some sort (before you switch stacks and STI, obviously).

Remember that interrupts can take different amounts of time to execute on different machines; the CPU manufacturer, CPU speed, speed of memory accesses, and CMOS settings (e.g. 'systems BIOS shadowing') can all affect performance in subtle ways. We recommend you program defensively and always check for unexpected reentry, to avoid transfer stack overflows.

* Switch to your own stack.

Interrupt handlers are called on a stack that typically has only a small amount of stack available (512 bytes or less). If you need to use more stack than this, you have to switch to your own stack on entry to the handler, and switch back before returning.

If you want to use C run-time library functions, which are compiled for flat memory model (SS == DS), and the base of CS == the base of DS, you need to switch back to a stack in the flat data segment first.

Note that switching stacks by itself won't prevent transfer stack overflows of the kind described above.


4. Does DOS/4G support VESA Int 10h Function 4F00?

No, DOS/4G doesn't directly support VESA Int 10h Function 4F00h.

However, DOS/4G provides tools that you can easily make these VESA interrupt calls. Any of the VESA extensions to int 10h will require that you translate your program's linear addresses to real mode addresses and back again. You may also need to allocate data buffers or control blocks in the lower 1MB. DOS/4G has APIs to do these things, so it will be really easy to do.


5. Is it true that the Watcom function _disable() only disables interrupts for the process, and not the processor?

That depends upon where you are running your DOS/4GW program.

The _disable() function just does a 'cli' instruction. How that affects your program/process/processor depends upon what operating system you are using.

In plain DOS, _disable() does indeed disable all interrupts, because there is only one 'process'.

If you are running in Win3.1 or Win95, the 'cli' is virtualized, and only interrupts for your process are disabled. Windows provides a int 2fh call you can make to truly disable interrupts., although I don't have my interrupt list here. You could also write a VXD.

In NT, the 'cli' is virtualized, and only interrupts for your process are disabled. You would have to write a NT device driver to get interrupts disabled totally.

OS/2 is similar to NT in this respect.


6. Is there any way around this, for example, using an asm 'cli' call?

Since _disable() just results in a 'cli', using an asm 'cli' won't. You would have to do something different for each operating system you are running in.


7. Can all published DOS interrupts be emulated with protected-mode code?

While a protected-mode system could be coded this way, we don't do this in our DOS extenders. Rather almost all DOS and BIOS interrupts are resignaled in real mode, after switching from protected mode. Of course, there is some copying of data and translation of pointers to make it work transparently, but we chose to code our systems to work this way to maximize compatibility.

By reflecting most interrupts to real mode, we insure that your DOS-extended program will be maximally compatible with existing software and systems. For example, if a TSR hooks the disk reading interrupt, because we reflect the disk reading interrupts to real mode, we insure that the TSR hook will be called.

The downside to this approach is that every DOS and BIOS call causes a switch to real mode and back again. Although most computers can perform such switching at a rate of tens of thousands of switches per second, the switching time can have a noticible impact on the performance of programs which heavily use DOS or BIOS services.

For example, a program which reads a disk file by calling DOS to read one byte at a time will likely run much slower in protected mode than in real mode. The solution is simple: buffer your disk reads to read, for example, 512 bytes per call to DOS. With such buffering, the extra time taken to perform mode switches will hardly be noticible.

Of course, you are free to do emulate DOS interrupt handling in your own code!


8. So, what DOS interrupts are handled by protected-mode code?

Basically, interrupts which allocate or free memory and interrupts which deal with installing interrupt handlers are handled by our DOS extenders. Of course, even though a memory allocation interrupt is handled by protected-mode code, that doesn't mean that a real-mode interrupt will not be signalled -- because the protected-mode code may need to allocate DOS memory.


[Previous Section] * [Index of FAQ] * [Next Section]
Last modified 2003.02.06. Your questions, comments, and feedback are welcome.