If you are wrapping ccall, another thing you can do is to wrap it with disable_sigint
C Interface · The Julia Language so that you don’t have to worry when calling the C functions that may not be interrupt safe.
Good idea. (… two minutes later…) On the other hand, what about calls that block for a while and are interrupt safe? Is that really something that should be automatic? maybe it should be a different macro? maybe an optional flag?
I think it’s better to have a safer default. If the C function is interrupt-safe, maybe just use ccall
. A separate macro like @interruptable_ccall
also makes sense.
I see your point. It would be nice if there were builtin interruptable_ccall
… Regarding the name, maybe just @c
for ccall
+ disable_sigint
? If you read it “at C do this” that’s kind of nice. Or maybe @guardedccall
to emphasise that it’s not entirely “safe” (because it can’t be) but it’s guarded from something (= sigint).
Yes if you’re naming it @ccall
, that should just be different syntax for ccall
.
It looks like disable_sigint
far predates @yuyichao’s big cleanup of the interrupt delivery in https://github.com/JuliaLang/julia/pull/16174. I’m not sure disable_sigint
is even necessary anymore.
A signal generated (for example) by Ctrl-C can be delivered even in a single threaded, single-Task
environment — it’s a facility provided by the operating system (and a bit platform dependent, see https://linux.die.net/man/2/signal or signal | Microsoft Learn for example).
Julia installs signal handlers for various internal things which users normally shouldn’t need to worry about, and from the look of the way InterruptException
is now delivered you shouldn’t need to worry about these corrupting the state of code which you’ve ccall
’d.
I think it is. See a recent discussion with @yuyichao in https://github.com/JuliaPy/PyCall.jl/pull/574
No, only if your c function can call back into Julia and doesn’t support longjmp (to be fair the second condition is likely to be the case if the first one is satisfied). Most c code don’t.
I see. So I guess @ccall
macro can wrap ccall
with disable_sigint
when it detects @cfunction
is used in the expression it’s transforming. Not sure if it’s too much of a magic, though. Also, call to Julia can happen in other ways.
Right, that makes sense. Perhaps it would be best to just leave sigint handling disabled inside julia code called by a cfunction
so that people would have to opt for the unsafe behavior explicitly… as you say, the typical C code which is calling the typical cfunction
won’t be longjmp safe. Is this feasible?
That’s not going to catch anything useful.
Do you mean what I proposed was non-comprehensive and over-protecting? If so, I agree (I already mentioned that it was not comprehensive).
No, I mean it’s just a bad heuristic. It’s not just over protecting, it’s underprotecting at the same time. It doesn’t catch most (any?) cases in the pycall issue.
I understand. That’s why I said non-comprehensive.
How about a syntax like
err = @C disable_sigint error_on_nonzero more_cowbell mkfifo(pathname::Cstring, mode::Cuint)::Cint
where symbols before the function call are flags that alter the behavior of the macro?
There’s nothing more we can do to improve the SIGINT
handling in the @ccall
macro; ccall
itself already does a good job of this (see #16174).
If you want syntax for extra behavior, I’d suggest tacking them on as extra key=value
pairs after the function signature (in analogy to @test
). Though I’m not sure that makes sense if there’s no equivalent behavior in ccall
itself.
I like the direction you’re going, but I think at that point it’s better just to chain macros @disable_siginit @nonzero_err @ccall ...
, it’s not much longer, it reads about the same, and the implementation is simpler.
@yuyichao what’s the feasibility of deferring SIGINT within @cfunction
generated wrappers by default? That would seem to be a reasonable heuristic, given that throwing InterruptException
inside cfunction is likely to jump over (and corrupt) non-julia stack frames.
It’s easy to implement. As for the default, there are people who complains when the exceptions are thrown too aggressively and when the exceptions are thrown not aggressively enough so I have no opinion on that.