diff --git a/vlib/os/signal.v b/vlib/os/signal.v index e359a0f3e8..f6f4c34255 100644 --- a/vlib/os/signal.v +++ b/vlib/os/signal.v @@ -41,3 +41,7 @@ pub enum Signal { } pub type SignalHandler = fn (Signal) + +// An empty system signal handler (callback function) used to mask the specified system signal. +fn ignore_signal_handler(signal Signal) { +} diff --git a/vlib/os/signal_darwin.c.v b/vlib/os/signal_darwin.c.v new file mode 100644 index 0000000000..d4d9f11d61 --- /dev/null +++ b/vlib/os/signal_darwin.c.v @@ -0,0 +1,39 @@ +[has_globals] +module os + +#include + +// A convenient way to ignore certain system signals when there is no need to process certain system signals, +// Masking of system signals under posix systems requires a distinction between main and background threads. +// Since there is no good way to easily tell whether the current thread is the main or background thread, +// So a global variable is introduced to make the distinction. + +fn C.pthread_self() usize + +__global main_thread_id = u64(C.pthread_self()) + +fn is_main_thread() bool { + return main_thread_id == u64(C.pthread_self()) +} + +fn C.sigaddset(set &u32, signum int) int +fn C.sigemptyset(set &u32) +fn C.sigprocmask(how int, set &u32, oldset &u32) int + +// signal_ignore to mask system signals, e.g.: signal_ignore(.pipe, .urg, ...) +pub fn signal_ignore(args ...Signal) { + if is_main_thread() { + // for main thread. + for arg in args { + C.signal(int(arg), ignore_signal_handler) + } + } else { + // for background threads. + mask1 := u32(0) + C.sigemptyset(&mask1) + for arg in args { + C.sigaddset(&mask1, int(arg)) + } + C.sigprocmask(C.SIG_BLOCK, &mask1, unsafe { nil }) + } +} diff --git a/vlib/os/signal_default.c.v b/vlib/os/signal_default.c.v new file mode 100644 index 0000000000..0ef4a153f3 --- /dev/null +++ b/vlib/os/signal_default.c.v @@ -0,0 +1,5 @@ +module os + +// unsupported platforms +pub fn signal_ignore(args ...Signal) { +} diff --git a/vlib/os/signal_linux.c.v b/vlib/os/signal_linux.c.v new file mode 100644 index 0000000000..99fc921bdd --- /dev/null +++ b/vlib/os/signal_linux.c.v @@ -0,0 +1,42 @@ +[has_globals] +module os + +#include + +// A convenient way to ignore certain system signals when there is no need to process certain system signals, +// Masking of system signals under posix systems requires a distinction between main and background threads. +// Since there is no good way to easily tell whether the current thread is the main or background thread, +// So a global variable is introduced to make the distinction. + +fn C.pthread_self() usize + +__global main_thread_id = u64(C.pthread_self()) + +fn is_main_thread() bool { + return main_thread_id == u64(C.pthread_self()) +} + +[typedef] +struct C.sigset_t {} + +fn C.sigaddset(set &C.sigset_t, signum int) int +fn C.sigemptyset(set &C.sigset_t) +fn C.sigprocmask(how int, set &C.sigset_t, oldset &C.sigset_t) int + +// signal_ignore to mask system signals, e.g.: signal_ignore(.pipe, .urg, ...) +pub fn signal_ignore(args ...Signal) { + if is_main_thread() { + // for main thread. + for arg in args { + C.signal(int(arg), ignore_signal_handler) + } + } else { + // for background threads. + mask1 := C.sigset_t{} + C.sigemptyset(&mask1) + for arg in args { + C.sigaddset(&mask1, int(arg)) + } + C.sigprocmask(C.SIG_BLOCK, &mask1, unsafe { nil }) + } +} diff --git a/vlib/os/signal_test.v b/vlib/os/signal_test.v index 66aa8a4d09..c803c6b546 100644 --- a/vlib/os/signal_test.v +++ b/vlib/os/signal_test.v @@ -33,3 +33,15 @@ fn test_signal_opt_return_former_handler() { // this should work, but makes the CI fail because of a bug in clang -fsanitize=memory // assert func2 == former_handler } + +fn signal_ignore_in_background_thread() { + os.signal_ignore(.pipe, .urg) + assert true +} + +fn test_signal_ignore() { + os.signal_ignore(.pipe, .urg) + assert true + t := spawn signal_ignore_in_background_thread() + t.wait() +}