26.02.2014 Views

Getting Started with QNX Neutrino - QNX Software Systems

Getting Started with QNX Neutrino - QNX Software Systems

Getting Started with QNX Neutrino - QNX Software Systems

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Writing interrupt handlers<br />

© 2009, <strong>QNX</strong> <strong>Software</strong> <strong>Systems</strong> GmbH & Co. KG.<br />

on us. With InterruptAttachEvent(), the kernel has no idea whether or not the<br />

hardware event that caused the interrupt was “significant” for us, so it drops the event<br />

on us every time it occurs, masks the interrupt, and lets us decide if the interrupt was<br />

significant or not.<br />

We handled the decision in the code example for InterruptAttach() (above) by<br />

returning either a struct sigevent to indicate that something should happen, or by<br />

returning the constant NULL. Notice the changes that we did to our code when we<br />

modified it for InterruptAttachEvent():<br />

• The “ISR” work is now done at thread time in main().<br />

• We must always unmask the interrupt source after receiving our event (because the<br />

kernel masks it for us).<br />

• If the interrupt is not significant to us, we don’t do anything and simply loop<br />

around again in the for statement, waiting for another interrupt.<br />

• If the interrupt is significant to us, we handle it directly (in the case IIR_MSR<br />

part).<br />

Where you decide to clear the source of the interrupt depends on your hardware and<br />

the notification scheme you’ve chosen. With the combination of SIGEV_INTR and<br />

InterruptWait(), the kernel doesn’t “queue” more than one notification; <strong>with</strong><br />

SIGEV_PULSE and MsgReceive(), the kernel will queue all the notifications. If you’re<br />

using signals (and SIGEV_SIGNAL, for example), you define whether the signals are<br />

queued or not. With some hardware schemes, you may need to clear the source of the<br />

interrupt before you can read more data out of the device; <strong>with</strong> other pieces of<br />

hardware, you don’t have to and can read data while the interrupt is asserted.<br />

An ISR returning SIGEV_THREAD is one scenario that fills me <strong>with</strong> absolute fear! I’d<br />

recommend avoiding this “feature” if at all possible.<br />

In the serial port example above, we’ve decided to use InterruptWait(), which will<br />

queue one entry. The serial port hardware may assert another interrupt immediately<br />

after we’ve read the interrupt identification register, but that’s fine, because at most one<br />

SIGEV_INTR will get queued. We’ll pick up this notification on our next iteration of<br />

the for loop.<br />

InterruptAttach() versus InterruptAttachEvent()<br />

This naturally brings us to the question, “Why would I use one over the other?”<br />

The most obvious advantage of InterruptAttachEvent() is that it’s simpler to use than<br />

InterruptAttach() — there’s no ISR routine (hence no need to debug it). Another<br />

advantage is that since there’s nothing running in kernel space (as an ISR routine<br />

would be) there’s no danger of crashing the entire system. If you do encounter a<br />

programming error, then the process will crash, rather than the whole system.<br />

However, it may be more or less efficient than InterruptAttach() depending on what<br />

you’re trying to achieve. This issue is complex enough that reducing it to a few words<br />

182 Chapter 4 • Interrupts April 30, 2009

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!