{
sigchld_delivered++;
}
The actual sigchld_handler() routine can do whatever it needs to do, including call Xlib routines, since it is
only called when it is safe to do so. You should note that XNextEvent() waits until it reads an event from the X
server before it returns, so handling the signal may take a long time if the program is waiting for the user to do
something.
These code fragments demonstrate the general design for handling signals in a rudimentary way. In a real application,
the actual signal handler would probably need access to all of the parameters passed to the original signal handling
function. One example of this situation would be a signal handler that displays the values of all its parameters in a
dialog box. You can't change anything on the display using the original signal handler because it would require
making Xlib calls, so you have to save the parameters until the real signal handler is called. To save the parameters,
you could define a data structure that contains fields for all of the parameters. The original signal handler could
allocate a new structure and fill it in each time a signal is delivered. As we will discuss later, there can also be
problems with memory allocation in a signal handler. When the real signal handler is called, it can access the data
structure and create a dialog using the appropriate Xlib calls.
21.2 Handling Signals in Xt
Since this is a book on Motif and Motif is based on Xt, the next step is to find a solution that is appropriate for
Xt−based applications. In Xt, you typically don't read events directly from the X server using XNextEvent() and
then branch on the event type to decide what to do next. Instead, Xt provides XtAppMainLoop(); the code for this
function is below:
void
XtAppMainLoop(app_context)
XtAppContext app_context;
{
XEvent event;
for (;;) {
XtAppNextEvent (app_context, &event);
XtDispatchEvent (&event);
}
}
Since the event processing loop is internal to the Xt toolkit, we don't have the opportunity to insert a check to see if
any signals have been delivered, as we did with Xlib. There are various ways to handle this problem. We could write
our own event processing loop and include code that tests for the delivery of a signal. One problem with this solution
is that it bypasses a standard library routine. We want to ensure upwards compatibility with future versions of Xt, and
if we write our own routine, we risk losing any functionality that might be introduced later.
Even though it is unlikely that XtAppMainLoop() will change in the future, we should find another way to solve
the problem. Clearly, the desired effect is to get Xt to notify us just before it's going to call XNextEvent(), since
this is the window of opportunity where it is safe for a signal handler to make Xlib or Xt calls. It just so happens that
Xt provides two methods that do what we want: work procedures and timers.
A work procedure is a function that is called by Xt when it does not have any events to process. Although an
application can register multiple work procedures, the procedures are processed one at a time, with the most recent
one being invoked first. We can solve the signal handler problem using a work procedure because most applications
spend a fair bit of time waiting for the user to generate events. In the signal handler, we register a work procedure
21 Signal Handling 21.2 Handling Signals in Xt
590
using XtAppAddWorkProc(). When the application is idle, Xt invokes the work procedure, which does the real
work of handling the signal. The following code fragment uses this approach:
XtAppContext app;
static void real_reset(), reset();
main(argc, argv)
int argc;
char *argv[];
{
...
signal (SIGCHLD, real_reset);
...
}
/* reset() −− a program died... */
static void
real_reset()
{
int pid, i;
#ifdef SYSV
int status;
#else
union wait status;
#endif /* SYSV */
if ((pid = wait (&status)) == −1)
/* an error of some kind (fork probably failed); ignore it */
return;
(void) XtAppAddWorkProc (app, reset, NULL);
}
static Boolean
reset(client_data)
XtPointer client_data;
{
/* handle anything Xt/Xlib−related that needs to be done now */
return True; /* remove the work procedure from the list */
}
This example assumes that the application forks off a new process at some point. When the child eventually exits, the
parent is sent a SIGCHLD signal, at which point the application branches directly to the real_reset() signal
handler. This routine reaps the child using wait() and then adds a work procedure using XtAppAddWorkProc().
(The function normally returns a work procedure ID, but we're not interested in it here.) When Xt does not have any
events to process, it calls reset(). This routine can perform any other tasks necessary for handling the signal, such
as calling Xlib routines, popping up dialogs, or anything it likes.
If the application is waiting for events when it receives the signal, the work procedure is invoked almost immediately
after the actual signal handler. However, if the application is in a callback routine handling an event, the work
procedure is not called until control is passed back to the event loop. While it's true that there may be some delay
between the time that the signal is delivered and the time that it is actually processed, the delay is usually small
enough that an application doesn't need to worry about it. If timing is critical, you can always set a global signal flag
when the signal is received, and then test that variable in critical sections of your code to see if the signal has been
delivered.
21 Signal Handling 21.2 Handling Signals in Xt
591

Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.