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  

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!.


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ł ...


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.