Signals (XForms (Forms Library) - Version 1.2 (Rev. 4) A Graphical User Interface Toolkit for X)

Next: Idle Callbacks and Timeouts, Previous: Doing Interaction, Up: Part V Overview of Main Functions [Contents][Index]

### 32.6 Signals

Typically, when a signal is delivered, the application does not know what state the application is in, thus limiting the tasks a signal handler can do. In a GUI system and with a main loop inside the library, it’s even harder to know what’s safe or unsafe to do in a signal handler. Given all these difficulties, the Forms Library’s main loop is made to be aware of signal activities and invoke signal handlers only when it’s appropriate to do so, thus removing most limitations on what a signal handler can do.

The application program can elect to handle the receipt of a signal by registering a callback function that gets called when a signal is caught

    typedef void (*FL_SIGNAL_HANDLER)(int, void *);

    void fl_add_signal_callback(int signal, FL_SIGNAL_HANDLER sh,
                                void *data);

Only one callback per signal is permitted. By default, `fl_add_signal_callback()` will store the callback function and initiate a mechanism for the OS to deliver the signal when it occurs. When the signal is received by the library, the main loop will invoke the registered callback function when it is appropriate to do so. The callback function can make use of all of XForms’s functions as well as Xlib functions as if they were reentrant. Further, a signal callback registered his way is persistent and will cease to function only when explicitly removed.

It is very simple to use this routine. For example, to prevent a program from exiting prematurely due to signals, a code fragment similar to the following can be used:

    void clean_up(int signum, void *data) {
        /* clean up, of course */
    }

    /* call this somewhere after fl_initialize() */
    fl_add_signal_callback(SIGINT, clean_up, &mydata);

After this, whenever a `SIGINT` signal is received, `clean_up()` is called.

To remove a signal callback, the following routine should be used

    void fl_remove_signal_callback(int signal);

Although very easy to use, there are limitations with the default behavior outlined above. For example on some platforms there is no blocking of signals of any kind while handling a signal. In addition, use of `fl_add_signal_callback()` prevents the application program from using any, potentially more flexible, system signal handling routines on some platforms. Also there might be perceptible delays from the time a signal is delivered by the OS and the time its callback is invoked by XForms’ main loop. This delay can be particular troublesome for timing sensitive tasks (playing music for example).

In light of these limitations, provisions are made so an application program may choose to take over the initial signal handling setup and receipt via various system dependent methods (`sigaction()` for example).

To change the default behavior of the built-in signal facilities, the following routine should be called prior to any use of `fl_add_signal_callback(`) with a true value for `flag`:

    void fl_app_signal_direct(int flag);

After this call `fl_add_signal_callback()` will not initiate any actions to receive a signal. The application program should handle the receipt and blocking of signals (via e.g., `signal(2)`, `sigaction(2)`, `sigprocmask(2`) etc.) When the signal is received by the application program, it should call the following routine to inform the main loop of the delivery of the signal `signum`, possibly after performing some timing sensitive tasks:

    void fl_signal_caught(int signum);

This routine is the only one in the library that can be safely called from within a direct application signal handler. If multiple invocations of `fl_signal_caught()` occur before the main loop is able to call the registered callback, the callback is called only once.

The following example illustrates how to handle a timing critical situation (for most application, idle callback, timeouts or `FL_TIMER` object should be sufficient).

First, you need to define the function that will handle the timing critical tasks. The function will be registered with the OS to be invoked directly by it. There are limitations on what you can do within a (OS) signal handler, in particular, GUI activity is not safe.

    void timing_critical_task(int sig) {
        /* handle timing critical tasks that does not involve GUI */
        ...
        /* Now tell the library the signal has been delivered by the OS.
         * The library will invoke the xforms signal handler when it's
         * appropriate to do so */
        fl_signal_caught(sig);
    }

Now define a (XForms) signal handler that will be responsible for handling the response of the GUI upon receipt of the signal

    void gui_signal_handler(int sig, void *data) {
        /* within an XForms signal handler, there is no limitation
         * on GUI activitity */
        fl_set_object_color(....);
        ...
    }

To make all this work, a set-up similar to the following can be used

    /* setup the signal */
    fl_app_signal_direct(1);
    setitimer(ITIMER_REAL, interval);

    /* setup the OS signal handler */
    signal(SIGALRM, timing_critical_tasks);

    /* setup the XForms signal handler */
    fl_add_signal_callback(SIGALRM, gui_signal_handler, &myData);

Next: Idle Callbacks and Timeouts, Previous: Doing Interaction, Up: Part V Overview of Main Functions [Contents][Index]