## 4.10 Handling signals

As of version 3.1.0, SWI-Prolog is capable to handle software interrupts (signals) in Prolog as well as in foreign (C) code (see section 9.4.12).

Signals are used to handle internal errors (execution of a non-existing CPU instruction, arithmetic domain errors, illegal memory access, resource overflow, etc.), as well as for dealing asynchronous inter-process communication.

Signals are defined by the POSIX standard and part of all Unix machines. The MS-Windows Win32 provides a subset of the signal handling routines, lacking the vital functionality to raise a signal in another thread for achieving asynchronous inter-process (or inter-thread) communication (Unix kill() function).

on_signal(+Signal, -Old, :New)
  Determines the reaction on Signal. Old is unified with the old behaviour, while the behaviour is switched to New. As with similar environment-control predicates, the current value is retrieved using `on_signal(Signal, Current, Current)`.

  The action description is an atom denoting the name of the predicate that will be called if Signal arrives. on_signal/3 is a meta-predicate, which implies that <Module>:<Name> refers the <Name>/1 in the module <Module>. The handler is called with a single argument: the name of the signal as an atom. The Prolog names for signals is explained below.

  Two predicate-names have special meaning. `throw` implies Prolog will map the signal onto a Prolog exception as described in section 4.9. `default` resets the handler to the settings active before SWI-Prolog manipulated the handler.

  Signals bound to a foreign function through PL_signal() are reported using the term `$foreign_function(Address)`.

  After receiving a signal mapped to `throw`, the exception raised has the structure

  > `error(signal(<SigName>, <SigNum>), <Context>)`

  One possible usage of this is, for example, to limit the time spent on proving a goal. This requires a little C-code for setting the alarm timer (see chapter 9):

      #include <SWI-Prolog.h>
      #include <unistd.h>

      foreign_t
      pl_alarm(term_t time)
      { double t;

        if ( PL_get_float(time, &t) )
        { alarm((long)(t+0.5));

          PL_succeed;
        }

        PL_fail;
      }

      install_t
      install()
      { PL_register_foreign("alarm", 1, pl_alarm, 0);
      }

  Next, we can define the Prolog below. This will run Goal just as once/1, throwing the exception `error(signal(alrm, _), _)` if a timeout occurs.31Note that call_with_time_limit/2 is defined in `library(time)`, part of the `clib' package. The version provided in the library runs on POSIX systems as well as MS-Windows and can schedule multiple concurrent alarms.

      :- load_foreign_library(alarm).

      :- on_signal(alrm, _, throw).

      :- meta_predicate
              call_with_time_limit(+, 0).

      call_with_time_limit(MaxTime, Goal) :-
              alarm(MaxTime),
              call_cleanup(Goal, _, alarm(0)), !.

  The signal names are defined by the POSIX standard as symbols of the form `SIG`<SIGNAME>. The Prolog name for a signal is the lowercase version of <SIGNAME>. The predicate current_signal/3 may be used to map between names and signals.

  Initially, some signals are mapped to `throw`, while all other signals are `default`. The following signals throw an exception: `ill`, `fpe`, `segv`, `pipe`, `alrm`, `bus`, `xcpu`, `xfsz` and `vtalrm`.

current_signal(?Name, ?Id, ?Handler)
  Enumerate the currently defined signal handling. Name is the signal name, Id is the numerical identifier and Handler is the currently defined handler (see on_signal/3).

### 4.10.1 Notes on signal handling

Before deciding to deal with signals in your application, please consider the following:

- Portability
  On MS-Windows, the signal interface is severely limited. Different Unix brands support different sets of signals, and the relation between signal name and number may vary.

- Safety
  Signal handling is not completely safe in the current implementation, especially if `throw` is used in combination with external foreign code. The system will use the C longjmp() construct to direct control to the innermost PL_next_solution(), thus forcing an external procedure to be abandoned at an arbitrary moment. Most likely not all SWI-Prolog's own foreign code is (yet) safe too. For the multi-threaded versions this is even worse: signals can easily violate thread synchronisation consistency.

  The C-interface described in section 9.4.12 provides the option `PL_SIGSYNC` for registering a signal handler that delays delivery of signals to a safe point. Unfortunately this may cause signals to be delayed for a long time if Prolog is executing foreign code.

- Garbage Collection
  The garbage collector will block all signals that are handled by Prolog. While handling a signal, the garbage-collector is disabled.

- Time of delivery
  Normally delivery is immediate (or as defined by the operating system used). Signals are blocked when the garbage collector is active, and internally delayed if they occur within a `critical section'. The critical sections are generally very short.