os: add a convenient way to ignore certain system signals (#19632)

This commit is contained in:
shove 2023-10-24 04:48:39 +08:00 committed by GitHub
parent 9051ac8921
commit 0c92c31406
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 0 deletions

View File

@ -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) {
}

39
vlib/os/signal_darwin.c.v Normal file
View File

@ -0,0 +1,39 @@
[has_globals]
module os
#include <signal.h>
// 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 })
}
}

View File

@ -0,0 +1,5 @@
module os
// unsupported platforms
pub fn signal_ignore(args ...Signal) {
}

42
vlib/os/signal_linux.c.v Normal file
View File

@ -0,0 +1,42 @@
[has_globals]
module os
#include <signal.h>
// 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 })
}
}

View File

@ -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()
}