Intercettazione del segnale di sistema in Julia


9

In un programma Julia eseguito su Linux, devo avviare un'azione dedicata quando viene ridimensionata una finestra della console. Quindi, come in Julia, posso intercettare il segnale di sistema SIGWINCH (ridimensionamento della finestra) e collegare ad esso una funzione che esegue l'azione richiesta?

In Ada è piuttosto semplice dichiararlo:

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

SOLUZIONE TENTATIVA BASATA SULL'IDEA DI SCHEMER: cerco di utilizzare una libreria C che conduce il monitoraggio dell'interruzione 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);
}

Compilazione e preparazione della biblioteca

gcc -c -Wall -fPIC myLibrary.c

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

Programma in Julia che utilizza 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 

Il programma Julia funziona correttamente ma quando la finestra del terminale viene ridimensionata viene emesso un errore di segmentazione (core scaricato) e il programma viene detto uscito con il codice: 139.

Quindi la domanda è: da dove viene questo errore di segmentazione? Dal modello di compilazione? Julia non ha il diritto di controllare l'esecuzione del codice nella parte di memoria in cui C gestisce il monitoraggio del segnale?

La rimozione dell'operazione println in Sig_handler elimina l'errore di segmentazione:

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
Dovrebbe essere abbastanza semplice attualizzarlo come modulo SignalHandlers.jl usando ccall ((: signal ...) e @cfunction, ma AFAIK non è stato fatto.
Bill

Il tuo suggerimento è stato buono. Grazie.
Emile

Risposte:


4

Dato che finora nessuno ha risposto a questa domanda, una possibile soluzione alternativa potrebbe essere il monitoraggio asincrono delle dimensioni del terminale in alcuni intervalli di tempo.

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

E ora un esempio di utilizzo:

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

Fintanto che il terminale è attivo, qualsiasi modifica alle sue dimensioni verrà stampata BOO!.


Non conoscevo questo bel modo per ottenere l'attuale dimensione della finestra della console. Displaysize (stdout) Grazie
Emile,

0

Sì, è davvero una soluzione di fallback che non è certo quello che ci si aspetta da una nuova lingua piena di promesse ... ma per mancanza di mughetti possiamo effettivamente mangiare merli (sorriso).

Ma se Julia non ha pianificato di essere in grado di tenere conto dei segnali di sistema del mondo Unix / Linux, potrebbe essere possibile farlo usando una libreria C come quella a cui Signal.h accede.

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

Dovremmo definire una funzione julia facendo ciò che è previsto quando viene ricevuto il segnale di sistema. Rendilo utilizzabile in C come Sig_handler e chiama da julia il segnale dell'istruzione C (SIGWINCH, Sig_handler);

Non ho abbastanza familiarità con Julia per scrivere il codice esatto. Ma questa è l'idea ...


Proverò ad attuare ciò che proponi.
Emile

@Emile se riesci a implementarlo (inclusa la scrittura di Jullia ccal) e vuoi trasformarlo in un pacchetto Julia standard, posso aiutarti a imballarlo.
Przemyslaw Szufel,

Debitamente annotato ! Devo approfondire un po 'la documentazione di Julia.
Emile,

@Przemyslaw Szufel: Qual è la tua analisi del guasto di segmentazione mostrato sopra come complemento alla mia domanda e che si verifica quando la funzione C viene utilizzata per rilevare l'interruzione?
Emile

Non ho scritto il codice di integrazione Julia-C. Tuttavia, so che per molto tempo si è verificato un errore segfault ogni volta che è stato utilizzato qualsiasi IO di sistema nei thread Julia, quindi probabilmente ci sono alcuni problemi lì. Forse nel primo passaggio prova a vedere cosa è successo quando hai appena stampato ("boo") senza chiedere le dimensioni del terminale.
Przemyslaw Szufel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.