Interception du signal du système dans Julia

9

Dans un programme Julia qui s'exécute sous Linux, je dois lancer une action dédiée lorsqu'une fenêtre de console est redimensionnée. Alors comment, dans Julia, puis-je intercepter le signal système SIGWINCH (redimensionnement de la fenêtre) et y attacher une fonction qui effectue l'action requise?

En Ada, il est assez simple de le déclarer:

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

SOLUTION TENTATIVE BASÉE SUR L'IDÉE DE SCHEMER: J'essaie d'utiliser une bibliothèque C qui effectue la surveillance des interruptions 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);
}

Compilation et préparation de la bibliothèque

gcc -c -Wall -fPIC myLibrary.c

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

Programme en Julia qui utilise la 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 

Le programme Julia fonctionne correctement mais lorsque la fenêtre du terminal est redimensionnée, un défaut de segmentation (core dumped) est émis et le programme est dit quitté avec le code: 139.

La question est donc d'où vient ce défaut de segmentation? Du modèle de compilation? Julia n'a pas le droit de contrôler l'exécution du code dans la partie mémoire où C gère la surveillance du signal?

La suppression de l'opération println dans Sig_handler supprime l'erreur de segmentation:

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
la source
1
Il devrait être assez simple de l'actualiser en tant que module SignalHandlers.jl en utilisant ccall ((: signal ...) et @cfunction, mais AFAIK, cela n'a pas été fait.
Projet de loi du
Votre suggestion était bonne. Je vous remercie.
Emile

Réponses:

4

Étant donné que personne n'a répondu à cette question jusqu'à présent, une solution de contournement possible pourrait être la surveillance asynchrone de la taille du terminal à certains intervalles de temps.

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

Et maintenant, exemple d'utilisation:

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

Tant que le terminal est vivant, toute modification de sa taille s'imprime BOO!.

Przemyslaw Szufel
la source
Je ne connaissais pas cette belle façon d'obtenir la taille actuelle de la fenêtre de la console. affiche (stdout) Merci
Emile
0

Oui, c'est en effet une solution de repli qui n'est guère ce que l'on attend d'une nouvelle langue pleine de promesses ... mais faute de grives on peut effectivement manger des merles (sourire).

Mais si Julia n'a pas prévu de pouvoir prendre en compte les signaux système du monde Unix / Linux, il pourrait être possible de le faire en utilisant une bibliothèque C comme celle à laquelle accède 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;
}

Il faudrait définir une fonction julia faisant ce qui est attendu lors de la réception du signal système. Rendez-le utilisable en C comme Sig_handler et appelez de julia le signal d'instruction C (SIGWINCH, Sig_handler);

Je ne connais pas assez julia pour écrire le code exact. Mais c'est l'idée ...

Intrigant
la source
Je vais essayer de mettre en œuvre ce que vous proposez.
Emile
@Emile si vous parvenez à l'implémenter (y compris l'écriture de Jullia ccal) et que vous souhaitez en faire plus tard un package Julia standard, je peux vous aider à l'empaqueter.
Przemyslaw Szufel
Dûment noté! Je dois aller un peu plus loin dans la documentation de Julia.
Emile
@Przemyslaw Szufel: Quelle est votre analyse du défaut de segmentation montré ci-dessus en complément de ma question et se produisant lorsque la fonction C est utilisée pour détecter l'interruption?
Emile
Je n'ai pas écrit de code d'intégration Julia-C. Cependant, je sais que pendant très longtemps, une erreur de segmentation s'est produite chaque fois qu'une E / S système était utilisée dans les threads Julia, il y a donc probablement des problèmes. Peut-être que dans la première étape, essayez de voir ce qui se passe lorsque vous imprimez ("boo") sans demander la taille du terminal.
Przemyslaw Szufel