QNX Neutrino and interrupts

The first thing we need to ask is, “What's an interrupt?”

An interrupt is exactly what it sounds like—an interruption of whatever was going on and a diversion to another task.

For example, suppose you're sitting at your desk working on job “A.” Suddenly, the phone rings. A Very Important Customer (VIC) needs you to immediately answer some skill-testing question. When you've answered the question, you may go back to working on job “A,” or the VIC may have changed your priorities so that you push job “A” off to the side and immediately start on job “B.”

Now let's put that into perspective under QNX Neutrino.

At any moment in time, the processor is busy processing the work for the highest-priority READY thread (this will be a thread that's in the RUNNING state). To cause an interrupt, a piece of hardware on the computer's bus asserts an interrupt line (in our analogy, this was the phone ringing).

As soon as the interrupt line is asserted, the kernel jumps to a piece of code that sets up the environment to run an interrupt service routine (ISR), a piece of software that determines what should happen when that interrupt is detected.

The amount of time that elapses between the time that the interrupt line is asserted by the hardware and the first instruction of the ISR being executed is called the interrupt latency. Interrupt latency is measured in microseconds. Different processors have different interrupt latency times; it's a function of the processor speed, cache architecture, memory speed, and, of course, the efficiency of the operating system.

In our analogy, if you're listening to some music in your headphones and ignoring the ringing phone, it will take you longer to notice this phone “interrupt.” Under QNX Neutrino, the same thing can happen; there's a processor instruction that disables interrupts (cli on the x86, for example). The processor won't notice any interrupts until it reenables interrupts (on the x86, this is the sti opcode).

Note: To avoid CPU-specific assembly language calls, QNX Neutrino provides the following calls: InterruptEnable() and InterruptDisable(), and InterruptLock() and InterruptUnlock(). These take care of all the low-level details on all supported platforms.

The ISR usually performs the minimum amount of work possible, and then ends (in our analogy, this was the conversation on the telephone with the VIC—we usually don't put the customer on hold and do several hours of work; we just tell the customer, “Okay, I'll get right on that!”). When the ISR ends, it can tell the kernel either that nothing should happen (meaning the ISR has completely handled the event and nothing else needs to be done about it) or that the kernel should perform some action that might cause a thread to become READY.

In our analogy, telling the kernel that the interrupt was handled would be like telling the customer the answer—we can return to whatever we were doing, knowing that the customer has had their question answered.

Telling the kernel that some action needs to be performed is like telling the customer that you'll get back to them—the telephone has been hung up, but it could ring again.