From 7113c4d38754c7fc92e8cec0ec7934e233f4b042 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Fri, 28 Sep 2018 00:03:05 -0700 Subject: [PATCH 1/2] Add Base.exit_on_sigint to wrap jl_exit_on_sigint --- base/c.jl | 16 ++++++++++++++++ base/client.jl | 2 +- base/docs/basedocs.jl | 12 ++++++++++++ doc/src/base/c.md | 1 + stdlib/REPL/test/repl.jl | 4 ++-- test/stress.jl | 4 ++-- 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/base/c.jl b/base/c.jl index f64bfe548a99a..87eff402ccc61 100644 --- a/base/c.jl +++ b/base/c.jl @@ -463,6 +463,22 @@ function reenable_sigint(f::Function) res end +""" + exit_on_sigint(on::Bool) + +Set `exit_on_sigint` flag of the julia runtime. If `false`, Ctrl-C +(SIGINT) is capturable as [`InterruptException`](@ref) in `try` block. +This is the default behavior in REPL, any code run via `-e` and `-E` +and in Julia script run with `-i` option. + +If `true`, `InterruptException` is not thrown by Ctrl-C. Running code +upon such event requires [`atexit`](@ref). This is the default +behavior in Julia script run without `-i` option. +""" +function exit_on_sigint(on::Bool) + ccall(:jl_exit_on_sigint, Cvoid, (Cint,), on) +end + function ccallable(f::Function, rt::Type, argt::Type, name::Union{AbstractString,Symbol}=string(f)) ccall(:jl_extern_c, Cvoid, (Any, Any, Any, Cstring), f, rt, argt, name) end diff --git a/base/client.jl b/base/client.jl index 5c5894fc7c8a3..bc5442d781eeb 100644 --- a/base/client.jl +++ b/base/client.jl @@ -257,7 +257,7 @@ function exec_options(opts) if arg_is_program # program if !is_interactive - ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 1) + exit_on_sigint(true) end include(Main, PROGRAM_FILE) end diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index ba21ad06331c2..840b3e9c09235 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -1077,6 +1077,18 @@ TypeError InterruptException() The process was stopped by a terminal interrupt (CTRL+C). + +Note that, in Julia script started without `-i` (interactive) option, +`InterruptException` is not thrown by default. Calling +[`Base.exit_on_sigint(false)`](@ref Base.exit_on_sigint) in the script +can recover the behavior of the REPL. Alternatively, a Julia script +can be started with + +```sh +julia -e "include(popfirst!(ARGS))" script.jl +``` + +to let `InterruptException` be thrown by CTRL+C during the execution. """ InterruptException diff --git a/doc/src/base/c.md b/doc/src/base/c.md index df9143b8dc4f6..fdb0ae9d405f1 100644 --- a/doc/src/base/c.md +++ b/doc/src/base/c.md @@ -18,6 +18,7 @@ Base.pointer_from_objref Base.unsafe_pointer_to_objref Base.disable_sigint Base.reenable_sigint +Base.exit_on_sigint Base.systemerror Core.Ptr Core.Ref diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 1e5208f32fc3d..e9991016f2330 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -64,7 +64,7 @@ function fake_repl(@nospecialize(f); options::REPL.Options=REPL.Options(confirm_ end # Writing ^C to the repl will cause sigint, so let's not die on that -ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0) +Base.exit_on_sigint(false) # These are integration tests. If you want to unit test test e.g. completion, or # exact LineEdit behavior, put them in the appropriate test files. # Furthermore since we are emulating an entire terminal, there may be control characters @@ -714,7 +714,7 @@ fake_repl() do stdin_write, stdout_read, repl Base.wait(repltask) end -ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 1) +Base.exit_on_sigint(true) let exename = Base.julia_cmd() # Test REPL in dumb mode diff --git a/test/stress.jl b/test/stress.jl index 6acbd38276715..83e590413b15d 100644 --- a/test/stress.jl +++ b/test/stress.jl @@ -94,7 +94,7 @@ end # !Sys.iswindows # sig 2 is SIGINT per the POSIX.1-1990 standard if !Sys.iswindows() - ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0) + Base.exit_on_sigint(false) @test_throws InterruptException begin ccall(:kill, Cvoid, (Cint, Cint,), getpid(), 2) for i in 1:10 @@ -102,5 +102,5 @@ if !Sys.iswindows() ccall(:jl_gc_safepoint, Cvoid, ()) # wait for SIGINT to arrive end end - ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 1) + Base.exit_on_sigint(true) end From ec600f1d1092821d0fc1f9a513befb4aa64819e9 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Thu, 30 Apr 2020 23:11:47 -0700 Subject: [PATCH 2/2] Add NEWS and compat information --- NEWS.md | 2 ++ base/c.jl | 3 +++ 2 files changed, 5 insertions(+) diff --git a/NEWS.md b/NEWS.md index 45e89d4897e94..c4732bb471102 100644 --- a/NEWS.md +++ b/NEWS.md @@ -118,6 +118,8 @@ New library functions * New function `bitrotate(x, k)` for rotating the bits in a fixed-width integer ([#33937]). * One argument methods `startswith(x)` and `endswith(x)` have been added, returning partially-applied versions of the functions, similar to existing methods like `isequal(x)` ([#33193]). * New function `contains(haystack, needle)` and its one argument partially applied form have been added, it acts like `occursin(needle, haystack)`([#35132]). +* New function `Base.exit_on_sigint` is added to control if `InterruptException` is + thrown by Ctrl-C ([#29411]). New library features -------------------- diff --git a/base/c.jl b/base/c.jl index 78ea685559d0e..42003bba32eb7 100644 --- a/base/c.jl +++ b/base/c.jl @@ -474,6 +474,9 @@ and in Julia script run with `-i` option. If `true`, `InterruptException` is not thrown by Ctrl-C. Running code upon such event requires [`atexit`](@ref). This is the default behavior in Julia script run without `-i` option. + +!!! compat "Julia 1.5" + Function `exit_on_sigint` requires at least Julia 1.5. """ function exit_on_sigint(on::Bool) ccall(:jl_exit_on_sigint, Cvoid, (Cint,), on)