10

In a Julia program which run under Linux, I need to launch a dedicated action when a console window is resized. So how in Julia, can I intercept the system signal SIGWINCH (window resizing) and attach to it a function which performs the required action ?

In Ada it is rather straightforward to declare it :

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

TENTATIVE SOLUTION BASED ON IDEA OF SCHEMER : I try to use a C Library which conducts the SIGWINCH interruption monitoring.

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

Compilation & Library preparation

gcc -c -Wall -fPIC myLibrary.c

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

Program in Julia which uses the 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 

The Julia program run properly but when the terminal window is resized a Segmentation fault (core dumped) is issued and program is said exited with code: 139.

So the question is where does this segmentation fault come from ? From the compilation model ? Julia has not the right to control code execution in the memory part where C manages the signal monitoring ?

Removing println operation in Sig_handler suppress the segmentation fault :

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
  • 163
  • 6
  • 1
    It should be fairly straightforward to actualize this as a SignalHandlers.jl module using ccall((:signal...) and @cfunction, but AFAIK this has not been done. – Bill Mar 23 '20 at 22:44
  • Your suggestion was a good one. Thank you. – Emile Mar 30 '20 at 10:58

2 Answers2

4

Since no one has answered this question so far, one possible workaround could be asynchronously monitoring the size of the terminal in some time intervals.

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

And now sample usage:

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

As long as the terminal is alive, any change to its size will print BOO!.

Przemyslaw Szufel
  • 40,002
  • 3
  • 32
  • 62
  • I did not know this nice way to get the current console window size. displaysize(stdout) Thank you – Emile Mar 24 '20 at 14:26
1

Yes, it is indeed a fallback solution which is hardly what one expects from a new language full of promises ... but for lack of thrushes we can actually eat blackbirds (smile).

But if Julia hasn't planned to be able to take into account the system signals of the Unix/Linux world, it might be possible to do it using a C library like the one that signal.h accesses.

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

We would have to define a julia function doing what is expected when the system signal is received. Make it usable in C as Sig_handler and call from julia the C statement signal(SIGWINCH, Sig_handler);

I am not enough familiar with julia to write the exact code. But this is the idea...

Schemer
  • 11
  • 2
  • I will try to implement what you propose. – Emile Mar 24 '20 at 14:27
  • @Emile if you manage to implement it (including writing Jullia's `ccal`) and want later make it into a standard Julia package I can help with packaging that. – Przemyslaw Szufel Mar 25 '20 at 12:55
  • Duly noted ! I have to a bit further in the julia documentation. – Emile Mar 25 '20 at 14:41
  • @Przemyslaw Szufel : What is your analysis of the segmentation fault shown above as complement to my question and occuring when the C function is used to catch the interruption ? – Emile Mar 29 '20 at 18:48
  • I have not been writing Julia-C integration code. However, I know that for a very long time there was a segfault error whenever any system IO was used in Julia threads so probably there are some issues there. Maybe in the first step try to see what happend when you just println("boo") without asking for the terminal size. – Przemyslaw Szufel Mar 29 '20 at 22:24
  • You right, if I remove the println operation in the sig_handler function which only has to read the new size of the terminal declared as a global variable, it works fine. – Emile Mar 30 '20 at 07:52