Intercepção de sinal do sistema em Julia

9

Em um programa Julia executado no Linux, preciso iniciar uma ação dedicada quando uma janela do console é redimensionada. Então, como em Julia, posso interceptar o sinal do sistema SIGWINCH (redimensionamento de janela) e anexar a ele uma função que executa a ação necessária?

Em Ada, é bastante simples declará-lo:

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

SOLUÇÃO TENTATIVA BASEADA NA IDÉIA DO ESQUEMA: Tento usar uma biblioteca C que conduz o monitoramento de interrupção do 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);
}

Compilação e preparação da biblioteca

gcc -c -Wall -fPIC myLibrary.c

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

Programa em Julia que usa a C-Library:

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 

O programa Julia é executado corretamente, mas quando a janela do terminal é redimensionada, uma falha de segmentação (núcleo despejado) é emitida e o programa é encerrado com o código: 139.

Portanto, a questão é de onde vem essa falha de segmentação? Do modelo de compilação? Julia não tem o direito de controlar a execução do código na parte da memória em que C gerencia o monitoramento do sinal?

A remoção da operação println no Sig_handler suprime a falha de segmentação:

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  
Emile
fonte
11
Deve ser bastante simples atualizar isso como um módulo SignalHandlers.jl usando ccall ((: signal ...) e @cfunction, mas o AFAIK não foi feito.
Bill
Sua sugestão foi boa. Obrigado.
Emile

Respostas:

4

Como ninguém respondeu a essa pergunta até agora, uma solução possível poderia ser o monitoramento assíncrono do tamanho do terminal em alguns intervalos de tempo.

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

E agora experimente o uso:

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

Enquanto o terminal estiver ativo, qualquer alteração em seu tamanho será impressa BOO!.

Przemyslaw Szufel
fonte
Eu não conhecia essa maneira agradável de obter o tamanho atual da janela do console. displaysize (stdout) Obrigado
Emile
0

Sim, é de fato uma solução alternativa que dificilmente é o que se espera de um novo idioma cheio de promessas ... mas, por falta de sapinhos, podemos realmente comer melros (sorriso).

Mas se Julia não planejou ser capaz de levar em conta os sinais do sistema do mundo Unix / Linux, talvez seja possível fazê-lo usando uma biblioteca C como a que o access.h acessa.

 #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;
}

Teríamos que definir uma função julia fazendo o que é esperado quando o sinal do sistema é recebido. Torne-o utilizável em C como Sig_handler e chame de julia o sinal de instrução C (SIGWINCH, Sig_handler);

Não estou familiarizado o suficiente com julia para escrever o código exato. Mas essa é a ideia ...

Schemer
fonte
Vou tentar implementar o que você propõe.
Emile
@Emile se você conseguir implementá-lo (incluindo escrever Jullia's ccal) e depois quiser transformá-lo em um pacote Julia padrão, eu posso ajudar com o empacotamento.
Przemyslaw Szufel 25/03
Devidamente anotado ! Eu tenho um pouco mais na documentação julia.
Emile
@Przemyslaw Szufel: Qual é a sua análise da falha de segmentação mostrada acima como complemento da minha pergunta e ocorrendo quando a função C é usada para capturar a interrupção?
Emile
Eu não escrevi o código de integração Julia-C. No entanto, eu sei que por um longo tempo, houve um erro de segfault sempre que qualquer E / S do sistema era usada nos encadeamentos Julia, portanto, provavelmente existem alguns problemas. Talvez no primeiro passo tente ver o que aconteceu quando você apenas imprime ("vaia") sem perguntar o tamanho do terminal.
Przemyslaw Szufel 29/03