Attach an event to an interrupt source
#include <sys/neutrino.h> int InterruptAttachEvent( int intr, const struct sigevent* event, unsigned flags ); int InterruptAttachEvent_r( int intr, const struct sigevent* event, unsigned flags );
- The interrupt vector number that you want to attach an event to; for more information, see Interrupt vector numbers in the documentation for InterruptAttach().
- A pointer to the sigevent structure that you want to be delivered when this interrupt occurs.
- Flags that specify how you want to attach the interrupt handler. For more information, see Flags, below.
Use the -l c option to qcc to link against this library. This library is usually included automatically.
The InterruptAttachEvent() and InterruptAttachEvent_r() kernel calls attach the given event to the hardware interrupt specified by intr. They automatically enable (i.e., unmask) the interrupt level.
The InterruptAttachEvent() and InterruptAttachEvent_r() functions are identical except in the way they indicate errors. See the Returns section for details.
Before calling either of these functions, the thread must:
- have the PROCMGR_AID_INTERRUPT and PROCMGR_AID_IO abilities enabled. For more information, see procmgr_ability().
- request I/O privileges by calling:
ThreadCtl( _NTO_TCTL_IO, 0 );
If the thread doesn't have the appropriate abilities, the call to InterruptAttachEvent() fails with an error of EPERM; if the thread doesn't successfully call ThreadCtl(), it might SIGSEGV when it calls InterruptAttachEvent() or InterruptAttachEvent_r().
To prevent infinite interrupt recursion, the kernel automatically does an InterruptMask() for intr when delivering the event. After the interrupt-handling thread has dealt with the event, it must call InterruptUnmask() to reenable the interrupt.
Consider the following when choosing an event type:
- Message-driven processes that block in a receive loop using MsgReceivev() should consider using SIGEV_PULSE to trigger a channel.
- Threads that block at a particular point in their code and don't go
back to a common receive point, should consider using
SIGEV_INTR as the event notification type and
as the blocking call.
The thread that calls InterruptWait() must be the one that called InterruptAttachEvent().
- Using SIGEV_SIGNAL, SIGEV_SIGNAL_CODE, or SIGEV_SIGNAL_THREAD is discouraged. It is less efficient than the other mechanisms for interrupt event delivery.
On a multicore system, the thread that receives the event set up by InterruptAttachEvent() runs on any CPU, limited only by the scheduler and the runmask.
The flags argument is a bitwise OR of the following values, or 0:
|_NTO_INTR_FLAGS_END||Put the new event at the end of the list of existing events instead of the start.|
|_NTO_INTR_FLAGS_PROCESS||Associate the event with the process instead of the attaching thread.|
|_NTO_INTR_FLAGS_TRK_MSK||Track calls to InterruptMask() and InterruptUnmask() to make detaching the interrupt handler safer.|
The interrupt structure allows hardware interrupts to be shared. For example if two processes call InterruptAttachEvent() for the same physical interrupt, both events are sent consecutively. When an event attaches, it's placed in front of any existing events for that interrupt and is delivered first. You can change this behavior by setting the _NTO_INTR_FLAGS_END flag in the flags argument. This adds the event at the end of any existing events.
Adding _NTO_INTR_FLAGS_PROCESS to flags associates the interrupt event with the process instead of the attaching thread. The interrupt event is removed when the process exits, instead of when the attaching thread exits.
The _NTO_INTR_FLAGS_TRK_MSK flag and the id argument to InterruptMask() and InterruptUnmask() let the kernel track the number of times a particular interrupt handler or event has been masked. Then, when an application detaches from the interrupt, the kernel can perform the proper number of unmasks to ensure that the interrupt functions normally. This is important for shared interrupt levels.
Advantages & disadvantages
InterruptAttachEvent() has several advantages over InterruptAttach():
- Less work is done at interrupt time (you avoid the context switch necessary to map in an interrupt handler).
- Interrupt handling code runs at the thread's priority, which lets you specify the priority of the interrupt handling.
- You can use process-level debugging on your interrupt handler code.
- It isn't safe to use floating-point operations in Interrupt Service Routines.
There are also some disadvantages:
- There might be a delay before the interrupt handling code runs (until the thread is scheduled to run).
- For multiple devices sharing an event, the amount of time spent with the interrupt masked increases.
You can freely mix calls to InterruptAttach() and InterruptAttachEvent() for a particular interrupt.
This call doesn't block.
The only difference between these functions is the way they indicate errors:
- An interrupt function ID. If an error occurs, -1 is returned and errno is set.
- An interrupt function ID. This function does NOT set errno. If an error occurs, the negative of a value from the Errors section is returned.
Use the ID with InterruptDetach() to detach this interrupt event.
- All kernel interrupt entries are in use.
- A fault occurred when the kernel tried to access the buffers provided.
- The value of intr isn't a valid interrupt number.
- The process doesn't have I/O privileges, or it doesn't have the required permission; see procmgr_ability().