`ccall` macros for controlling SIGINT handling

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.

1 Like

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.

See also: https://github.com/JuliaLang/julia/issues/2622

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).

1 Like

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.

1 Like

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.

2 Likes

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?

2 Likes

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.

2 Likes

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.

2 Likes

@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.

2 Likes