signal handler
We set the signal handler for polymake.jl in initialize_polymake but this breaks Ctrl+C in julia afterwards.
Either we remove this or we need to set and unset this around every computation, and make sure we reset it to he correct one.
julia> sleep(5);
^CERROR: InterruptException:
Stacktrace:
[1] poptaskref(::Base.InvasiveLinkedListSynchronized{Task}) at ./task.jl:564
[2] wait() at ./task.jl:591
[3] wait(::Base.GenericCondition{Base.Threads.SpinLock}) at ./condition.jl:104
[4] stream_wait(::Timer, ::Base.GenericCondition{Base.Threads.SpinLock}) at ./stream.jl:47
[5] wait(::Timer) at ./asyncevent.jl:116
[6] sleep(::Int64) at ./asyncevent.jl:188
[7] top-level scope at REPL[1]:1
julia> using Polymake
polymake version 4.0
Copyright (c) 1997-2020
Ewgenij Gawrilow, Michael Joswig, and the polymake team
Technische Universität Berlin, Germany
https://polymake.org
...
julia> sleep(5);
^C^C^C (nothing happens)
julia>
After removing the set_interrupt_signal from the polymake init Ctrl+C aborts julia and returns to the shell:
julia> using Polymake
polymake version 4.0
...
julia> sleep(5)
^C
lorenz $
It seems perl is also messing with the signal handler.
ok, so that means that polymake always grabs the interrupt and does nothing with it? I thought what we set-up was passing the interrupt from julia to polymake if we're in polymake function;
but I can reproduce this; I guess it's best to revert this change and think about a solution to the following scenario:
julia> s = rand_sphere(15, 1000);
julia> s.FACETS;
^C
Interrupted
julia>
i.e. how to break a computation that has no chance of ever finishing without using ^Z + kill ;)
polymake can set a signal handler but we can remove/disable that (or use a different signal), but also perl does many calls to sigaction.
I dont think polymake is responsible for the 'kills julia' behaviour.
There can be only one signal handler for a given signal, so we are overwriting the one from julia. And the behaviour of the polymake signal handler depends on the currently running code:
- It should abort rather quickly when polymake is running perl code.
- But if polymake is running some C++ code or foreign library code it will not abort until it returns to perl.
The second point is to avoid any inconsistent state, just stopping arbitrary C or C++ code might leave plenty of leaking memory in the best case, invalid pointers in global variables otherwise.
So I don't think you can get a safe way to abort p.FACETS.
Is it possible on the julia side to have custom code triggered when Ctrl+C is pressed, the REPL is probably running in a different thread? Then we could set polymake to a signal other than SIGINT and send that custom signal via pthread_kill if we know the correct thread? (But most signal seem already in use by julia: https://github.com/JuliaLang/julia/blob/master/src/signals-unix.c )
I just meant that the only possibility of stopping the endless computation is to suspend and then kill julia process; What would be ideal is to pass the interrupt to polymake, which passes the interrupt to external code, library, etc. but then it does depend on how (or if) that library handles interrupts (e.g. cleaning-up itself), etc.
anyway, since I don't know enough how julia handles the interrupts to answer the questions, It's safest to revert this thing as it breaks something that used to work without achieving what we want in return;
let's keep this open for the time as a remainder though
julia> using Polymake
...
julia> sleep(10)
^CERROR: InterruptException:
Stacktrace:
[1] wait at ./asyncevent.jl:128 [inlined]
[2] sleep(::Int64) at ./asyncevent.jl:213
[3] top-level scope at REPL[2]:1
julia> c = polytope.cube(14);
julia> c.VERTICES;
^CERROR: InterruptException:
Stacktrace:
[1] internal_give(::Polymake.BigObjectAllocated, ::String) at /home/lorenz/.julia/packages/CxxWrap/ucmly/src/CxxWrap.jl:596
[2] give(::Polymake.BigObjectAllocated, ::String) at /home/lorenz/software/polymake/julia/Polymake-glibcxx.jl/src/perlobj.jl:41
[3] getproperty(::Polymake.BigObjectAllocated, ::Symbol) at /home/lorenz/software/polymake/julia/Polymake-glibcxx.jl/src/perlobj.jl:53
julia> c
Error showing value of type Polymake.BigObjectAllocated:
ERROR: rule 'RAYS, LINEALITY_SPACE : FACETS, LINEAR_SPAN, RAYS_IN_FACETS' attempts to read its output property VERTICES before it is created
Stacktrace:
[1] properties(::Polymake.BigObjectAllocated) at /home/lorenz/.julia/packages/CxxWrap/ucmly/src/CxxWrap.jl:596
[2] show(::IOContext{REPL.Terminals.TTYTerminal}, ::MIME{Symbol("text/plain")}, ::Polymake.BigObjectAllocated) at /home/lorenz/software/polymake/julia/Polymake-glibcxx.jl/src/visual.jl:4
[3] display(::REPL.REPLDisplay, ::MIME{Symbol("text/plain")}, ::Any) at /var/tmp/portage/dev-lang/julia-1.4.0-r1/work/julia-1.4.0/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:137
[4] display(::REPL.REPLDisplay, ::Any) at /var/tmp/portage/dev-lang/julia-1.4.0-r1/work/julia-1.4.0/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:141
[5] display(::Any) at ./multimedia.jl:323
[6] #invokelatest#1 at ./essentials.jl:712 [inlined]
[7] invokelatest at ./essentials.jl:711 [inlined]
[8] print_response(::IO, ::Any, ::Bool, ::Bool, ::Any) at /var/tmp/portage/dev-lang/julia-1.4.0-r1/work/julia-1.4.0/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:161
[9] print_response(::REPL.AbstractREPL, ::Any, ::Bool, ::Bool) at /var/tmp/portage/dev-lang/julia-1.4.0-r1/work/julia-1.4.0/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:146
[10] (::REPL.var"#do_respond#38"{Bool,REPL.var"#48#57"{REPL.LineEditREPL,REPL.REPLHistoryProvider},REPL.LineEditREPL,REPL.LineEdit.Prompt})(::Any, ::Any, ::Any) at /var/tmp/portage/dev-lang/julia-1.4.0-r1/work/julia-1.4.0/usr/share/julia/stdlib/v1.4/REPL/src/REPL.jl:729
julia> exit()
signal (11): Segmentation fault
in expression starting at REPL[6]:1
Segmentation fault
I hope to get this done tonight so we can do a release tomorrow.
since we can't interrupt polymake we should disable_sigint before every function/method/give call:
help?> disable_sigint
search: disable_sigint
disable_sigint(f::Function)
Disable Ctrl-C handler during execution of a function on the current task, for calling external code that may call julia code that is not interrupt safe. Intended to be called using do
block syntax as follows:
disable_sigint() do
# interrupt-unsafe code
...
end
This is not needed on worker threads (Threads.threadid() != 1) since the InterruptException will only be delivered to the master thread. External functions that do not call julia code
or julia runtime automatically disable sigint during their execution.
This won't solve the original issue, but
- we can't fix it in
Polymake.jlalone; - we will avoid the forest of memory corruption in the valley of segfaults
Maybe polymake itself could learn when it is safe to interrupt it, but I understand this is a HUGE endeavour.
since we can't interrupt polymake we should
disable_sigintbefore everyfunction/method/givecall:
This seems very reasonable. In theory we might need to do this for any small cxxwrap based function call?
Is it possible to get some custom handler running in this case so that we can pass a different signal to polymake which can abort at least some (e.g. perl-based) computations?
jl_install_sigint_handler won't help I guess ...
Maybe
polymakeitself could learn when it is safe to interrupt it, but I understand this is a HUGE endeavour.
It does know that it's safe during perl code. There is https://trac.polymake.org/ticket/20 open for quite a while
in #278 we disable sigint while calling into polymake kernel
We had a request to add a (non-exported) flag that disables this feature (disables the disable_sigint) for very adventurous developers (with a big warning).