Node:Signal Handling, Up:Calling Prolog Asynchronously



Signal Handling

As noted above it is not possible to call e.g. SP_query() or even SP_event() from an arbitrary signal handler. That is, from signal handlers installed with signal or sigaction. Instead you need to install the signal handler using SP_signal().

When the OS delivers a signal sig for which SP_signal(sig,func) has been called SICStus will not call func immediately. Instead the call to func will be delayed until it is safe for Prolog to do so, in much the same way that functions installed by SP_event() are handled (this is an incompatible change from SICStus 3.8 and earlier).

Since the signal handling function func will not be called immediately upon delivery of the signal to the process it only makes sense to use SP_signal() to handle certain asynchronous signals such as SIGINT, SIGUSR1, SIGUSR2. Other asynchronous signals handled specially by the OS, such as SIGCHLD are not suitable for handling via SP_signal(). Note that the development system installs a handler for SIGINT, and, under Windows, SIGBREAK, to catch keyboard interrupts. Under UNIX, library(timeout) currently uses SIGVTALRM.

When func is called it may only call other (non SICStus) C code and SP_event(). Note that func will be called in the main thread.

To install a function, func, as a handler for the signal sig, call:

typedef void SP_SigFun (int);
SP_SigFun SP_signal (int sig, SP_SigFun fun);

SP_signal() returns SP_SIG_ERR on error. On success, SP_signal() returns some unspecified value different from SP_SIG_ERR.

If fun is one of the special constants SP_SIG_IGN or SP_SIG_DFL, then one of two things happens. If a signal handler for sig has already been installed with SP_signal(), then the SICStus OS-level signal handler is removed and replaced with, respectively, SIG_IGN or SIG_DFL. If a signal handler has not been installed with SP_signal(), then SP_signal() does nothing and returns SP_SIG_ERR.

A signal handler installed by a foreign resource should be uninstalled in the deinit function for the foreign resource. This is to prevent the handler in the foreign resource from being called after the code of the foreign resource has been unloaded (e.g. by unload_foreign_resource/1).

The following two functions were used prior to SICStus 3., but are obsolete now:

SP_SigFun SP_reinstall_signal (int sig, SP_SigFun)  obsolescent
void SP_continue(void)  obsolescent
they are no-ops.

The following piece of C code illustrates these facilities. The function signal_init() installs the function signal_handler() as the primary signal handler for the signals SIGUSR1 and SIGUSR2. That function invokes the predicate user:prolog_handler/1 as the actual signal handler, passing the signal number as an argument to the predicate.

SP_pred_ref event_pred;

static int signal_event(void *handle)
{
  int signal_no = (int) handle;
  SP_term_ref x=SP_new_term_ref();
  int rc;

  SP_put_integer(x, signal_no); /* Should not give an error */
  rc = SP_query(event_pred, x);
  if (rc == SP_ERROR && SP_exception_term(x))
    SP_raise_exception(x);        /* Propagate any raised exception */
  return rc;
}

static void signal_handler(int signal_no)
{
  SP_event(signal_event, (void *)signal_no);
  /* The two calls below are for SICStus 3.8 compatibility */
  SP_reinstall_signal(signal_no, signal_handler);
  SP_continue();
}

void signal_init(void)
{
  event_pred = SP_predicate("prolog_handler",1,"user");

  SP_signal(SIGUSR1, signal_handler);
  SP_signal(SIGUSR2, signal_handler);
}