Abfangen von Systemsignalen in Julia

9

In einem Julia-Programm, das unter Linux ausgeführt wird, muss ich eine dedizierte Aktion starten, wenn die Größe eines Konsolenfensters geändert wird. Wie kann ich in Julia das Systemsignal SIGWINCH (Fenstergrößenänderung) abfangen und eine Funktion anhängen, die die erforderliche Aktion ausführt?

In Ada ist es ziemlich einfach, es zu erklären:

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

VORLÄUFIGE LÖSUNG AUF DER GRUNDLAGE DER SCHEMER-IDEE: Ich versuche, eine C-Bibliothek zu verwenden, die die SIGWINCH-Unterbrechungsüberwachung durchführt.

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

Zusammenstellung & Bibliotheksvorbereitung

gcc -c -Wall -fPIC myLibrary.c

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

Programm in Julia, das die C-Bibliothek nutzt:

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 

Das Julia-Programm wird ordnungsgemäß ausgeführt, aber wenn die Größe des Terminalfensters geändert wird, wird ein Segmentierungsfehler (Core Dumped) ausgegeben und das Programm mit dem Code 139 beendet.

Die Frage ist also, woher dieser Segmentierungsfehler kommt. Aus dem Kompilierungsmodell? Julia hat nicht das Recht, die Codeausführung in dem Speicherbereich zu steuern, in dem C die Signalüberwachung verwaltet.

Durch Entfernen der Druckoperation in Sig_handler wird der Segmentierungsfehler unterdrückt:

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
quelle
1
Es sollte ziemlich einfach sein, dies als SignalHandlers.jl-Modul mit ccall ((: signal ...) und @cfunction zu aktualisieren, aber AFAIK wurde dies nicht getan
Bill
Ihr Vorschlag war gut. Vielen Dank.
Emile

Antworten:

4

Da diese Frage bisher noch niemand beantwortet hat, könnte eine mögliche Problemumgehung darin bestehen, die Größe des Terminals in bestimmten Zeitintervallen asynchron zu überwachen.

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

Und jetzt Beispielnutzung:

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

Solange das Terminal aktiv ist, wird jede Änderung seiner Größe gedruckt BOO!.

Przemyslaw Szufel
quelle
Ich kannte diesen guten Weg nicht, um die aktuelle Größe des Konsolenfensters zu erhalten. displayize (stdout) Danke
Emile
0

Ja, es ist in der Tat eine Fallback-Lösung, die man von einer neuen Sprache voller Versprechen kaum erwartet ... aber mangels Drosseln können wir tatsächlich Amseln essen (Lächeln).

Aber wenn Julia nicht geplant hat, die Systemsignale der Unix / Linux-Welt berücksichtigen zu können, ist es möglicherweise möglich, dies mit einer C-Bibliothek wie der zu tun, auf die signal.h zugreift.

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

Wir müssten eine Julia-Funktion definieren, die das tut, was erwartet wird, wenn das Systemsignal empfangen wird. Machen Sie es in C als Sig_handler verwendbar und rufen Sie von Julia das C-Anweisungssignal (SIGWINCH, Sig_handler) auf;

Ich bin nicht genug mit Julia vertraut, um den genauen Code zu schreiben. Aber das ist die Idee ...

Intrigant
quelle
Ich werde versuchen, Ihre Vorschläge umzusetzen.
Emile
@Emile Wenn Sie es schaffen, es zu implementieren (einschließlich des Schreibens von Jullia ccal) und es später zu einem Standard-Julia-Paket machen möchten, kann ich Ihnen beim Packen helfen.
Przemyslaw Szufel
Zur Kenntnis genommen ! Ich muss noch ein bisschen weiter in der Julia-Dokumentation.
Emile
@Przemyslaw Szufel: Wie ist Ihre Analyse des oben gezeigten Segmentierungsfehlers als Ergänzung zu meiner Frage und tritt auf, wenn die C-Funktion zum Abfangen der Unterbrechung verwendet wird?
Emile
Ich habe keinen Julia-C-Integrationscode geschrieben. Ich weiß jedoch, dass es sehr lange Zeit einen Segfault-Fehler gab, wenn eine System-E / A in Julia-Threads verwendet wurde, sodass wahrscheinlich einige Probleme auftreten. Vielleicht versuchen Sie im ersten Schritt zu sehen, was passiert ist, wenn Sie nur drucken ("boo"), ohne nach der Terminalgröße zu fragen.
Przemyslaw Szufel