JuliaPy / PythonCall.jl

Python and Julia in harmony.
https://juliapy.github.io/PythonCall.jl/stable/
MIT License
721 stars 61 forks source link

Julia crashes on Interrupt when using PythonCall #382

Open schlichtanders opened 8 months ago

schlichtanders commented 8 months ago

Affects: PythonCall

Describe the bug I just turned off threads to make PythonCall work, but now I experience that every time I try interrupting the julia REPL (with PythonCall loaded and used inside a WebServer) it results in a fatal error which crashes the whole Julia REPL (however I would like to stay in the julia REPL)

Here the error message

^Cfatal: error thrown and no exception handler available.
InterruptException()
_jl_mutex_unlock at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/threading.c:805
jl_mutex_unlock at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/julia_locks.h:81 [inlined]
ijl_task_get_next at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/partr.c:394
poptask at ./task.jl:974
wait at ./task.jl:983
task_done_hook at ./task.jl:672
jfptr_task_done_hook_49546.clone_1 at /usr/local/julia/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2758 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2940
jl_apply at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/julia.h:1880 [inlined]
jl_finish_task at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/task.c:320
start_task at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/task.c:1103
fatal: error thrown and no exception handler available.
ErrorException("schedule: Task not runnable")
error at ./error.jl:35
#schedule#649 at ./task.jl:840
schedule at ./task.jl:838 [inlined]
notify at ./condition.jl:154
#notify#622 at ./condition.jl:148 [inlined]
notify at ./condition.jl:148 [inlined]
notify at ./condition.jl:148 [inlined]
task_done_hook at ./task.jl:655
jfptr_task_done_hook_49546.clone_1 at /usr/local/julia/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2758 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2940
jl_apply at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/julia.h:1880 [inlined]
jl_finish_task at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/task.c:320
start_task at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/task.c:1103
┌ Warning: temp cleanup
│   exception =
│    schedule: Task not runnable
│    Stacktrace:
│      [1] error(s::String)
│        @ Base ./error.jl:35
│      [2] enq_work(t::Task)
│        @ Base ./task.jl:769
│      [3] yield
│        @ ./task.jl:882 [inlined]
│      [4] yield
│        @ ./task.jl:880 [inlined]
│      [5] Channel{Tuple{String, Vector{String}, Vector{String}}}(func::Base.Filesystem.var"#28#31"{String}, size::Int64; taskref::Nothing, spawn::Bool)
│        @ Base ./channels.jl:140
│      [6] Channel (repeats 2 times)
│        @ ./channels.jl:132 [inlined]
│      [7] #walkdir#27
│        @ ./file.jl:967 [inlined]
│      [8] walkdir
│        @ ./file.jl:928 [inlined]
│      [9] prepare_for_deletion(path::String)
│        @ Base.Filesystem ./file.jl:507
│     [10] temp_cleanup_purge(; force::Bool)
│        @ Base.Filesystem ./file.jl:542
│     [11] temp_cleanup_purge
│        @ ./file.jl:535 [inlined]
│     [12] (::Base.var"#930#931")()
│        @ Base ./initdefs.jl:354
│     [13] _atexit(exitcode::Int32)
│        @ Base ./initdefs.jl:416
└ @ Base.Filesystem file.jl:547
schedule: Task not runnable
atexit hook threw an error: ErrorException("schedule: Task not runnable")
error at ./error.jl:35
#schedule#649 at ./task.jl:840
schedule at ./task.jl:838 [inlined]
uv_writecb_task at ./stream.jl:1166
jfptr_uv_writecb_task_49483.clone_1 at /usr/local/julia/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2758 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2940
jlcapi_uv_writecb_task_31800.clone_1 at /usr/local/julia/lib/julia/sys.so (unknown line)
uv__write_callbacks at /workspace/srcdir/libuv/src/unix/stream.c:959
uv__stream_io at /workspace/srcdir/libuv/src/unix/stream.c:1294
uv__run_pending at /workspace/srcdir/libuv/src/unix/core.c:804
uv_run at /workspace/srcdir/libuv/src/unix/core.c:392
ijl_task_get_next at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/partr.c:390
poptask at ./task.jl:974
wait at ./task.jl:983
uv_write at ./stream.jl:1048
unsafe_write at ./stream.jl:1120
write at ./strings/io.jl:244 [inlined]
print at ./strings/io.jl:246
jfptr_print_33672.clone_1 at /usr/local/julia/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2758 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2940
showerror at ./errorshow.jl:144
unknown function (ip: 0x7f61c41878c6)
_jl_invoke at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2758 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2940
_atexit at ./initdefs.jl:419
jfptr__atexit_46096.clone_1 at /usr/local/julia/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2758 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2940
jl_apply at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/julia.h:1880 [inlined]
ijl_atexit_hook at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/init.c:280
ijl_exit at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/init.c:207
ijl_no_exc_handler at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/task.c:712
jl_finish_task at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/task.c:323
start_task at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/task.c:1103

I was not able to simplify it to a MWE yet. Maybe the above error is already somehow self-explaining.

Your system Please provide detailed information about your system:

schlichtanders commented 8 months ago

Here a MWE run julia docker with

 docker run -it --rm julia:1.9 bash

and start julia. Then run the following code and while the last sleep is running, hit CTRL-c to interrupt the julia session

import Pkg
Pkg.add(["HTTP", "PythonCall", "Sockets"])
using HTTP
using PythonCall
import Sockets

function default_404(req = nothing)
    HTTP.Response(404, "Not found!")
end

router = HTTP.Router(default_404)

@warn "pid = ..."
os = pyimport("os")
pid = os.getpid()
@warn "pid = $pid"

function get_pid(request::HTTP.Request)
    @warn "pid = ..."
    os = pyimport("os")
    pid = os.getpid()
    @warn "pid = $pid"
    return HTTP.Response(200, string(pid))
end
HTTP.register!(router, "GET", "/pid", get_pid)

port = UInt16(32132)
serversocket = Sockets.listen(port)
server = HTTP.listen!(port; stream=true, server=serversocket, verbose=-1) do http::HTTP.Stream
    request::HTTP.Request = http.message
    request.body = read(http)
    response_body = router(request)
    @show response_body
    request.response::HTTP.Response = response_body
    request.response.request = request

    try
        HTTP.setheader(http, "Content-Length" => string(length(request.response.body)))
        # https://github.com/fonsp/Pluto.jl/pull/722
        HTTP.setheader(http, "Referrer-Policy" => "same-origin")
        # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#:~:text=is%202%20minutes.-,14.38%20Server
        HTTP.startwrite(http)
        write(http, request.response.body)
    catch e
        if isa(e, Base.IOError) || isa(e, ArgumentError)
            # @warn "Attempted to write to a closed stream at $(request.target)"
            @debug "that is fine error" exception=(e, catch_backtrace())
        else
            rethrow(e)
        end
    end
end

sleep(2)

HTTP.get("http://localhost:$port/pid")

sleep(100)

It gives the following error

julia> sleep(10)
^C^C^CSYSTEM ERROR: Failed to report error to REPL frontend^Cfatal: error thrown and no exception handler available.
InterruptException()
_jl_mutex_unlock at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/threading.c:805
jl_mutex_unlock at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/julia_locks.h:81 [inlined]
jl_lookup_generic_ at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2912 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2936
scrub_repl_backtrace at ./client.jl:102
_start at ./client.jl:524
jfptr__start_40034.clone_1 at /usr/local/julia/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2758 [inlined]
ijl_apply_generic at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/gf.c:2940
jl_apply at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/julia.h:1880 [inlined]
true_main at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/jlapi.c:573
jl_repl_entrypoint at /cache/build/default-amdci5-5/julialang/julia-release-1-dot-9/src/jlapi.c:717
main at julia (unknown line)
unknown function (ip: 0x7fc40aa221c9)
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
unknown function (ip: 0x4010b8)
root@b66abeaaf63d:/# 
exit