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?
6. Is there any way around this, for example, using an asm "cli" call?
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 by installing separate real mode and protected mode handlers.
If you use a passup interrupt handler, so that interrupts received in real mode are resignalled 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 signalled, 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 itsself 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(W) has APIs to do these things, so it will be really easy to do.
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. I believe there is 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() is effectively a 'cli', no it wouldn't.