-
Notifications
You must be signed in to change notification settings - Fork 190
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
Re-enable SIGINT handler in pyjlwrap_call #574
base: master
Are you sure you want to change the base?
Conversation
So I had to wrap some more BTW, is it safe to call |
Hmm.... I guess the julia> py"""
from abc import ABC
jl_println = $println
class Any(ABC):
@classmethod
def __subclasshook__(cls, subclass):
jl_println("It's like Julia's Any")
return True
"""
julia> pyisinstance(py"1"o, py"Any")
ERROR: sigatomic_end called in non-sigatomic region It's cumbersome to wrap almost everything with |
This reverts commit bd0fcd8.
I just go ahead and add It breaks indent everywhere so let me know if it's a way to go and you want the idents to be fixed in this PR. (I really wnat |
0c41abd
to
0b810b5
Compare
@@ -110,7 +124,7 @@ function pydecref(o::PyObject) | |||
end | |||
|
|||
function pyincref_(o::Union{PyPtr,PyObject}) | |||
ccall((@pysym :Py_IncRef), Cvoid, (PyPtr,), o) | |||
@pyccall(:Py_IncRef, Cvoid, (PyPtr,), o) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess Py_DecRef
can call __del__
so it should probably be protected but I wonder if Py_IncRef
can ever call any Python functions.
https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_dealloc
Hmm... With this change, (Using: JuliaPy/pyjulia@2dc8148 and 0b810b5) |
Actually, |
Calling $ python -c 'from julia import Main; Main.println("Sleeping..."); Main.sleep(10)'
Sleeping...
^CTraceback (most recent call last):
File "<string>", line 1, in <module>
KeyboardInterrupt: Julia exception: InterruptException() |
# context. | ||
macro ccall(args...) | ||
quote | ||
disable_sigint() do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds a higher-order function call to every ccall
; have you checked whether it makes a measurable difference in performance? (Hopefully it all gets inlined, but…)
I really wish this would get fixed in Julia itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, JuliaLang/julia#2622 is closed, does that mean we don't need this anymore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, now I vaguely remember JuliaLang/julia#16174 — we still need this for any ccall
in that might call back to Julia code in which we want to catch interrupt exceptions, I think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment should clarify this, in any case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean a comment like this?:
Although #2622 is closed, ccall still does not automatically disable SIGINT.
have you checked whether it makes a measurable difference in performance?
No, but the code without it was unsafe. It manifested easily because I added reenable_sigint
so that julia
runtime complains. Wasn't it needed to avoid setfault like #15?
Having said that, there are places where we can merge disable_sigint
and do it in a batch while using ccall
s. If we detect performance regression I guess we can use such tricks. I need to look at benchmarks/
code to do the check.
I'm confused by what this fixes. AFAICT, there shouldn't be any need for any |
Also, just tested locally, aborting in the code you have in the top post works just fine from julia REPL. |
julia> py"""
try:
print("Hit Ctrl-C a few seconds later!")
$sleep(10)
except KeyboardInterrupt as err:
print("Got:", err)
else:
print("Got nothing")
"""
^CERROR: LoadError: InterruptException:
Stacktrace:
[1] @py_str(::LineNumberNode, ::Module, ::Any, ::Vararg{Any,N} where N) at /home/yuyichao/.julia/packages/PyCall/rUul9/src/pyeval.jl:200
in expression starting at REPL[4]:1 |
@yuyichao You need to be a bit patient and wait until you see the message My example uses PyCall.jl's mechanism to translate Julia's Line 122 in fb88f4d
However, IIUC, in order for this to work, SIGINT handler has to be enabled during Julia's |
It should not. OK, so PyCall is still using private API to disable sigint, it should just use Note that |
Thanks for the clarification.
That would be great. Is there a Julia issue tracking it? Shall I open one? I have one more question. When using libjulia, do I need to call My another related worry is that if it is possible to get back to the "0-th level", even all Julia packages I use calls |
Sure.
If you don't want julia callbacks to throw across python frame than yes.
Not sure if I understand this... |
When I was asking that question, I was thinking that something like the following would fail in the way Python cannot control: from julia import Julia
jl = Julia()
evil_func = jl.eval("""
function evil_func()
Base.sigatomic_end()
end
""")
evil_func() However, I just tried it and found that Julia notices the mistake in |
Hmm... A puzzling thing is that this PR only works in "interactive session". Is exception handler available only in REPL? Note that calling $ cat hitme.jl
@show Base.JLOptions().handle_signals
using PyCall
py"""
$sleep(0)
try:
print("Hit Ctrl-C!")
$sleep(10)
except KeyboardInterrupt as err:
print("Got:", err)
else:
print("Got nothing")
"""
$ julia < hitme.jl # "interactive session"
(Base.JLOptions()).handle_signals = 1
1
Hit Ctrl-C!
^CGot: Julia exception: InterruptException()
$ julia -e 'include("hitme.jl")'
(Base.JLOptions()).handle_signals = 1
Hit Ctrl-C!
^Cfatal: error thrown and no exception handler available.
InterruptException()
jl_run_once at /buildworker/worker/package_linux64/build/src/jl_uv.c:185
process_events at ./libuv.jl:98 [inlined]
wait at ./event.jl:246
task_done_hook at ./task.jl:309
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2182
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1536 [inlined]
finish_task at /buildworker/worker/package_linux64/build/src/task.c:233
start_task at /buildworker/worker/package_linux64/build/src/task.c:276
unknown function (ip: 0xffffffffffffffff)
julia -e 'include("hitme.jl")' 6.76s user 0.75s system 70% cpu 10.716 total
$ julia hitme.jl
(Base.JLOptions()).handle_signals = 1
Hit Ctrl-C!
^C
signal (2): Interrupt
in expression starting at /home/takafumi/.julia/dev/PyCall/hitme.jl:3
syscall at /usr/lib/libc.so.6 (unknown line)
uv__epoll_wait at /buildworker/worker/package_linux64/build/deps/srccache/libuv-ed3700c849289ed01fe04273a7bf865340b2bd7e/src/unix/linux-syscalls.c:321
uv__io_poll at /buildworker/worker/package_linux64/build/deps/srccache/libuv-ed3700c849289ed01fe04273a7bf865340b2bd7e/src/unix/linux-core.c:275
uv_run at /buildworker/worker/package_linux64/build/deps/srccache/libuv-ed3700c849289ed01fe04273a7bf865340b2bd7e/src/unix/core.c:360
process_events at ./libuv.jl:98 [inlined]
wait at ./event.jl:246
task_done_hook at ./task.jl:309
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2182
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1536 [inlined]
finish_task at /buildworker/worker/package_linux64/build/src/task.c:233
start_task at /buildworker/worker/package_linux64/build/src/task.c:276
unknown function (ip: 0xffffffffffffffff)
unknown function (ip: 0xffffffffffffffff)
Allocations: 16558214 (Pool: 16554931; Big: 3283); GC: 36
julia hitme.jl 6.90s user 0.55s system 71% cpu 10.416 total |
It was because my startup.jl starts some |
Here is another problem (I'm wondering if it could be a bug in julia). With this branch, evaluating import DiffEqBase # it was necessary somehow...
show(IOBuffer(), "text/plain", @doc Base.Enum) via PyJulia segfaults at Here is the reproducible environment which can be run by the following commands (note: it does not work in Debian JuliaPy/pyjulia#185): git clone https://gist.github.com/tkf/5f14bcc6957641be44f3bdba24e83a8c segfault
cd segfault
make Here is the stacktrace: https://gist.github.com/tkf/048bc3a96576da7957880094cfeeeec8 I split the change in smaller patches and ran @yuyichao @stevengj Does it make sense to report it to JuliaLang/julia? Is it possible that this is a bug in (lib)julia? |
Note 1: There is a patch JuliaLang/julia#31191 mentioning JuliaLang/julia#29498 so maybe the situation is better now? Note 2: I don't remember if I tried it, but maybe changing Lines 49 to 50 in 0b2dc20
to pyjlwrap_call(self_::PyPtr, args_::PyPtr, kw_::PyPtr) =
Base.invokelatest(_pyjlwrap_call, unsafe_pyjlwrap_to_objref(self_), args_, kw_) makes sense? Note that we are doing Lines 21 to 28 in 0b2dc20
|
TODO: #683 (comment) |
This PR makes the following example work:
Without this PR, the exception is raised in Julia side after the
sleep
is completed (i.e., no early termination):