Handling interrupts
In QNX-based systems, device drivers that are stand-alone user processes handle most interrupts. Exceptions include inter-process interrupts (IPIs) and per-processor clock interrupts, which the kernel handles. In any handling case, each interrupt is associated with a thread, known as an Interrupt Service Thread (IST). You can see the IPI and clock IST for each core in pidin when looking at the kernel process.
One method to handle interrupts is to call InterruptAttachThread(), which attaches the calling thread to an interrupt source ID. This thread becomes an IST and is dedicated to the handling of the interrupt. The IST can invoke InterruptWait() to block until the interrupt occurs. If the call returns without an error, the kernel masks the interrupt. To unmask the interrupt, once it's finished processing, you can call InterruptUnmask() or pass the _NTO_INTR_WAIT_FLAGS_UNMASK flag to InterruptWait(). Doing the latter unmasks the interrupt and then blocks, which saves on the number of kernel calls required to handle an interrupt.
int const id = InterruptAttachThread (interrupt_number, _NTO_INTR_FLAGS_NO_UNMASK);
for (;;) {
if (InterruptWait (_NTO_INTR_WAIT_FLAGS_UNMASK, NULL) != -1) {
//Service interrupt
} else {
// Handle errors
}
}
Because the interrupt handling loop above uses the shortcut flag _NTO_INTR_WAIT_FLAGS_UNMASK for unmasking an interrupt before blocking, the prior call to InterruptAttachThread() shouldn't unmask the interrupt itself (and thus, should use the _NTO_INTR_FLAGS_NO_UNMASK flag as in this example). The kernel tracks the number of times these calls mask and unmask an interrupt and returns an error if the interrupt has been unmasked too many times.
Another method to handle interrupts is to call InterruptAttachEvent(), which associates an interrupt ID with an event by first creating a thread that calls InterruptAttachThread(). Using events with interrupts provides the same functionality that ISTs do. However, ISTs provide lower overhead and better control for interrupt handling. The purpose of the InterruptAttachEvent*() calls is to allow for easy migration of code from QNX SDP 7.x to QNX SDP 8.0. After calling InterruptAttachEvent(), the newly created thread runs a loop while the device driver waits for the event. Once InterruptWait() returns, the thread dispatches the event, and the device driver processes the interrupt; you should only associate pulse and semaphore events with interrupts.