Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make InterruptException capturable in a program #29383

Closed
wants to merge 1 commit into from

Conversation

tkf
Copy link
Member

@tkf tkf commented Sep 27, 2018

In julia 1.0 (probably since 0.3?), Julia program launched outside REPL (and -e and -E) cannot catch InterruptException:

$ cat catch-sleep.jl
try
    println("sleeping...")
    sleep(10)
catch err
    @show err
finally
    println("woke up")
end

$ julia --startup-file=no catch-sleep.jl
sleeping...
^C
signal (2): Interrupt

This PR makes it work:

$ julia --startup-file=no catch-sleep.jl
sleeping...
^Cerr = InterruptException()
woke up

It seems ccall(:jl_exit_on_sigint, Void, (Cint,), 1) is added in #6754 but I don't see the discussion why it was required. I also checked the PRs touching this code but couldn't find any relevant discussion (#25162, #23775, #12679, #11347, #9482).

I think it makes sense for various ways of running Julia program

$ julia script.jl
$ julia -e 'include("script.jl")'
$ julia
julia> include("script.jl")

behave consistently. Are there any reasons why exit_on_sigint is set to 1 only in the case of julia script.jl?

Even if this change is reasonable, since this breaks the API, I suppose this has to be blocked until 2.0? Still, adding CLI option --handle-interrupt or a documented Julia function wrapping jl_exit_on_sigint would be nice.

closes #25308

@JeffBezanson
Copy link
Member

I think the idea of this was that interrupting code is mostly useful in interactive mode, while in a "program" you expect it to just stop (like it does for C programs).

@tkf
Copy link
Member Author

tkf commented Sep 27, 2018

The usecase I have in mind is some kind of long-running computation with some buffer which has to be flushed before exit:

handle = prepare_computation()
try
    while !finished(handle)
        dump_computation("output/file", handle)
        do_some_computation_for_a_while!(handle)
    end
finally
    dump_computation("output/file", handle)
end

(which can be nicely converted into a do block with some wrapper).

In HPC clusters, you often have an option to send a signal before the computation limit time. This PR is useful for such case since you can (relatively) safely shutdown the computation without loosing intermediate results. Of course, you can do it with atexit but then it makes it hard to write correct code. For example, imagine that you need to do two of the above computations in the same Julia script. You may not want to trigger the tear-down code for the first computation while sigint is received during the second computation. It's doable, but isn't try-catch/finally much nicer to write?

Also, since Python can catch KeyboardInterrupt in script, being able to catch InterruptException was my first expectation.

@JeffBezanson
Copy link
Member

I think your best bet for now is to call ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0). I agree we should add a documented wrapper for this; that would be a new feature and so can be added in 1.x.

@tkf
Copy link
Member Author

tkf commented Sep 27, 2018

Yes, it makes sense that you can't change it in 1.x. But can it get a 2.0 milestone? It looks like I'm not the only one that finds this behavior strange:

#25308
#19222
https://stackoverflow.com/questions/40937921/julia-0-4-7-how-to-catch-sigterm
https://stackoverflow.com/questions/20831290/julia-handle-keyboard-interrupt/29270413

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Different SIGINT handling in REPL and command line is undocumented
3 participants