InterruptAttachEvent(), InterruptAttachEvent_r(), InterruptAttachEventPriority(), InterruptAttachEventPriority_r()
Attach an event to an interrupt source
Synopsis:
#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 );
int InterruptAttachEventPriority(
int const intr,
struct sigevent* const event,
unsigned const prio,
unsigned const flags );
int InterruptAttachEventPriority_r(
int const intr,
struct sigevent* const event,
unsigned const prio,
unsigned const flags );
Arguments:
- intr
- The interrupt vector number that you want to attach an event
to; for more information, see
Interrupt vector numbers
in the documentation for InterruptAttachThread(). - event
- A pointer to the sigevent structure that you want to be delivered when this interrupt occurs. You can associate a maximum of 32 events with an interrupt.
- flags
- Flags that specify how you want to attach the interrupt thread; a bitwise OR of zero or more of
the following:
- _NTO_INTR_FLAGS_END
- _NTO_INTR_FLAGS_NO_UNMASK
- _NTO_INTR_FLAGS_EXCLUSIVE
- _NTO_INTR_FLAGS_CPU_LOCAL
For more information, see
Flags,
below. - prio
- (InterruptAttachEventPriority() and
InterruptAttachEventPriority_r() only) The priority of the IST. The
value of prio must be at least 1 but no greater than the value of the
clock interrupt service thread (IST). By default, out-of-range priority requests
"saturate" to the closest outer limit of this range. For example, if you set
prio to a value less than 1, prio is
automatically set to 1. Note:By default, the clock IST runs at priority 254. You can use procnto's -c option to configure this value.
Library:
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
Description:
The InterruptAttachEvent*() kernel calls attach the given event to the hardware interrupt specified by intr. The event doesn't need to be registered.
The InterruptAttachEvent() and InterruptAttachEvent_r() calls are identical except in the way they indicate errors. The same case applies for InterruptAttachEventPriority() and InterruptAttachEventPriority_r(). See the Returns section for details.
Before a process calls any of
these functions, it must have the PROCMGR_AID_INTERRUPT ability enabled. For
more information, go to Abilities
in the System Security Guide.
If the thread doesn't have the appropriate abilities, the call to InterruptAttachEvent() or InterruptAttachEventPriority() fails with an error of EPERM.
The kernel automatically masks the interrupt before scheduling the attached thread. To receive interrupts after processing, you must either explicitly unmask the interrupt by calling InterruptUnmask(), or have the kernel do so automatically by passing the _NTO_INTR_WAIT_FLAGS_UNMASK when calling InterruptWait().
Consider the following when choosing an event type:
- Using SIGEV_SEM with an anonymous named semaphore increments the semaphore.
- Using SIGEV_INTR doesn't create a new thread; this event type is handled as if
you called InterruptAttachThread(), which makes the calling thread the
IST. When this event type is set, the prio argument is ignored.
Note:An IST can attach to only one interrupt.
- 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
InterruptWait() as the
blocking call.
Note:The thread that calls InterruptWait() must be the one that called InterruptAttachEvent*().
- Using SIGEV_THREAD is very inefficient, because that would create a new thread
for every interrupt.
In order to use an event of type SIGEV_THREAD, your process must have the PROCMGR_AID_SIGEV_THREAD ability enabled.
- For SIGEV_SIGNAL, SIGEV_SIGNAL_CODE, and SIGEV_SIGNAL_THREAD, handling a signal using a signal handler is noticeably inefficient as compared to using pulses. But, delivering a signal to a thread that's blocked on sigwaitinfo() is actually more efficient than the pulse choice, though less efficient than the InterruptWait() choice. The advantage is in flexibility, allowing the thread to be woken up both by interrupts and by other threads in the process as needed. Architecturally, this lets you create a thread that's dedicated to handling hardware.
If you don't use SIGEV_INTR, the InterruptAttachEvent*() and InterruptAttachEvent*_r() calls spawn a thread that calls InterruptAttachThread() or InterruptAttachThread_r(). Once the thread is attached to the interrupt, it becomes an Interrupt Service Thread (IST). The InterruptAttachEventPriority() and InterruptAttachEventPriority_r() calls allow you to set the priority of the IST, specified by prio. The IST remains active until it has been detached using InterruptDetach().
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.
Flags
The flags argument is a bitwise OR of zero or more of the following values:
- _NTO_INTR_FLAGS_END
- Put the new event at the end of the list of existing events instead of the start.
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 _NTO_INTR_FLAGS_END.
- _NTO_INTR_FLAGS_NO_UNMASK
- Leave the interrupt masked.
Normally, InterruptAttachEvent*() automatically unmasks an interrupt the first time something is attached to it. If you specify _NTO_INTR_FLAGS_NO_UNMASK, the kernel leaves the interrupt masked, and you must specifically call InterruptUnmask() to enable it.
- _NTO_INTR_FLAGS_EXCLUSIVE
- Request exclusive access to the interrupt vector. If another thread already called an InterruptAttach*() function with the same vector, this kernel call fails with an EBUSY error. Similarly, if this call succeeds but another thread later calls an InterruptAttach*() function with the same vector, that call fails with the same error.
- _NTO_INTR_FLAGS_CPU_LOCAL
-
Identify that the interrupt vector number, specified by intr, is local to the CPU of the thread that called InterruptAttachEvent*(). The thread's processor affinity must be set to run on a single CPU; the IST inherits the thread's processor affinity.
Blocking states
These calls don't block.
Returns:
A unique interrupt ID that corresponds with the process that called InterruptAttachEvent*(). If an error occurs:
- InterruptAttachEvent() and InterruptAttachEventPriority() return -1 and sets errno.
- InterruptAttachEvent_r() and InterruptAttachEventPriroity_r() return the negative of a value from the Errors section and don't set errno.
Pass this interrupt ID to other calls, such as InterruptDetach() and InterruptMask().
Errors:
- EAGAIN
- One of the following errors occurred:
- Not enough memory is available.
- All kernel interrupt entries are in use.
- The maximum number (32) of threads or events that can be attached to an interrupt has been exceeded.
- EBUSY
- One of the following errors occurred:
- An event type of SIGEV_INTR was specified and the calling thread is already attached to an interrupt.
- You tried to attach a thread to an interrupt, but a thread with the _NTO_INTR_FLAGS_EXCLUSIVE flag was already attached to the interrupt.
- You tried to attach a thread with the _NTO_INTR_FLAGS_EXCLUSIVE flag to an interrupt, but a thread was already attached to the interrupt.
- EFAULT
- A fault occurred when the kernel tried to access the buffers provided.
- EINVAL
- One of the following errors occurred:
- The value of intr isn't a valid interrupt number.
- You specified the _NTO_INTR_FLAGS_CPU_LOCAL flag but the thread's runmask isn't set to run on a single CPU.
- You supplied one of the following events in the structure pointed to by event: SIGEV_NONE, SIGEV_UNBLOCK or SIGEV_SIGNAL_THREAD.
- EPERM
- The process doesn't have the required permission; see procmgr_ability().
Classification:
Safety: | |
---|---|
Cancellation point | No |
Signal handler | Yes |
Thread | Yes |