Przechwytywanie sygnału systemu w Julii

9

W programie Julia, który działa pod Linuksem, muszę uruchomić dedykowane działanie, gdy zmieni się rozmiar okna konsoli. Jak więc w Julii mogę przechwycić sygnał systemowy SIGWINCH (zmiana rozmiaru okna) i dołączyć do niego funkcję, która wykonuje wymagane działanie?

W Adzie deklaracja jest dość prosta:

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

ROZWIĄZANIE TENTATYWNE W OPARCIU O POMYSŁ SCHEMERA: Próbuję użyć biblioteki C, która prowadzi monitorowanie przerw 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);
}

Kompilacja i przygotowanie biblioteki

gcc -c -Wall -fPIC myLibrary.c

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

Program w Julii korzystający z biblioteki 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 

Program Julia działa poprawnie, ale po zmianie rozmiaru okna terminala generowany jest błąd segmentacji (zrzut pamięci) i program kończy się kodem: 139.

Pytanie brzmi, skąd bierze się ta usterka segmentacji? Z modelu kompilacji? Julia nie ma prawa kontrolować wykonywania kodu w części pamięci, w której C zarządza monitorowaniem sygnału?

Usunięcie operacji println w module Sig_handler tłumi błąd segmentacji:

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
źródło
1
Uaktualnienie tego jako modułu SignalHandlers.jl powinno być dość proste przy użyciu ccall ((: sygnał ...) i funkcji @, ale AFAIK tego nie zrobiono
Bill
Twoja sugestia była dobra. Dziękuję Ci.
Emile

Odpowiedzi:

4

Ponieważ do tej pory nikt nie odpowiedział na to pytanie, jednym z możliwych obejść może być asynchroniczne monitorowanie wielkości terminala w określonych odstępach czasu.

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

A teraz przykładowe użycie:

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

Tak długo, jak terminal będzie żył, będą drukowane wszelkie zmiany jego rozmiaru BOO!.

Przemysław Szufel
źródło
Nie znałem tego miłego sposobu na uzyskanie bieżącego rozmiaru okna konsoli. displayize (standardowe wyjście) Dziękuję
Emile
0

Tak, to rzeczywiście rozwiązanie awaryjne, które nie jest tym, czego można oczekiwać od nowego języka pełnego obietnic ... ale z powodu braku pleśniawki możemy faktycznie jeść kosy (uśmiech).

Ale jeśli Julia nie planuje brać pod uwagę sygnałów systemowych ze świata Unix / Linux, może to być możliwe przy użyciu biblioteki C, takiej jak ta, do której uzyskuje dostęp.

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

Musielibyśmy zdefiniować funkcję Julii wykonującą to, czego się oczekuje po odebraniu sygnału systemowego. Uczyń go użytecznym w C jako Sig_handler i wywołaj z Julii sygnał instrukcji C (SIGWINCH, Sig_handler);

Nie jestem wystarczająco zaznajomiony z Julią, aby napisać dokładny kod. Ale to jest pomysł ...

Intrygant
źródło
Spróbuję wdrożyć to, co zaproponujesz.
Emile
@Emile, jeśli uda Ci się go wdrożyć (w tym napisać Jullię ccal) i chcesz później przekształcić go w standardowy pakiet Julii, mogę pomóc w jego pakowaniu.
Przemysław Szufel
Zanotowano ! Muszę pójść trochę dalej w dokumentacji Julii.
Emile
@Przemyslaw Szufel: Jaka jest twoja analiza błędu segmentacji pokazanego powyżej jako uzupełnienie mojego pytania i występującego, gdy funkcja C jest używana do wychwytywania przerwy?
Emile
Nie piszę kodu integracji Julii-C. Wiem jednak, że przez bardzo długi czas pojawiał się błąd segfault, ilekroć w systemie IO był używany wątek Julii, więc prawdopodobnie występują pewne problemy. Być może w pierwszym kroku spróbuj zobaczyć, co się stanie, gdy po prostu wydrukujesz („boo”) bez pytania o rozmiar terminala.
Przemysław Szufel