首页 文章

在GNU-Prolog中,我可以'catch'一个linux信号吗?

提问于
浏览
20

有没有办法在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 -1kill -2 等中断它,编译后的程序就会退出 .

我已经尝试用 --no-top-level 编译程序,以防默认顶层以某种方式捕获信号,但这没有任何区别 .

SWI-Prolog似乎有一个合适的内置谓词 on_signal ,它可以达到目的,但我可以 .

2 回答

  • 10

    在查看current gprolog source code后使用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);

    我们可以看到信号的唯一用途是:

    • 在REPL中处理 SIGINT (通过按CTRL C生成)

    • 来处理 SIGSEGV

    • 忽略 SIGPIPE

    所以这是不可能的,除非你愿意修改源代码 .

    另外,我在git commit消息中找不到any mention of signals .

  • 10

    感谢mescalinum谁确认signal handling is not available by default in GNU Prolog .

    但是GNU Prolog对C语言中的用户例程有很好的支持,我已经能够编写少量的C代码来捕获Linux信号并触发(如果需要)一个Prolog异常(注意我的是Ubuntu 14.04 / GNU Prolog 1.3) 0.0所以C类型 init_signal 功能是从 Bool gprolog.h - 在gprolog.h 1.3.1这个改变起到 PlBool - 见1.3.0 VS most recent手册):

    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> 从另一个终端中断

    Bambam@desktop:~/prolog/signal$ ./test
    Prolog signal test program started
    SIGHUP handler registered
    received SIGHUP
    Prolog exception thrown
    Bambam@desktop:~/prolog/signal$
    

    出于我的目的,我可以在C信号处理程序中有用地处理传入的异常,但是将它反映回Prolog'throw'(在这种情况下带有'实例化错误')将代码整齐地保存在Prolog中 .

    我希望能够向执行的GNU Prolog进程发送(和捕获)信号的原因是因为我的系统是一个高性能的并行处理Prolog环境,它可以触发任何长期运行的Prolog进程,以动态地将自己“拆分”为然后在其他机器上执行的多个部件 . 但是你从根本上不能(用我的方法)预测工作的确切分布,并且在适当的时候,其他处理器将被中断(即发送信号)以进一步分解工作量 .

相关问题