Notification schemes

How do you receive a timeout notification? With the delay timer, you received notification by virtue of being made READY again. With periodic and one-shot timers, you have a choice:

We've talked about pulses in Message passing, signals are a standard UNIX-style mechanism, and we'll talk about the thread creation notification type shortly.

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 need to fill in a struct sigevent structure:

struct sigevent {
    int                 sigev_notify;

    union {
        int             sigev_signo;
        int             sigev_coid;
        int             sigev_id;
        void          (*sigev_notify_function) (union sigval);
    };

    union sigval        sigev_value;

    union {
        struct {
            short       sigev_code;
            short       sigev_priority;
        };
        pthread_attr_t *sigev_notify_attributes;
    };
};
Note: Note that the above definition uses anonymous unions and structures. Careful examination of the header file shows you how this trick is implemented on compilers that don't support these features. Basically, there's a #define that uses a named union and structure to make it look like it's an anonymous union. 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:

SIGEV_PULSE
A pulse is sent.
SIGEV_SIGNAL, SIGEV_SIGNAL_CODE, or SIGEV_SIGNAL_THREAD
A signal is sent.
SIGEV_UNBLOCK
Not used in this case; used with kernel timeouts (see Kernel timeouts).
SIGEV_INTR
Not used in this case; used with interrupts.
SIGEV_THREAD
Creates a thread.

Since we are using the struct sigevent with timers, we're concerned only with the SIGEV_PULSE, SIGEV_SIGNAL* and SIGEV_THREAD values for sigev_notify; we 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 caught 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 BlackBerry 10 OS'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:

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

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

Field Value and meaning
sigev_signo Signal number to send (from <signal.h>, for example, 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 thread attributes structure for details).
Note: This notification type is a little scary! You can have a lot of threads created if the timer fires often enough and, if there are higher priority threads waiting to run, this can 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 BlackBerry 10 OS 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_SIGNAL_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.
SIGEV_UNBLOCK_INIT ( eventp )
Fill eventp with SIGEV_UNBLOCK.
SIGEV_INTR_INIT ( eventp )
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.

Pulse notification

Suppose you're designing a server that spent most of its life RECEIVE blocked, waiting for a message. Wouldn't it be ideal to receive a special message, one that told you that the time you had been waiting for finally arrived? This scenario is exactly where you should use pulses as the notification scheme. In Using timers , there is some sample code that can be used to get periodic pulse messages.

Signal notification

Suppose that, you're performing some kind of work, but don't want that work to go on forever. For example, you may be waiting for some function call to return, but you can't predict how long it takes. In this case, using a signal as the notification scheme, with perhaps a signal handler, is a good choice (another choice we'll discuss later is to use kernel timeouts; see _NTO_CHF_UNBLOCK . In Using timers, we'll see a sample that uses signals.

Note: It isn't safe to use floating-point operations in signal handlers.

Alternatively, a signal with sigwait() is cheaper than creating a channel to receive a pulse on, if you're not going to be receiving messages in your application anyway.