Thanks to mescalinum who confirmed signal handling is not available by default in GNU Prolog.
But GNU Prolog has excellent support for user routines in C, and I've been able to write a small amount of C code which catches the Linux signal and triggers (if required) a Prolog exception (note mine is Ubuntu 14.04/GNU Prolog 1.3.0 so C type for init_signal
function is Bool
from gprolog.h - this changed in gprolog.h 1.3.1 onwards to PlBool
- see 1.3.0 vs most recent manuals):
C code "signal.c":
#include <stdio.h>
#include <signal.h>
#include <gprolog.h>
/* signal handler */
void sig_handler(int signo)
{
if (signo == SIGHUP)
{
printf("received SIGHUP\n");
/* throw Prolog exception */
Pl_Err_Instantiation();
}
}
/* GNU Prolog goal that registers the signal handler */
/* declared with :- foreign(init_signal). */
Bool init_signal()
{
if (signal(SIGHUP, sig_handler) == SIG_ERR)
{
printf("\ncan't catch SIGHUP\n");
}
printf("%s","SIGHUP handler registered\n");
return TRUE; /* succeed */
}
Test usage in Prolog "test.pl" - the "long-running" query in this example is o_query, used in a 'catch' relation and can be interrupted with SIGHUP:
:- foreign(init_signal).
:- initialization(main).
main :- write('Prolog signal test program started'),
nl,
init_signal,
catch(o_query,X,write('Prolog exception thrown')),
nl,
halt.
o_query :- repeat,
sleep(1),
fail.
Compile with gplc test.pl signal.c
Now if the program is run with ./test it can be interrupted from another terminal with kill -1 <test process id>
Bambam@desktop:~/prolog/signal$ ./test
Prolog signal test program started
SIGHUP handler registered
received SIGHUP
Prolog exception thrown
Bambam@desktop:~/prolog/signal$
For my purposes, I can usefully handle the incoming exception while I'm in the C signal handler, but reflecting it back to a Prolog 'throw' (in this case with a 'instantiation error') keeps the code tidily within Prolog.
The reason I want to be able to send (and catch) a signal to the executing GNU Prolog process is because my system is a high-performance parallel processing Prolog environment which can trigger any long-running Prolog process to dynamically 'split' itself into multiple parts which then execute on other machines. But you fundamentally cannot (with my method) predict the exact distribution of work and in due course other processors will be interrupted (i.e. sent a signal) to further split the workload.
call_nth/2
down to a couple of integers. Thus writing is something like 50 bytes... – Concertante