How to fill in the struct sigevent

Let's take a quick look at how you fill in the struct sigevent structure.

Regardless of the notification scheme you choose, you'll need to fill in a struct sigevent structure. For the details, see the C Library Reference; here's a simplified version:

struct sigevent {
    int                             sigev_notify;
    union {
            int                     __sigev_signo;
            int                     __sigev_coid;
            int                     __sigev_id;
            void                    (*__sigev_notify_function)(union sigval);
            volatile unsigned       *__sigev_addr;
    } __sigev_un1;

    union sigval                    sigev_value;

    union {
            struct {
                    short           __sigev_code;
                    short           __sigev_priority;
            } __st;
            pthread_attr_t          *__sigev_notify_attributes;
            int                     __sigev_memop;
        } __sigev_un2;

Note: Note that the above definition uses various unions and structures, but there are #define statements that make it easier for you to access the members. Check out <sys/siginfo.h> for details.

The first field you have to fill in is the sigev_notify member. This determines the notification type you've selected:

A pulse will be sent.
A signal will be sent.
Not used in this case; used with kernel timeouts (see "Kernel timeouts" below).
Not used in this case; used with interrupts (see the Interrupts chapter).
Creates a thread.

Since we're going to be using the struct sigevent with timers, we're concerned only with the SIGEV_PULSE, SIGEV_SIGNAL* and SIGEV_THREAD values for sigev_notify; we'll see the other types as mentioned in the list above.

Pulse notification

To send a pulse when the timer fires, set the sigev_notify field to SIGEV_PULSE and provide some extra information:

Field Value and meaning
sigev_coid Send the pulse to the channel associated with this connection ID.
sigev_value A 32-bit value that gets sent to the connection identified in the sigev_coid field.
sigev_code An 8-bit value that gets sent to the connection identified in the sigev_coid field.
sigev_priority The pulse's delivery priority. The value zero is not allowed (too many people were getting bitten by running at priority zero when they got a pulse—priority zero is what the idle task runs at, so effectively they were competing with QNX Neutrino's IDLE process and not getting much CPU time :-)).

Note that the sigev_coid could be a connection to any channel (usually, though not necessarily, the channel associated with the process that's initiating the event).

Signal notification

To send a signal, set the sigev_notify field to one of:

Send a regular signal to the process.
Send a signal containing an 8-bit code to the process.
Send a signal containing an 8-bit code to a specific thread.

For SIGEV_SIGNAL*, the additional fields you'll have to fill are:

Field Value and meaning
sigev_signo Signal number to send (from <signal.h>, e.g., SIGALRM).
sigev_code An 8-bit code (if using SIGEV_SIGNAL_CODE or SIGEV_SIGNAL_THREAD).

Thread notification

To create a thread whenever the timer fires, set the sigev_notify field to SIGEV_THREAD and fill these fields:

Field Value and meaning
sigev_notify_function Address of void * function that accepts a void * to be called when the event triggers.
sigev_value Value passed as the parameter to the sigev_notify_function() function.
sigev_notify_attributes Thread attributes structure (see the Processes and Threads chapter, under "The thread attributes structure" for details).
Note: This notification type is a little scary! You could have a whole slew of threads created if the timer fires often enough and, if there are higher priority threads waiting to run, this could chew up all available resources on the system! Use with caution!

General tricks for notification

There are some convenience macros in <sys/siginfo.h> to make filling in the notification structures easier (see the entry for sigevent in the QNX Neutrino C Library Reference):

SIGEV_SIGNAL_INIT (eventp, signo)
Fill eventp with SIGEV_SIGNAL, and the appropriate signal number signo.
SIGEV_SIGNAL_CODE_INIT (eventp, signo, value, code)
Fill eventp with SIGEV_SIGNAL_CODE, the signal number signo, as well as the value and code.
SIGEV_SIGNAL_THREAD_INIT (eventp, signo, value, code)
Fill eventp with SIGEV_SIGNAL_THREAD, the signal number signo, as well as the value and code.
SIGEV_PULSE_INIT (eventp, coid, priority, code, value)
Fill eventp with SIGEV_PULSE, the connection to the channel in coid and a priority, code, and value. Note that there is a special value for priority of SIGEV_PULSE_PRIO_INHERIT that causes the receiving thread to run at the process's initial priority.
Fill eventp with SIGEV_UNBLOCK.
Fill eventp with SIGEV_INTR.
SIGEV_THREAD_INIT (eventp, func, val, attributes)
Fill eventp with the thread function (func) and the attributes structure (attributes). The value in val is passed to the function in func when the thread is executed.