julia icon indicating copy to clipboard operation
julia copied to clipboard

Repeating Ctrl-C required on Julia 1.8

Open fonsp opened this issue 3 years ago • 6 comments

Since Julia 1.8, a single Ctrl-C does not work, I always need to repeat Ctrl-C multiple times to get the forced SIGINT (with WARNING: Force throwing a SIGINT):

https://user-images.githubusercontent.com/6933510/188428251-dec8a3da-7410-4ebf-b001-8de77457e14b.mov

I found this to be the case for anything that I interrupt, not just sleep. This means that, to exit Pluto, Jupyter, a web server or any other long running process, users will now need to hold down Ctrl-C, printing multiple WARNINGs, which makes Julia look unstable.

Julia Version 1.8.0
Commit 5544a0fab76 (2022-08-17 13:38 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin21.4.0)
  CPU: 8 × Apple M1
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, westmere)
  Threads: 1 on 8 virtual cores
Julia Version 1.7.0
Commit 3bf9d17731 (2021-11-30 12:12 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin19.5.0)
  CPU: Apple M1
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, westmere)

Same problem with the MacOS ARM build.

fonsp avatar Sep 05 '22 10:09 fonsp

I can confirm I have the same issue on Windows 11 on an Intel processor and Windows Terminal 1.15.2203.0

Windows 11 Pro Insider Preview Build 25193.rs_prelease.220829-1428 (no legacy cmd, unfortunately!)

image image

julia> versioninfo()
Julia Version 1.8.0
Commit 5544a0fab7 (2022-08-17 13:38 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 8 × 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, tigerlake)
  Threads: 1 on 8 virtual cores

pankgeorg avatar Sep 05 '22 12:09 pankgeorg

Debian 11 (bullseye), amd64, JupyterLab Terminal:

julia> versioninfo()
Julia Version 1.8.0
Commit 5544a0fab76 (2022-08-17 13:38 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 40 × Intel(R) Xeon(R) Silver 4210R CPU @ 2.40GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, cascadelake)
  Threads: 1 on 40 virtual cores
Environment:
  JULIA_VERSION = 1.8.0
  JULIA_PATH = /opt/julia

julia> sleep(123)
^C^C^C^C^C^C^C^C^CWARNING: Force throwing a SIGINT
ERROR: InterruptException:
Stacktrace:
 [1] poptask(W::Base.InvasiveLinkedListSynchronized{Task})
   @ Base ./task.jl:921
 [2] wait()
   @ Base ./task.jl:930
 [3] wait(c::Base.GenericCondition{Base.Threads.SpinLock})
   @ Base ./condition.jl:124
 [4] _trywait(t::Timer)
   @ Base ./asyncevent.jl:138
 [5] wait
   @ ./asyncevent.jl:155 [inlined]
 [6] sleep(sec::Int64)
   @ Base ./asyncevent.jl:240
 [7] top-level scope
   @ REPL[2]:1

julia> 

Debian 11 (bullseye), arm64, JupyterLab Terminal:

julia> versioninfo()
Julia Version 1.8.0
Commit 5544a0fab76 (2022-08-17 13:38 UTC)
Platform Info:
  OS: Linux (aarch64-linux-gnu)
  CPU: 8 × unknown
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, generic)
  Threads: 1 on 8 virtual cores
Environment:
  JULIA_VERSION = 1.8.0
  JULIA_PATH = /opt/julia

julia> sleep(123)
^C^C^C^C^C^C^C^C^CWARNING: Force throwing a SIGINT
ERROR: InterruptException:
Stacktrace:
 [1] poptask(W::Base.InvasiveLinkedListSynchronized{Task})
   @ Base ./task.jl:921
 [2] wait()
   @ Base ./task.jl:930
 [3] wait(c::Base.GenericCondition{Base.Threads.SpinLock})
   @ Base ./condition.jl:124
 [4] _trywait(t::Timer)
   @ Base ./asyncevent.jl:138
 [5] wait
   @ ./asyncevent.jl:155 [inlined]
 [6] sleep(sec::Int64)
   @ Base ./asyncevent.jl:240
 [7] top-level scope
   @ REPL[2]:1

julia> 

ℹ️ May be reproduced at https://demo.jupyter.b-data.ch or with docker run --rm -it -p 8888:8888 registry.gitlab.b-data.ch/jupyterlab/julia/pubtools

benz0li avatar Sep 05 '22 15:09 benz0li

A bisect shows that the first bad commit is https://github.com/JuliaLang/julia/commit/0eaf35a1990bd572a3bf701aa3e8623224b005c5 . @vtjnash

gbaraldi avatar Sep 05 '22 20:09 gbaraldi

It looks like it is still possible to interrupt Pkg precompilation with a single Ctrl+C (video), strange...

fonsp avatar Sep 20 '22 14:09 fonsp

Narrowing down on the interrupt in Pkg precompilation, I found that Ctrl+C still works reliably in this snippet:

while true
	sleep(.1)
end
Details
julia> sleep(100)
^C^C^C^C^C^C^CWARNING: Force throwing a SIGINT
ERROR: InterruptException:

julia> while true
       sleep(100)
       end
^C^C^C^C^C^C^C^CWARNING: Force throwing a SIGINT
ERROR: InterruptException:

julia> while true
       sleep(.1)
       end
^CERROR: InterruptException:
Stacktrace:
 [1] poptask(W::Base.InvasiveLinkedListSynchronized{Task})
   @ Base ./task.jl:921
 [2] wait()
   @ Base ./task.jl:930
 [3] wait(c::Base.GenericCondition{Base.Threads.SpinLock})
   @ Base ./condition.jl:124
 [4] _trywait(t::Timer)
   @ Base ./asyncevent.jl:138
 [5] wait
   @ ./asyncevent.jl:155 [inlined]
 [6] sleep(sec::Float64)
   @ Base ./asyncevent.jl:240
 [7] top-level scope
   @ ./REPL[14]:2

julia> 

This means that Packages that use the "Press Ctrl+C to stop" UI, like an HTTP.jl server, can use this as a workaround.

Example with HTTP.jl:

Instead of:

server = HTTP.serve!(...)

@info "Server running, press Ctrl+C to interrupt..."
wait(server)

You can use:

server = HTTP.serve!(...)

@info "Server running, press Ctrl+C to interrupt..."
try
	while Base.isopen(server)
		sleep(.1)
	end
catch e
	@info "Closing server..."
	close(server)
	wait(server)
end

fonsp avatar Sep 20 '22 15:09 fonsp

The more correct way to read ^C in a UI is exemplified here in runtests.jl: https://github.com/JuliaLang/julia/blob/276af848511510861f8d0e6c1e69e15e4c646e3e/test/runtests.jl#L221-L232

vtjnash avatar Sep 20 '22 16:09 vtjnash

I don't think it's reasonable to expect HTTP.jl internals to be messing with REPL/Terminals/raw character input. I also don't really understand what changed though and why doing Ctrl + C doesn't throw an InteruptException like it used to? Maybe we just need to provide an interuptible_wait() function in Base that people can call if they want a way to reliably allow and catch an InteruptException?

quinnj avatar Oct 08 '22 00:10 quinnj

@vtnash Besides documenting this use case as a solution to CTRL+C, could HTTP.jl have a function that implements the solution so that applications could use a standard tested piece of code that can be improved over time?

clarkevans avatar Nov 04 '22 14:11 clarkevans

does a test framework exist for testing keystroke interrupts?

mind6 avatar Nov 05 '22 07:11 mind6

yes same issue MacOS and Windows

AbhimanyuAryan avatar Nov 13 '22 13:11 AbhimanyuAryan

I don't understand why this is not patched in 1.8.x but put back for 1.9 which is probably months from a release

toollu avatar Nov 15 '22 09:11 toollu

Julia 1.9 seems actually close, but I believe there's no solution [PR] yet (though a workaround in Pluto), so I'm afraid it will not make it into 1.9, maybe 1.10, which IS months away. Though if solved likely could be backported to 1.9. I'm guessing the solution isn't too easy (and the behavior that worked, was never promised, so some tradeoff with keeping it, not simply a bug).

It's certainly annoying and what I do instead (kills the process on Linux, so not the best workaround for REPL work): CTRL-Z kill %1

PallHaraldsson avatar Nov 15 '22 11:11 PallHaraldsson