Julia中的系统信号拦截


9

在Linux下运行的Julia程序中,需要在调整控制台窗口大小时启动专用操作。那么在Julia中,我怎样才能截获系统信号SIGWINCH(调整窗口大小)并附加执行所需动作的功能呢?

在Ada中,声明它非常简单:

 protected Signalhandler is
      procedure Handlewindowresizing;
      pragma Attach_Handler (Handlewindowresizing, SIGWINCH);
 end Signalhandler;

基于方案思想的解决方案:我尝试使用C库进行SIGWINCH中断监视。

myLibrary.h

void Winresize (void Sig_Handler());

myLibrary.c

#include "myLibrary.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void Winresize(void sig_handler (void)) { 
     signal(SIGWINCH, sig_handler);
}

编译与图书馆准备

gcc -c -Wall -fPIC myLibrary.c

gcc -shared -fPIC -o myLibrary.so myLibrary.o

Julia中使用C库的程序:

function getc1()    
ret = ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), stdin.handle, true)    
ret == 0 || error("unable to switch to raw mode")    
c = read(stdin, UInt8)    
ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), stdin.handle, false)    
c    
end

function traitement() println(displaysize(stdout)); end    
Mon_traitement_c = @cfunction(traitement, Cvoid, ())    
ccall((:Winresize, "/home/Emile/programmation/Julia/myLibrary.so"), Cvoid, (Ptr{Cvoid},), Mon_traitement_c)

while true    
println(getc1())    
end 

Julia程序正常运行,但是在调整终端窗口的大小时,会发出分段错误(内核已转储),并说程序已退出,代码为139。

那么问题是这种分割错误来自何处?从编译模型?茱莉亚(Julia)无权在C负责信号监控的存储部分中控制代码执行?

在Sig_handler中删除println操作可抑制分段错误:

curr_size = displaysize(stdout)
new_size = curr_size
function traitement()  global new_size ; new_size = displaysize(stdout); return end

Mon_traitement_c = @cfunction(traitement, Cvoid, ())

ccall((:Winresize, "/home/Emile/programmation/Julia/myLibrary.so"), Cvoid, (Ptr{Cvoid},), Mon_traitement_c)

while true 
    global curr_size, new_size
    if new_size != curr_size
       curr_size = new_size
       println(curr_size)
    end
    sleep(0.1)  
end  

1
使用ccall((:signal ...)和@cfunction将其实现为SignalHandlers.jl模块应该相当简单,但是AFAIK尚未完成
Bill

您的建议是一个好建议。谢谢。
埃米尔(Emile)

Answers:


4

由于到目前为止还没有人回答这个问题,因此一种可能的解决方法是在某些时间间隔中异步监视终端的大小。

function monitor_term(func)
    @async begin 
        curr_size = displaysize(stdout)
        while (true)
            sleep(0.1)
            new_size = displaysize(stdout)
            if new_size != curr_size
                curr_size = new_size
                func()
            end
        end
    end
end

现在示例用法:

julia> monitor_term(() -> print("BOO!"))
Task (runnable) @0x0000000013071710

只要终端处于活动状态,任何大小更改都会打印出来BOO!


我不知道这种获取当前控制台窗口大小的好方法。displaysize(stdout)谢谢
Emile

0

是的,这确实是一个后备解决方案,这几乎不是人们对一种充满希望的新语言的期望...但是由于缺少画眉,我们实际上可以吃黑鸟(微笑)。

但是,如果Julia尚未计划考虑Unix / Linux世界的系统信号,则可能可以使用signal.h访问的C库来实现。

 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>

 void sig_handler(int signum)
 {
    printf("Received signal %d\n", signum);
 }

int main()
{
   signal(SIGINT, sig_handler);
   sleep(10); // This is your chance to press CTRL-C
   return 0;
}

我们将必须定义一个julia函数,以执行接收系统信号时所期望的功能。使它可以在C中用作Sig_handler并从julia调用C语句信号(SIGWINCH,Sig_handler);

我对julia不太熟悉,无法编写确切的代码。但这就是主意...


我将尝试执行您的建议。
埃米尔(Emile)

@Emile,如果您设法实现它(包括编写Jullia的代码ccal),并希望以后将其放入标准的Julia包中,我可以帮助打包。
Przemyslaw Szufel

适当注意!我必须在julia文档中进一步介绍。
埃米尔(Emile)

@Przemyslaw Szufel:您对上面显示的分段错误的分析是对我的问题的补充,当使用C函数捕获中断时发生的分析是什么?
埃米尔

我尚未编写Julia-C集成代码。但是,我知道很长时间以来,每当在Julia线程中使用任何系统IO时,都会出现段错误,因此可能存在一些问题。也许在第一步中,尝试查看只需要println(“ boo”)而不问终端大小的情况。
Przemyslaw Szufel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.