Skip to content

Commit

Permalink
Improve REPL SIGINT user experience.
Browse files Browse the repository at this point in the history
* Add a SIGINT dead time after a force throw

    Fixes Jeff's issue in #17706

* Make the eval and print loop sigatomic to avoid sigint being delivered
  outside `try`-`catch` blocks.
  • Loading branch information
yuyichao committed Jul 30, 2016
1 parent ba46baf commit ba15807
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 4 deletions.
6 changes: 6 additions & 0 deletions base/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ end

function eval_user_input(ast::ANY, backend::REPLBackend)
iserr, lasterr = false, ((), nothing)
ccall(:jl_sigatomic_begin, Void, ())
while true
try
ccall(:jl_sigatomic_end, Void, ())
if iserr
put!(backend.response_channel, lasterr)
iserr, lasterr = false, ()
Expand All @@ -74,6 +76,7 @@ function eval_user_input(ast::ANY, backend::REPLBackend)
iserr, lasterr = true, (err, catch_backtrace())
end
end
ccall(:jl_sigatomic_end, Void, ())
end

function start_repl_backend(repl_channel::Channel, response_channel::Channel)
Expand Down Expand Up @@ -136,8 +139,10 @@ function print_response(repl::AbstractREPL, val::ANY, bt, show_value::Bool, have
print_response(outstream(repl), val, bt, show_value, have_color, specialdisplay(repl))
end
function print_response(errio::IO, val::ANY, bt, show_value::Bool, have_color::Bool, specialdisplay=nothing)
ccall(:jl_sigatomic_begin, Void, ())
while true
try
ccall(:jl_sigatomic_end, Void, ())
if bt !== nothing
display_error(errio, val, bt)
println(errio)
Expand Down Expand Up @@ -166,6 +171,7 @@ function print_response(errio::IO, val::ANY, bt, show_value::Bool, have_color::B
bt = catch_backtrace()
end
end
ccall(:jl_sigatomic_end, Void, ())
end

# A reference to a backend
Expand Down
17 changes: 16 additions & 1 deletion src/signal-handling.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ JL_DLLEXPORT void jl_profile_stop_timer(void);
JL_DLLEXPORT int jl_profile_start_timer(void);

static uint64_t jl_last_sigint_trigger = 0;
static uint64_t jl_disable_sigint_time = 0;
static void jl_clear_force_sigint(void)
{
jl_last_sigint_trigger = 0;
Expand All @@ -44,7 +45,21 @@ static int jl_check_force_sigint(void)
if (!isnormal(new_weight))
new_weight = 0;
accum_weight = new_weight;
return new_weight > 1;
if (new_weight > 1) {
jl_disable_sigint_time = cur_time + (uint64_t)0.5e9;
return 1;
}
jl_disable_sigint_time = 0;
return 0;
}

// Force sigint requires pressing `Ctrl-C` repeatedly.
// Ignore sigint for a short time after that to avoid rethrowing sigint too
// quickly again. (Code that has this issue is inherently racy but this is
// a interactive feature anyway.)
static int jl_ignore_sigint(void)
{
return jl_disable_sigint_time && jl_disable_sigint_time > uv_hrtime();
}

static int exit_on_sigint = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ static void *signal_listener(void *arg)
critical = 1;
}
else {
jl_try_deliver_sigint();
if (!jl_ignore_sigint())
jl_try_deliver_sigint();
continue;
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/signals-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ void __cdecl crt_sig_handler(int sig, int num)
signal(SIGINT, (void (__cdecl *)(int))crt_sig_handler);
if (exit_on_sigint)
jl_exit(130); // 128 + SIGINT
jl_try_throw_sigint();
if (!jl_ignore_sigint())
jl_try_throw_sigint();
break;
default: // SIGSEGV, (SSIGTERM, IGILL)
memset(&Context, 0, sizeof(Context));
Expand Down Expand Up @@ -180,7 +181,8 @@ static BOOL WINAPI sigint_handler(DWORD wsig) //This needs winapi types to guara
}
if (exit_on_sigint)
jl_exit(128 + sig); // 128 + SIGINT
jl_try_deliver_sigint();
if (!jl_ignore_sigint())
jl_try_deliver_sigint();
return 1;
}

Expand Down

0 comments on commit ba15807

Please sign in to comment.