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


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  

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"), не спрашивая размер терминала.
Пшемыслав Шуфель
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.