[test] Implement ut for sigsuspend

This commit is contained in:
ClawSeven 2023-12-22 12:00:14 +08:00 committed by volcano
parent 1147e6956f
commit 2a801e5fec
15 changed files with 174 additions and 132 deletions

@ -1152,7 +1152,6 @@ rt_sigaction03 rt_sigaction03
rt_sigprocmask01 rt_sigprocmask01 rt_sigprocmask01 rt_sigprocmask01
#rt_sigprocmask02 rt_sigprocmask02 #rt_sigprocmask02 rt_sigprocmask02
rt_sigqueueinfo01 rt_sigqueueinfo01 rt_sigqueueinfo01 rt_sigqueueinfo01
rt_sigsuspend01 rt_sigsuspend01
rt_sigtimedwait01 rt_sigtimedwait01 rt_sigtimedwait01 rt_sigtimedwait01
rt_tgsigqueueinfo01 rt_tgsigqueueinfo01 rt_tgsigqueueinfo01 rt_tgsigqueueinfo01
@ -1448,8 +1447,6 @@ sigprocmask01 sigprocmask01
sigrelse01 sigrelse01 sigrelse01 sigrelse01
sigsuspend01 sigsuspend01
sigtimedwait01 sigtimedwait01 sigtimedwait01 sigtimedwait01
sigwait01 sigwait01 sigwait01 sigwait01

@ -38,15 +38,25 @@ pub fn do_handle_interrupt(
/// Broadcast interrupts to threads by sending POSIX signals. /// Broadcast interrupts to threads by sending POSIX signals.
pub fn broadcast_interrupts() -> Result<usize> { pub fn broadcast_interrupts() -> Result<usize> {
let should_interrupt_thread = |thread: &&ThreadRef| -> bool { let should_interrupt_thread = |thread: &&ThreadRef| -> bool {
let should_interrupt = thread.process().is_forced_to_exit() if thread.process().is_forced_to_exit() || thread.is_forced_to_stop() {
|| thread.is_forced_to_stop() return true;
|| !thread.process().sig_queues().read().unwrap().empty(); }
// Check Thread::sig_mask to avoid wrong interrupts let sig_mask_guard = thread.sig_mask().read().unwrap();
let sig_queues = thread.sig_queues().read().unwrap(); let interested = !*sig_mask_guard;
let sig_mask = thread.sig_mask().read().unwrap(); drop(sig_mask_guard);
should_interrupt || sig_queues.has_valid_signal(&sig_mask) let thread_pending_sig = thread.sig_queues().read().unwrap().pending() & interested;
if !thread_pending_sig.empty() {
return true;
}
let process_pending_sig =
thread.process().sig_queues().read().unwrap().pending() & interested;
if !process_pending_sig.empty() {
return true;
}
false
}; };
let num_signaled_threads = crate::process::table::get_all_threads() let num_signaled_threads = crate::process::table::get_all_threads()

@ -7,7 +7,7 @@ use super::io_multiplexing::{AsEpollFile, EpollCtl, EpollFile, EpollFlags, FdSet
use fs::{CreationFlags, File, FileDesc, FileRef}; use fs::{CreationFlags, File, FileDesc, FileRef};
use misc::resource_t; use misc::resource_t;
use process::Process; use process::Process;
use signal::{do_sigprocmask, sigset_t, MaskOp, SigSet}; use signal::{sigset_t, MaskOp, SigSet, SIGKILL, SIGSTOP};
use std::convert::TryFrom; use std::convert::TryFrom;
use time::{timespec_t, timeval_t}; use time::{timespec_t, timeval_t};
use util::mem_util::from_user; use util::mem_util::from_user;
@ -723,9 +723,9 @@ pub fn do_select(
ret ret
} }
#[derive(Clone, Copy, Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct Pselect6sig { pub struct sigset_argpack {
ss: *const sigset_t, ss: *const sigset_t,
ss_len: size_t, ss_len: size_t,
} }
@ -736,11 +736,13 @@ pub fn do_pselect6(
writefds: *mut libc::fd_set, writefds: *mut libc::fd_set,
exceptfds: *mut libc::fd_set, exceptfds: *mut libc::fd_set,
timeout: *mut timespec_t, timeout: *mut timespec_t,
sig_data: *const Pselect6sig, sig_data: *const sigset_argpack,
) -> Result<isize> { ) -> Result<isize> {
let mut is_set_sig = false; let mut is_set_sig = false;
let mut original_sig_set = sigset_t::default(); let mut prev_mask = SigSet::default();
let thread = current!();
// Set signal mask
if !sig_data.is_null() { if !sig_data.is_null() {
from_user::check_ptr(sig_data)?; from_user::check_ptr(sig_data)?;
let user_sig_data = unsafe { &*(sig_data) }; let user_sig_data = unsafe { &*(sig_data) };
@ -750,15 +752,20 @@ pub fn do_pselect6(
if user_sig_data.ss_len != std::mem::size_of::<sigset_t>() { if user_sig_data.ss_len != std::mem::size_of::<sigset_t>() {
return_errno!(EINVAL, "unexpected sigset size"); return_errno!(EINVAL, "unexpected sigset size");
} }
let op_and_set = { let update_mask = {
let op = MaskOp::SetMask;
let sigset = user_sig_data.ss; let sigset = user_sig_data.ss;
from_user::check_ptr(sigset)?; from_user::check_ptr(sigset)?;
let set = unsafe { &*sigset }; let set = unsafe { &*sigset };
Some((op, set)) let mut set = SigSet::from_c(unsafe { *sigset });
// According to man pages, "it is not possible to block SIGKILL or SIGSTOP.
// Attempts to do so are silently ignored."
set -= SIGKILL;
set -= SIGSTOP;
set
}; };
let mut curr_mask = thread.sig_mask().write().unwrap();
do_sigprocmask::do_rt_sigprocmask(op_and_set, Some(&mut original_sig_set))?; prev_mask = *curr_mask;
*curr_mask = update_mask;
} }
} }
@ -815,12 +822,8 @@ pub fn do_pselect6(
// Restore the original signal mask // Restore the original signal mask
if is_set_sig { if is_set_sig {
let op_and_set = { let mut curr_mask = thread.sig_mask().write().unwrap();
let op = MaskOp::SetMask; *curr_mask = prev_mask;
let set = &original_sig_set;
Some((op, set))
};
do_sigprocmask::do_rt_sigprocmask(op_and_set, None)?;
} }
ret ret

@ -6,6 +6,7 @@ pub fn do_sigpending() -> Result<SigSet> {
let thread = current!(); let thread = current!();
let process = thread.process(); let process = thread.process();
let pending = (thread.sig_queues().read().unwrap().pending() let pending = (thread.sig_queues().read().unwrap().pending()
| process.sig_queues().read().unwrap().pending()) | process.sig_queues().read().unwrap().pending())
& *thread.sig_mask().read().unwrap(); & *thread.sig_mask().read().unwrap();

@ -2,24 +2,15 @@ use super::constants::*;
use super::{sigset_t, SigSet}; use super::{sigset_t, SigSet};
use crate::prelude::*; use crate::prelude::*;
pub fn do_rt_sigprocmask( pub fn do_rt_sigprocmask(op_and_set: Option<(MaskOp, &SigSet)>) -> Result<SigSet> {
op_and_set: Option<(MaskOp, &sigset_t)>, debug!("do_rt_sigprocmask: op_and_set: {:?}", op_and_set,);
oldset: Option<&mut sigset_t>,
) -> Result<()> {
debug!(
"do_rt_sigprocmask: op_and_set: {:?}, oldset: {:?}",
op_and_set.map(|(op, set)| (op, SigSet::from_c(*set))),
oldset
);
let thread = current!(); let thread = current!();
let mut sig_mask = thread.sig_mask().write().unwrap(); let mut sig_mask = thread.sig_mask().write().unwrap();
if let Some(oldset) = oldset { let old_mask = *sig_mask;
*oldset = sig_mask.to_c(); if let Some((op, set)) = op_and_set {
}
if let Some((op, &set)) = op_and_set {
let set = { let set = {
let mut set = SigSet::from_c(set); let mut set = *set;
// According to man pages, "it is not possible to block SIGKILL or SIGSTOP. // According to man pages, "it is not possible to block SIGKILL or SIGSTOP.
// Attempts to do so are silently ignored." // Attempts to do so are silently ignored."
set -= SIGKILL; set -= SIGKILL;
@ -38,7 +29,7 @@ pub fn do_rt_sigprocmask(
} }
}; };
} }
Ok(()) Ok(old_mask)
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]

@ -1,36 +1,46 @@
use super::do_sigprocmask::do_rt_sigprocmask; use super::constants::*;
use super::do_sigtimedwait::PendingSigWaiter; use super::do_sigtimedwait::PendingSigWaiter;
use super::{sigset_t, MaskOp, SigNum, SigSet, Signal}; use super::{sigset_t, MaskOp, SigNum, SigSet, Signal};
use crate::prelude::*; use crate::prelude::*;
pub fn do_sigsuspend(mask: &sigset_t) -> Result<()> { pub fn do_sigsuspend(mask: &SigSet) -> Result<()> {
debug!("do_sigsuspend: mask: {:?}", mask); debug!("do_sigsuspend: mask: {:?}", mask);
let thread = current!(); let thread = current!();
let process = thread.process().clone(); let process = thread.process().clone();
let mut original_sig_set = sigset_t::default();
// Set signal mask // Set signal mask
let op_and_set = Some((MaskOp::SetMask, mask)); let update_mask = {
do_rt_sigprocmask(op_and_set, Some(&mut original_sig_set))?; let mut set = *mask;
// According to man pages, "it is not possible to block SIGKILL or SIGSTOP.
let interest = SigSet::from_c(!*mask); // Attempts to do so are silently ignored."
let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest); set -= SIGKILL;
set -= SIGSTOP;
match pending_sig_waiter.suspend() { set
Ok(_) => {
// Restore the original signal mask
let op_and_set = {
let op = MaskOp::SetMask;
let set = &original_sig_set;
Some((op, set))
}; };
do_rt_sigprocmask(op_and_set, None).unwrap();
Err(errno!(EINTR, "Wait for EINTR signal successfully")) let mut curr_mask = thread.sig_mask().write().unwrap();
let prev_mask = *curr_mask;
*curr_mask = update_mask;
drop(curr_mask);
// Suspend for interest signal
let interest = !update_mask;
let pending_sig_waiter = PendingSigWaiter::new(thread.clone(), process, interest);
let err = match pending_sig_waiter.suspend() {
Ok(_) => {
errno!(EINTR, "Wait for EINTR signal successfully")
} }
Err(_) => { Err(_) => {
// Impossible path // Impossible path
Err(errno!(EFAULT, "No interesting, pending signal")) errno!(EFAULT, "No interesting, pending signal")
}
} }
};
// Restore the original signal mask
let mut curr_mask = thread.sig_mask().write().unwrap();
*curr_mask = prev_mask;
Err(err)
} }

@ -136,13 +136,12 @@ impl PendingSigWaiter {
if has_interest_signal(&self.interest, &self.thread, &self.process) { if has_interest_signal(&self.interest, &self.thread, &self.process) {
return Ok(()); return Ok(());
} }
} else { }
// Impossible case // Impossible case
return Err(e); return Err(e);
} }
} }
} }
}
} }
impl Drop for PendingSigWaiter { impl Drop for PendingSigWaiter {
@ -164,17 +163,11 @@ impl Drop for PendingSigWaiter {
} }
fn has_interest_signal(interest: &SigSet, thread: &ThreadRef, process: &ProcessRef) -> bool { fn has_interest_signal(interest: &SigSet, thread: &ThreadRef, process: &ProcessRef) -> bool {
let blocked = !*interest; let pending = (thread.sig_queues().read().unwrap().pending()
process | process.sig_queues().read().unwrap().pending())
.sig_queues() & *interest;
.write()
.unwrap() !pending.empty()
.has_valid_signal(&blocked)
|| thread
.sig_queues()
.write()
.unwrap()
.has_valid_signal(&blocked)
} }
fn dequeue_pending_signal( fn dequeue_pending_signal(

@ -22,6 +22,7 @@ mod do_kill;
mod do_sigaction; mod do_sigaction;
mod do_sigaltstack; mod do_sigaltstack;
mod do_sigpending; mod do_sigpending;
mod do_sigprocmask;
mod do_sigreturn; mod do_sigreturn;
mod do_sigsuspend; mod do_sigsuspend;
mod do_sigtimedwait; mod do_sigtimedwait;
@ -35,4 +36,3 @@ mod signals;
mod syscalls; mod syscalls;
pub mod constants; pub mod constants;
pub mod do_sigprocmask;

@ -38,41 +38,6 @@ impl SigQueues {
self.count == 0 self.count == 0
} }
pub fn has_valid_signal(&self, blocked: &SigSet) -> bool {
// Fast path for the common case of no pending signals
if self.empty() {
return false;
}
// Check standard signals.
for &signum in &Self::ORDERED_STD_SIGS {
if blocked.contains(signum) {
continue;
}
let queue = self.get_std_queue(signum);
if queue.is_some() {
return true;
}
}
// If no standard signals, then check real-time signals.
for signum in MIN_RT_SIG_NUM..=MAX_RT_SIG_NUM {
let signum = unsafe { SigNum::from_u8_unchecked(signum) };
if blocked.contains(signum) {
continue;
}
let queue = self.get_rt_queue(signum);
if !queue.is_empty() {
return true;
}
}
// There must be pending but blocked signals
false
}
pub fn enqueue(&mut self, signal: Box<dyn Signal>) { pub fn enqueue(&mut self, signal: Box<dyn Signal>) {
let signum = signal.num(); let signum = signal.num();
if signum.is_std() { if signum.is_std() {

@ -89,23 +89,25 @@ pub fn do_rt_sigprocmask(
if sigset_size != std::mem::size_of::<sigset_t>() { if sigset_size != std::mem::size_of::<sigset_t>() {
return_errno!(EINVAL, "unexpected sigset size"); return_errno!(EINVAL, "unexpected sigset size");
} }
let mut set_sig = SigSet::default();
let op_and_set = { let op_and_set = {
if !set_ptr.is_null() { if !set_ptr.is_null() {
let op = MaskOp::from_u32(how as u32)?; let op = MaskOp::from_u32(how as u32)?;
let set = unsafe { &*set_ptr }; set_sig = SigSet::from_c(unsafe { *set_ptr });
Some((op, set)) Some((op, &set_sig))
} else { } else {
None None
} }
}; };
let old_set = {
let old_set = super::do_sigprocmask::do_rt_sigprocmask(op_and_set)?;
if !oldset_ptr.is_null() { if !oldset_ptr.is_null() {
Some(unsafe { &mut *oldset_ptr }) unsafe {
} else { *oldset_ptr = old_set.to_c();
None
} }
}; }
super::do_sigprocmask::do_rt_sigprocmask(op_and_set, old_set)?;
Ok(0) Ok(0)
} }
@ -201,7 +203,7 @@ pub fn do_rt_sigsuspend(mask_ptr: *const sigset_t) -> Result<isize> {
return_errno!(EFAULT, "ptr must not be null"); return_errno!(EFAULT, "ptr must not be null");
} }
from_user::check_ptr(mask_ptr)?; from_user::check_ptr(mask_ptr)?;
unsafe { *mask_ptr } SigSet::from_c(unsafe { *mask_ptr })
}; };
super::do_sigsuspend::do_sigsuspend(&mask)?; super::do_sigsuspend::do_sigsuspend(&mask)?;

@ -45,7 +45,7 @@ use crate::net::{
do_epoll_pwait, do_epoll_wait, do_getpeername, do_getsockname, do_getsockopt, do_listen, do_epoll_pwait, do_epoll_wait, do_getpeername, do_getsockname, do_getsockopt, do_listen,
do_poll, do_ppoll, do_pselect6, do_recvfrom, do_recvmsg, do_select, do_sendmmsg, do_sendmsg, do_poll, do_ppoll, do_pselect6, do_recvfrom, do_recvmsg, do_select, do_sendmmsg, do_sendmsg,
do_sendto, do_setsockopt, do_shutdown, do_socket, do_socketpair, mmsghdr, msghdr, msghdr_mut, do_sendto, do_setsockopt, do_shutdown, do_socket, do_socketpair, mmsghdr, msghdr, msghdr_mut,
Pselect6sig, sigset_argpack,
}; };
use crate::process::{ use crate::process::{
do_arch_prctl, do_clone, do_execve, do_exit, do_exit_group, do_futex, do_get_robust_list, do_arch_prctl, do_clone, do_execve, do_exit, do_exit_group, do_futex, do_get_robust_list,
@ -367,7 +367,7 @@ macro_rules! process_syscall_table_with_callback {
(Readlinkat = 267) => do_readlinkat(dirfd: i32, path: *const i8, buf: *mut u8, size: usize), (Readlinkat = 267) => do_readlinkat(dirfd: i32, path: *const i8, buf: *mut u8, size: usize),
(Fchmodat = 268) => do_fchmodat(dirfd: i32, path: *const i8, mode: u16), (Fchmodat = 268) => do_fchmodat(dirfd: i32, path: *const i8, mode: u16),
(Faccessat = 269) => do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32), (Faccessat = 269) => do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32),
(Pselect6 = 270) => do_pselect6(nfds: c_int, readfds: *mut libc::fd_set, writefds: *mut libc::fd_set, exceptfds: *mut libc::fd_set, timeout: *mut timespec_t, data: *const Pselect6sig), (Pselect6 = 270) => do_pselect6(nfds: c_int, readfds: *mut libc::fd_set, writefds: *mut libc::fd_set, exceptfds: *mut libc::fd_set, timeout: *mut timespec_t, data: *const sigset_argpack),
(Ppoll = 271) => do_ppoll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout_ts: *const timespec_t, sigmask: *const sigset_t), (Ppoll = 271) => do_ppoll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout_ts: *const timespec_t, sigmask: *const sigset_t),
(Unshare = 272) => handle_unsupported(), (Unshare = 272) => handle_unsupported(),
(SetRobustList = 273) => do_set_robust_list(list_head_ptr: *mut RobustListHead, len: usize), (SetRobustList = 273) => do_set_robust_list(list_head_ptr: *mut RobustListHead, len: usize),

@ -21,8 +21,8 @@ TEST_DEPS := client data_sink naughty_child
TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe time timerfd \ TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe time timerfd \
truncate readdir mkdir open stat link symlink chmod chown tls pthread system_info rlimit \ truncate readdir mkdir open stat link symlink chmod chown tls pthread system_info rlimit \
server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group posix_flock \ server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group posix_flock \
ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait pselect \ ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs pselect sigsuspend \
spawn_attribute exec statfs random umask pgrp vfork mount flock utimes shm epoll brk posix_shm wait spawn_attribute exec statfs random umask pgrp vfork mount flock utimes shm epoll brk posix_shm
# Benchmarks: need to be compiled and run by bench-% target # Benchmarks: need to be compiled and run by bench-% target
BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput

@ -6,6 +6,7 @@
#include <errno.h> #include <errno.h>
#include <stdint.h> // for uint64_t #include <stdint.h> // for uint64_t
#include <pthread.h> #include <pthread.h>
#include "test.h"
// Signal handler for SIGUSR1 // Signal handler for SIGUSR1
void sigusr1_handler(int sig) { void sigusr1_handler(int sig) {
@ -36,13 +37,13 @@ int main() {
// Spawn new thread for sending signal when call pselect syscall // Spawn new thread for sending signal when call pselect syscall
pthread_t signal_thread; pthread_t signal_thread;
if (pthread_create(&signal_thread, NULL, send_signal, &main_thread_id) != 0) { if (pthread_create(&signal_thread, NULL, send_signal, &main_thread_id) != 0) {
perror("pthread_create"); THROW_ERROR("pthread_create");
return 1; return 1;
} }
int timer_fd = timerfd_create(CLOCK_REALTIME, 0); int timer_fd = timerfd_create(CLOCK_REALTIME, 0);
if (timer_fd == -1) { if (timer_fd == -1) {
perror("timerfd_create"); THROW_ERROR("timerfd_create");
return 1; return 1;
} }
@ -52,7 +53,7 @@ int main() {
timerValue.it_interval.tv_sec = 0; timerValue.it_interval.tv_sec = 0;
timerValue.it_interval.tv_nsec = 0; timerValue.it_interval.tv_nsec = 0;
if (timerfd_settime(timer_fd, 0, &timerValue, NULL) == -1) { if (timerfd_settime(timer_fd, 0, &timerValue, NULL) == -1) {
perror("timerfd_settime"); THROW_ERROR("timerfd_settime");
close(timer_fd); close(timer_fd);
return 1; return 1;
} }
@ -63,17 +64,17 @@ int main() {
int ready = pselect(timer_fd + 1, &readfds, NULL, NULL, NULL, &sigmask); int ready = pselect(timer_fd + 1, &readfds, NULL, NULL, NULL, &sigmask);
if (ready == -1) { if (ready > 0) {
perror("pselect6");
} else if (ready == 0) {
// Impossible case
printf("No input - timeout reached\n");
} else {
if (FD_ISSET(timer_fd, &readfds)) { if (FD_ISSET(timer_fd, &readfds)) {
printf("Timer expired, pselect blocked SIGUSR1 signal successfully\n"); printf("Timer expired, pselect blocked SIGUSR1 signal successfully\n");
uint64_t expirations; uint64_t expirations;
read(timer_fd, &expirations, sizeof(expirations)); read(timer_fd, &expirations, sizeof(expirations));
} }
} else if (ready == 0) {
// Impossible case
printf("No input - timeout reached\n");
} else {
THROW_ERROR("failed to pselect");
} }
pthread_join(signal_thread, NULL); pthread_join(signal_thread, NULL);

5
test/sigsuspend/Makefile Normal file

@ -0,0 +1,5 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS := -lpthread
BIN_ARGS :=

64
test/sigsuspend/main.c Normal file

@ -0,0 +1,64 @@
#include <sys/select.h>
#include <sys/timerfd.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h> // for uint64_t
#include <pthread.h>
#include "test.h"
// Signal handler for SIGUSR1
void sigusr_handler(int sig) {
printf("Received signals: %d. ", sig);
}
void *send_signal(void *arg) {
pthread_t main_thread_id = *(pthread_t *)arg;
sleep(1);
pthread_kill(main_thread_id, SIGUSR1);
sleep(1);
pthread_kill(main_thread_id, SIGUSR2);
return NULL;
}
int main() {
// Set SIGUSR1 signal action
struct sigaction sa1;
sa1.sa_handler = sigusr_handler;
sigemptyset(&sa1.sa_mask);
sa1.sa_flags = 0;
sigaction(SIGUSR1, &sa1, NULL);
// Set SIGUSR2 signal action
struct sigaction sa2;
sa2.sa_handler = sigusr_handler;
sigemptyset(&sa2.sa_mask);
sa2.sa_flags = 0;
sigaction(SIGUSR2, &sa2, NULL);
// Mask for blocking SIGUSR1 signal
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGUSR1);
// Access pthread id
pthread_t main_thread_id = pthread_self();
// Spawn new thread for sending signal when call pselect syscall
pthread_t signal_thread;
if (pthread_create(&signal_thread, NULL, send_signal, &main_thread_id) != 0) {
THROW_ERROR("failed to create pthread");
return 1;
}
int ret = sigsuspend(&sigmask);
if (ret == -1) {
printf("Signal received, the rt_sigsuspend syscall returns successfully\n");
} else {
THROW_ERROR("failed to call rt_sigsuspend syscall");
}
pthread_join(signal_thread, NULL);
return 0;
}