Sistema de interceptación de señales en Julia

9

En un programa de Julia que se ejecuta en Linux, necesito iniciar una acción dedicada cuando se cambia el tamaño de una ventana de consola. Entonces, ¿cómo en Julia, puedo interceptar la señal del sistema SIGWINCH (cambio de tamaño de ventana) y asignarle una función que realice la acción requerida?

En Ada es bastante sencillo declararlo:

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

SOLUCIÓN TENTATIVA BASADA EN LA IDEA DEL ESQUEMERO: Intento usar una Biblioteca C que realiza el monitoreo de interrupción 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);
}

Recopilación y preparación de la biblioteca.

gcc -c -Wall -fPIC myLibrary.c

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

Programa en Julia que usa la Biblioteca 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 

El programa Julia se ejecuta correctamente, pero cuando se cambia el tamaño de la ventana del terminal, se emite un fallo de segmentación (núcleo volcado) y se dice que el programa salió con el código: 139.

Entonces, la pregunta es ¿de dónde viene esta falla de segmentación? ¿Del modelo de compilación? ¿Julia no tiene derecho a controlar la ejecución del código en la parte de memoria donde C gestiona la supervisión de la señal?

Eliminar la operación println en Sig_handler suprime el error de segmentación:

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
fuente
1
Debería ser bastante sencillo actualizar esto como un módulo SignalHandlers.jl usando ccall ((: signal ...) y @cfunction, pero AFAIK esto no se ha hecho.
Bill
Tu sugerencia fue buena. Gracias.
Emile

Respuestas:

4

Como nadie ha respondido esta pregunta hasta ahora, una posible solución podría ser monitorear asincrónicamente el tamaño del terminal en algunos intervalos de tiempo.

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

Y ahora muestra el uso:

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

Mientras el terminal esté vivo, se imprimirá cualquier cambio en su tamaño BOO!.

Przemyslaw Szufel
fuente
No conocía esta buena forma de obtener el tamaño actual de la ventana de la consola. displaysize (stdout) Gracias
Emile
0

Sí, de hecho es una solución alternativa que difícilmente es lo que uno espera de un nuevo lenguaje lleno de promesas ... pero por falta de zorzales podemos comer mirlos (sonrisa).

Pero si Julia no ha planeado tener en cuenta las señales del sistema del mundo Unix / Linux, podría ser posible hacerlo usando una biblioteca C como la que accede a signal.h.

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

Tendríamos que definir una función julia haciendo lo que se espera cuando se recibe la señal del sistema. Hazlo utilizable en C como Sig_handler y llama desde julia la señal de la declaración C (SIGWINCH, Sig_handler);

No estoy lo suficientemente familiarizado con Julia para escribir el código exacto. Pero esta es la idea ...

Intrigante
fuente
Intentaré implementar lo que propones.
Emile
@Emile si logra implementarlo (incluida la escritura de Jullia ccal) y luego quiere convertirlo en un paquete estándar de Julia, puedo ayudarlo a empaquetarlo.
Przemyslaw Szufel
Debidamente notado! Tengo un poco más en la documentación de julia.
Emile
@Przemyslaw Szufel: ¿Cuál es su análisis de la falla de segmentación que se muestra arriba como complemento de mi pregunta y que ocurre cuando la función C se utiliza para detectar la interrupción?
Emile
No he estado escribiendo el código de integración de Julia-C. Sin embargo, sé que durante mucho tiempo hubo un error de segfault cada vez que se usó un sistema IO en los hilos de Julia, por lo que probablemente haya algunos problemas allí. Tal vez en el primer paso intente ver qué sucedió cuando simplemente imprimió ("boo") sin preguntar por el tamaño del terminal.
Przemyslaw Szufel