Skip to content

Commit

Permalink
os: add a convenient way to ignore certain system signals (#19639)
Browse files Browse the repository at this point in the history
  • Loading branch information
shove70 authored Oct 25, 2023
1 parent 90ac5dc commit 8394b35
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 0 deletions.
24 changes: 24 additions & 0 deletions vlib/os/signal.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,27 @@ pub fn signal_opt(signum Signal, handler SignalHandler) !SignalHandler {
}
return SignalHandler(prev_handler)
}

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

// An empty system signal handler (callback function) used to mask the specified system signal.
fn ignore_signal_handler(signal Signal) {
}

// 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.
$if !windows {
for arg in args {
signal_opt(arg, ignore_signal_handler) or {}
}
}
} else {
// for background threads.
signal_ignore_internal(...args)
}
}
30 changes: 30 additions & 0 deletions vlib/os/signal_darwin.c.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[has_globals]
module os

#flag -lpthread
#include <signal.h>

fn C.pthread_self() usize

// g_main_thread_id and is_main_thread can be used to determine if the current thread is the main thread.
// if need to get the tid of the main thread, can use the global variable g_main_thread_id
// instead of using thread_id() every time.
__global g_main_thread_id = u64(C.pthread_self())

// is_main_thread returns whether the current thread is the main thread.
pub fn is_main_thread() bool {
return g_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

fn signal_ignore_internal(args ...Signal) {
mask1 := u32(0)
C.sigemptyset(&mask1)
for arg in args {
C.sigaddset(&mask1, int(arg))
}
C.sigprocmask(C.SIG_BLOCK, &mask1, unsafe { nil })
}
35 changes: 35 additions & 0 deletions vlib/os/signal_default.c.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[has_globals]
module os

#flag -lpthread
#include <signal.h>

fn C.pthread_self() usize

// g_main_thread_id and is_main_thread can be used to determine if the current thread is the main thread.
// if need to get the tid of the main thread, can use the global variable g_main_thread_id
// instead of using thread_id() every time.
__global g_main_thread_id = u64(C.pthread_self())

// is_main_thread returns whether the current thread is the main thread.
pub fn is_main_thread() bool {
return g_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

fn signal_ignore_internal(args ...Signal) {
$if !android {
mask1 := C.sigset_t{}
C.sigemptyset(&mask1)
for arg in args {
C.sigaddset(&mask1, int(arg))
}
C.sigprocmask(C.SIG_BLOCK, &mask1, unsafe { nil })
}
}
12 changes: 12 additions & 0 deletions vlib/os/signal_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
18 changes: 18 additions & 0 deletions vlib/os/signal_windows.c.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[has_globals]
module os

fn C.GetCurrentThreadId() u32

// g_main_thread_id and is_main_thread can be used to determine if the current thread is the main thread.
// if need to get the tid of the main thread, can use the global variable g_main_thread_id
// instead of using thread_id() every time.
__global g_main_thread_id = u64(C.GetCurrentThreadId())

// is_main_thread returns whether the current thread is the main thread.
pub fn is_main_thread() bool {
return g_main_thread_id == u64(C.GetCurrentThreadId())
}

// The windows platform does not need to be handled.
fn signal_ignore_internal(args ...Signal) {
}

0 comments on commit 8394b35

Please sign in to comment.