Подтвердить что ты не робот

В GNU-Prolog я могу "поймать" сигнал linux?

Есть ли способ "захватить" (например, "catch" ) сигнал операционной системы в 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, если это возможно.

4b9b3361

Ответ 1

Благодаря mescalinum, который подтвердил обработку сигнала по умолчанию в 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 vs самые последние руководства):

C-код "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 */
}

Использование теста в Prolog "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>

[email protected]:~/prolog/signal$ ./test
Prolog signal test program started
SIGHUP handler registered
received SIGHUP
Prolog exception thrown
[email protected]:~/prolog/signal$

В моих целях я могу с пользой обработать входящее исключение, пока я нахожусь в обработчике сигнала C, но отражая его обратно на "проброс" Prolog (в данном случае с "ошибкой создания экземпляра" ) сохраняет код аккуратно внутри Пролог.

Причина, по которой я хочу отправить (и поймать) сигнал к процессу выполнения GNU Prolog, заключается в том, что моя система представляет собой высокопроизводительную параллельную обработку Prolog-среды, которая может инициировать любой продолжительный процесс Prolog для динамического разделения 'на несколько частей, которые затем выполняются на других машинах. Но вы принципиально не можете (с моим методом) предсказать точное распределение работы, и со временем другие процессоры будут прерваны (т.е. Отправлены сигнал) для дальнейшего разделения рабочей нагрузки.

Ответ 2

Посмотрев текущий исходный код 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.