En GNU-Prolog, ¿puedo "capturar" una señal de linux?
(2)
¿Hay una manera de "atrapar" (por ejemplo, "atrapar") una señal del sistema operativo dentro de GNU Prolog? (Estoy usando Ubuntu / Linux, último gprolog).
Creo que hace mucho tiempo usé este enfoque en WAMCC, antes de que se transformara en GNU Prolog:
:- catch(Long_Running_Goal,signal(2),write(''program interrupted''))
Pero si pruebo esto usando un bucle infinito (repetir, fallar) con, por ejemplo
:- catch((repeat,fail),X,write(X)).
En el intérprete, Ctrl-C todavía me lleva al rastreo / depurador, y el programa compilado simplemente se cierra si lo interrumpo con kill -1
, kill -2
etc.
He intentado compilar el programa con --no-top-level
en caso de que el --no-top-level
predeterminado capture la señal, pero eso no hizo ninguna diferencia.
SWI-Prolog parece tener un predicado incorporado adecuado on_signal
que cumple su función, pero estoy buscando una solución con gprolog si eso es posible.
Después de mirar el código fuente actual de gprolog donde se usa la signal()
:
- src / BipsPl / os_interf_c.c:
signal(SIGPIPE, SIG_IGN);
- src / EnginePl / LINUX_SIGSEGV.c:
signal(SIGSEGV, (void (*)()) SIGSEGV_Handler);
- src / EnginePl / PPC_SIGSEGV.c:
signal(SIGSEGV, (void (*)()) SIGSEGV_Handler);
- src / EnginePl / SOLARIS_SIGSEGV.c:
signal(SIGSEGV, (void (*)()) SIGSEGV_Handler);
- src / EnginePl / stacks_sigsegv.c:
signal(SIGSEGV, (void (*)(int)) SIGSEGV_Handler);
- src / EnginePl / WIN32_all_SIGSEGV.c:
signal(SIGSEGV, (void (*)(int)) SIGSEGV_Handler);
- src / Linedit / ctrl_c.c:
signal(sig, Wrapper_Handler);
- src / Linedit / ctrl_c.c:
signal(SIGINT, Wrapper_Handler);
Podemos ver que el único uso de las señales es:
- para manejar
SIGINT
(generado presionando CTRL + C ) en el REPL - para manejar
SIGSEGV
- ignorar
SIGPIPE
Por lo tanto, no es posible, a menos que esté dispuesto a modificar el código fuente.
Además, no pude encontrar ninguna mención de señales en los mensajes de confirmación de git.
Gracias a mescalinum que confirmó share .
Pero GNU Prolog tiene un excelente soporte para rutinas de usuario en C, y he podido escribir una pequeña cantidad de código C que captura la señal de Linux y dispara (si es necesario) una excepción Prolog (tenga en cuenta que Ubuntu 14.04 / GNU Prolog 1.3 .0 por lo que el tipo C para la función init_signal
es Bool
de gprolog.h - esto cambió en gprolog.h 1.3.1 en adelante a PlBool
- ver 1.3.0 vs manuales más recientes ):
Código C "señal.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 */
}
Uso de prueba en Prolog "test.pl": la consulta "de larga duración" en este ejemplo es o_query, se usa en una relación de "captura" y se puede interrumpir con 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.
Compilar con gplc test.pl signal.c
Ahora, si el programa se ejecuta con ./test, se puede interrumpir desde otro terminal con 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$
Para mis propósitos, puedo manejar útilmente la excepción entrante mientras estoy en el controlador de señal C, pero reflejándolo de nuevo a un ''lanzamiento'' de Prolog (en este caso con un ''error de creación de instancias'') mantiene el código ordenadamente dentro de Prolog.
La razón por la que quiero poder enviar (y capturar) una señal al proceso de Prolog GNU en ejecución es porque mi sistema es un entorno Prolog de procesamiento paralelo de alto rendimiento que puede desencadenar cualquier proceso Prolog de larga ejecución para que se "divida" dinámicamente en Piezas múltiples que luego se ejecutan en otras máquinas. Pero fundamentalmente no puede (con mi método) predecir la distribución exacta del trabajo y, a su debido tiempo, otros procesadores se interrumpirán (es decir, se enviará una señal) para dividir aún más la carga de trabajo.