-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
When calling into foreign code via ccall, it is possible that the foreign libraries will try to install their own signal handlers, replacing Julia's signal handlers.
In this case, could we provide a mechanism to backup and restore Julia's default signal handlers?
https://cs.github.com/JuliaLang/julia/blob/51bb96857d26f67e62f0edc4fc4682a156cb3d08/src/signals-unix.c#L981
Background
sigaction is part of the POSIX standard and accepts three arguments.
https://pubs.opengroup.org/onlinepubs/007904875/functions/sigaction.html
int sigaction(int sig, const struct sigaction *restrict act,
struct sigaction *restrict oact);sig- the signal to install the handler for (in)act- the handler to install (in)oact- the original handler that was installed (out)
If act is a null pointer, no signal handler will be installed. If oact is a null pointer, the original handler that was installed will not be written.
By using sigaction(sig, NULL, oact) we can retrieve the currently installed signal handlers.
Signal Handlers used by Julia
- SIGFPE
- SIGINT, SIGPIPE, SIGTRAP
- SIGUSR2 or mach handler*
- SIGILL, SIGABRT, SIGSYS, SIGPROF, SIGINFO, SIGUSR1
- SIGSEGV and SIGBUS
* Does not use sigaction
Proposal
Provide exported C functions to obtain and restore current signal handlers as an opaque pointer. This is specifically designed so that Julia functions do not need to know about the sizeof(struct sigaction) or any of the underlying implementation details.
#include <signal.h>
#include <stddef.h>
#include <malloc.h>
#include <string.h>
JL_DLLEXPORT int jl_get_signal_handlers(struct sigaction ** p_signal_handlers) {
struct sigaction * signal_handlers = malloc(sizeof(struct sigaction)*5);
memset(signal_handlers, 0, sizeof(struct sigaction)*5);
if(sigaction(SIGFPE, NULL, &signal_handlers[0]) < 0)
return -1;
if(sigaction(SIGINT, NULL, &signal_handlers[1]) < 0)
return -1;
if(sigaction(SIGUSR2, NULL, &signal_handlers[2]) < 0)
return -1;
if(sigaction(SIGILL, NULL, &signal_handlers[3]) < 0)
return -1;
if(sigaction(SIGSEGV, NULL, &signal_handlers[4]) < 0)
return -1;
*p_signal_handlers = signal_handlers;
return 0;
}
JL_DLLEXPORT int jl_set_signal_handlers(struct sigaction * signal_handlers) {
if(sigaction(SIGFPE, &signal_handlers[0], NULL) < 0)
return -1;
if(sigaction(SIGINT, &signal_handlers[1], NULL) < 0)
return -1;
if(sigaction(SIGUSR2, &signal_handlers[2], NULL) < 0)
return -1;
if(sigaction(SIGILL, &signal_handlers[3], NULL) < 0)
return -1;
if(sigaction(SIGSEGV, &signal_handlers[4], NULL) < 0)
return -1;
return 0;
}function restore_signal_handlers(func::Function)
ref = Ref{Ptr{Nothing}}(C_NULL)
status = @ccall jl_get_signal_handlers(ref::Ptr{Ptr{Nothing}})::Cint
status < 0 || error("Failed to get signal handlers")
try
func()
finally
status = @ccall jl_set_signal_handlers(ref[]::Ptr{Nothing})::Cint
status < 0 || error("Failed to set signal handlers")
end
endUsage
restore_signal_handlers() do
@ccall function_that_installs_signal_handlers(...)
endWhile the above mechanisms do not obtain the foreign signal handlers, it would not be hard for specific applications to use the new C functions to do so.