Могу ли я "поймать" сигнал linux в GNU-Prolog?
Есть ли способ "поймать" (например, "поймать") сигнал операционной системы в GNU Prolog? (Я использую Ubuntu/Linux, последний gprolog).
Я думаю, что давным-давно я использовал этот подход в WAMCC, а затем превратился в GNU Prolog:
:- catch(Long_Running_Goal,signal(2),write('program interrupted'))
Но если я проверю это, используя (повтор, сбой) бесконечный цикл, например, с
:- catch((repeat,fail),X,write(X)).
В интерпретаторе Ctrl-C по-прежнему приводит меня к трассировщику / отладчику, и скомпилированная программа просто выходит, если я прерываю его kill -1
, kill -2
и т.п.
Я пытался скомпилировать программу с --no-top-level
в случае, если уровень по умолчанию каким-то образом захватывает сигнал, но это не имеет значения.
SWI-Prolog, похоже, имеет подходящий встроенный предикат on_signal
которая служит цели, но я ищу решение с gprolog, если это возможно.
2 ответа
Благодаря мескалину, который подтвердил, что обработка сигналов не доступна по умолчанию в GNU Prolog.
Но GNU Prolog имеет отличную поддержку пользовательских подпрограмм на C, и я смог написать небольшое количество кода на C, который перехватывает сигнал Linux и запускает (если требуется) исключение Prolog (обратите внимание, что Ubuntu 14.04/GNU Prolog 1.3.0 так типа C для init_signal
функция Bool
от gprolog.h - это изменилось в gprolog.h 1.3.1 и далее PlBool
- см. 1.3.0 против самых последних руководств):
С кодом "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.pl" - "длительный" запрос в этом примере - это o_query, используемый в отношении "catch" и может быть прерван с помощью 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.
Компилировать с gplc test.pl signal.c
Теперь, если программа запущена с./test, она может быть прервана с другого терминала с 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$
Для моих целей я могу с пользой обработать входящее исключение, пока я нахожусь в обработчике сигнала C, но отражая его обратно в "бросок" Пролога (в данном случае с "ошибкой создания экземпляра"), код аккуратно хранится в Прологе.
Причина, по которой я хочу иметь возможность отправлять (и перехватывать) сигнал выполняющемуся процессу GNU Prolog, заключается в том, что моя система представляет собой высокопроизводительную среду Prolog для параллельной обработки, которая может инициировать любой длительный процесс Prolog для динамического "разделения" себя на несколько частей, которые затем выполняются на других машинах. Но вы принципиально не можете (с моим методом) предсказать точное распределение работы, и со временем другие процессоры будут прерваны (т.е. отправят сигнал) для дальнейшего разделения рабочей нагрузки.
После просмотра текущего исходного кода gprolog, где 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);
мы можем видеть только использование сигналов:
- обрабатывать
SIGINT
(генерируется нажатием CTRL + C) в REPL - обрабатывать
SIGSEGV
- игнорировать
SIGPIPE
Так что это невозможно, если вы не готовы изменить исходный код.
Кроме того, я не смог найти упоминания о сигналах в сообщениях git commit.