InterruptAttachEvent(), InterruptAttachEvent_r(), InterruptAttachEventPriority(), InterruptAttachEventPriority_r()

QNX SDP8.0C Library ReferenceAPIDeveloper

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().

Note:
If you want your code to be compatible with both QNX SDP 8.0 and QNX 7.x, it's convenient to use InterruptAttachEvent() or InterruptAttachEvent_r().

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:

QNX OS

Safety:
Cancellation pointNo
Signal handlerYes
ThreadYes
Page updated: