Система перехвата сигнала в Юлии

9

В программе Julia, работающей под Linux, мне нужно запустить специальное действие при изменении размера окна консоли. Итак, как в Джулии я могу перехватить системный сигнал SIGWINCH (изменение размера окна) и добавить к нему функцию, которая выполняет требуемое действие?

В Аде объявить это довольно просто:

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

ТЕНТАТИВНОЕ РЕШЕНИЕ НА ОСНОВЕ ИДЕИ ШЕМЕРА: Я пытаюсь использовать библиотеку C, которая проводит мониторинг прерываний 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);
}

Компиляция и подготовка библиотеки

gcc -c -Wall -fPIC myLibrary.c

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

Программа на Юлии, которая использует 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 

Программа Julia работает правильно, но когда размер окна терминала изменяется, выдается ошибка сегментации (сбрасывается ядро) и программа выходит из программы с кодом: 139.

Таким образом, вопрос в том, откуда возникает эта ошибка сегментации? Из модели компиляции? Джулия не имеет права контролировать выполнение кода в той части памяти, где C управляет мониторингом сигналов?

Удаление операции println в Sig_handler подавляет ошибку сегментации:

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
источник
1
Было бы довольно просто реализовать это как модуль SignalHandlers.jl, используя ccall ((: signal ...) и @cfunction, но AFAIK это не было сделано.
Bill
Ваше предложение было хорошим. Спасибо.
Эмиль

Ответы:

4

Поскольку до сих пор никто не ответил на этот вопрос, одним из возможных обходных путей может быть асинхронный мониторинг размера терминала через некоторые промежутки времени.

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

А теперь пример использования:

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

Пока терминал активен, любое изменение его размера будет печататься BOO!.

Пшемыслав Шуфель
источник
Я не знал этот хороший способ получить текущий размер окна консоли. displays (stdout) Спасибо
Эмиль
0

Да, это действительно запасное решение, которого вряд ли можно ожидать от нового языка, полного обещаний ... но из-за отсутствия дроздов мы можем есть черных дроздов (улыбается).

Но если Джулия не планировала принимать во внимание системные сигналы мира Unix / Linux, это можно было бы сделать с помощью библиотеки C, подобной той, к которой обращается 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;
}

Мы должны были бы определить функцию julia, делающую то, что ожидается, когда системный сигнал получен. Сделайте его пригодным для использования в C как Sig_handler и вызовите от julia сигнал оператора C (SIGWINCH, Sig_handler);

Я недостаточно знаком с Юлией, чтобы написать точный код. Но это идея ...

комбинатор
источник
Я постараюсь реализовать то, что вы предлагаете.
Эмиль
@ Эмиль, если вам удастся реализовать его (включая написание Джулии ccal) и захотите позже превратить его в стандартный пакет Джулии, я могу помочь с его упаковкой.
Пшемыслав Шуфель
Верно подмечено ! Я должен немного дальше в документации Джулии.
Эмиль
@Przemyslaw Szufel: Как вы анализируете ошибку сегментации, показанную выше как дополнение к моему вопросу и происходящую, когда функция C используется для обнаружения прерывания?
Эмиль
Я не писал код интеграции Julia-C. Тем не менее, я знаю, что в течение очень долгого времени была ошибка segfault всякий раз, когда какой-либо системный ввод-вывод использовался в потоках Julia, так что, вероятно, там есть некоторые проблемы. Возможно, на первом шаге попробуйте посмотреть, что происходит, когда вы просто печатаете ("boo"), не спрашивая размер терминала.
Пшемыслав Шуфель