[test] Implement ut for sigsuspend
This commit is contained in:
		
							parent
							
								
									219fdd4e26
								
							
						
					
					
						commit
						e96a1348e5
					
				| @ -1152,7 +1152,6 @@ rt_sigaction03 rt_sigaction03 | ||||
| rt_sigprocmask01 rt_sigprocmask01 | ||||
| #rt_sigprocmask02 rt_sigprocmask02 | ||||
| rt_sigqueueinfo01 rt_sigqueueinfo01 | ||||
| rt_sigsuspend01 rt_sigsuspend01 | ||||
| rt_sigtimedwait01 rt_sigtimedwait01 | ||||
| rt_tgsigqueueinfo01 rt_tgsigqueueinfo01 | ||||
| 
 | ||||
| @ -1448,8 +1447,6 @@ sigprocmask01 sigprocmask01 | ||||
| 
 | ||||
| sigrelse01 sigrelse01 | ||||
| 
 | ||||
| sigsuspend01 sigsuspend01 | ||||
| 
 | ||||
| sigtimedwait01 sigtimedwait01 | ||||
| 
 | ||||
| sigwait01 sigwait01 | ||||
|  | ||||
| @ -38,15 +38,25 @@ pub fn do_handle_interrupt( | ||||
| /// Broadcast interrupts to threads by sending POSIX signals.
 | ||||
| pub fn broadcast_interrupts() -> Result<usize> { | ||||
|     let should_interrupt_thread = |thread: &&ThreadRef| -> bool { | ||||
|         let should_interrupt = thread.process().is_forced_to_exit() | ||||
|             || thread.is_forced_to_stop() | ||||
|             || !thread.process().sig_queues().read().unwrap().empty(); | ||||
|         if thread.process().is_forced_to_exit() || thread.is_forced_to_stop() { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         // Check Thread::sig_mask to avoid wrong interrupts
 | ||||
|         let sig_queues = thread.sig_queues().read().unwrap(); | ||||
|         let sig_mask = thread.sig_mask().read().unwrap(); | ||||
|         let sig_mask_guard = thread.sig_mask().read().unwrap(); | ||||
|         let interested = !*sig_mask_guard; | ||||
|         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() | ||||
|  | ||||
| @ -7,7 +7,7 @@ use super::io_multiplexing::{AsEpollFile, EpollCtl, EpollFile, EpollFlags, FdSet | ||||
| use fs::{CreationFlags, File, FileDesc, FileRef}; | ||||
| use misc::resource_t; | ||||
| use process::Process; | ||||
| use signal::{do_sigprocmask, sigset_t, MaskOp, SigSet}; | ||||
| use signal::{sigset_t, MaskOp, SigSet, SIGKILL, SIGSTOP}; | ||||
| use std::convert::TryFrom; | ||||
| use time::{timespec_t, timeval_t}; | ||||
| use util::mem_util::from_user; | ||||
| @ -723,9 +723,9 @@ pub fn do_select( | ||||
|     ret | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, Debug)] | ||||
| #[derive(Debug)] | ||||
| #[repr(C)] | ||||
| pub struct Pselect6sig { | ||||
| pub struct sigset_argpack { | ||||
|     ss: *const sigset_t, | ||||
|     ss_len: size_t, | ||||
| } | ||||
| @ -736,11 +736,13 @@ pub fn do_pselect6( | ||||
|     writefds: *mut libc::fd_set, | ||||
|     exceptfds: *mut libc::fd_set, | ||||
|     timeout: *mut timespec_t, | ||||
|     sig_data: *const Pselect6sig, | ||||
|     sig_data: *const sigset_argpack, | ||||
| ) -> Result<isize> { | ||||
|     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() { | ||||
|         from_user::check_ptr(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>() { | ||||
|                 return_errno!(EINVAL, "unexpected sigset size"); | ||||
|             } | ||||
|             let op_and_set = { | ||||
|                 let op = MaskOp::SetMask; | ||||
|             let update_mask = { | ||||
|                 let sigset = user_sig_data.ss; | ||||
|                 from_user::check_ptr(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 | ||||
|             }; | ||||
| 
 | ||||
|             do_sigprocmask::do_rt_sigprocmask(op_and_set, Some(&mut original_sig_set))?; | ||||
|             let mut curr_mask = thread.sig_mask().write().unwrap(); | ||||
|             prev_mask = *curr_mask; | ||||
|             *curr_mask = update_mask; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -815,12 +822,8 @@ pub fn do_pselect6( | ||||
| 
 | ||||
|     // Restore the original signal mask
 | ||||
|     if is_set_sig { | ||||
|         let op_and_set = { | ||||
|             let op = MaskOp::SetMask; | ||||
|             let set = &original_sig_set; | ||||
|             Some((op, set)) | ||||
|         }; | ||||
|         do_sigprocmask::do_rt_sigprocmask(op_and_set, None)?; | ||||
|         let mut curr_mask = thread.sig_mask().write().unwrap(); | ||||
|         *curr_mask = prev_mask; | ||||
|     } | ||||
| 
 | ||||
|     ret | ||||
|  | ||||
| @ -6,6 +6,7 @@ pub fn do_sigpending() -> Result<SigSet> { | ||||
| 
 | ||||
|     let thread = current!(); | ||||
|     let process = thread.process(); | ||||
| 
 | ||||
|     let pending = (thread.sig_queues().read().unwrap().pending() | ||||
|         | process.sig_queues().read().unwrap().pending()) | ||||
|         & *thread.sig_mask().read().unwrap(); | ||||
|  | ||||
| @ -2,24 +2,15 @@ use super::constants::*; | ||||
| use super::{sigset_t, SigSet}; | ||||
| use crate::prelude::*; | ||||
| 
 | ||||
| pub fn do_rt_sigprocmask( | ||||
|     op_and_set: Option<(MaskOp, &sigset_t)>, | ||||
|     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 | ||||
|     ); | ||||
| pub fn do_rt_sigprocmask(op_and_set: Option<(MaskOp, &SigSet)>) -> Result<SigSet> { | ||||
|     debug!("do_rt_sigprocmask: op_and_set: {:?}", op_and_set,); | ||||
| 
 | ||||
|     let thread = current!(); | ||||
|     let mut sig_mask = thread.sig_mask().write().unwrap(); | ||||
|     if let Some(oldset) = oldset { | ||||
|         *oldset = sig_mask.to_c(); | ||||
|     } | ||||
|     if let Some((op, &set)) = op_and_set { | ||||
|     let old_mask = *sig_mask; | ||||
|     if let Some((op, set)) = op_and_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.
 | ||||
|             // Attempts to do so are silently ignored."
 | ||||
|             set -= SIGKILL; | ||||
| @ -38,7 +29,7 @@ pub fn do_rt_sigprocmask( | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
|     Ok(()) | ||||
|     Ok(old_mask) | ||||
| } | ||||
| 
 | ||||
| #[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::{sigset_t, MaskOp, SigNum, SigSet, Signal}; | ||||
| use crate::prelude::*; | ||||
| 
 | ||||
| pub fn do_sigsuspend(mask: &sigset_t) -> Result<()> { | ||||
| pub fn do_sigsuspend(mask: &SigSet) -> Result<()> { | ||||
|     debug!("do_sigsuspend: mask: {:?}", mask); | ||||
| 
 | ||||
|     let thread = current!(); | ||||
|     let process = thread.process().clone(); | ||||
|     let mut original_sig_set = sigset_t::default(); | ||||
| 
 | ||||
|     // Set signal mask
 | ||||
|     let op_and_set = Some((MaskOp::SetMask, mask)); | ||||
|     do_rt_sigprocmask(op_and_set, Some(&mut original_sig_set))?; | ||||
| 
 | ||||
|     let interest = SigSet::from_c(!*mask); | ||||
|     let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest); | ||||
| 
 | ||||
|     match pending_sig_waiter.suspend() { | ||||
|         Ok(_) => { | ||||
|             // Restore the original signal mask
 | ||||
|             let op_and_set = { | ||||
|                 let op = MaskOp::SetMask; | ||||
|                 let set = &original_sig_set; | ||||
|                 Some((op, set)) | ||||
|     let update_mask = { | ||||
|         let mut set = *mask; | ||||
|         // 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 | ||||
|     }; | ||||
|             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(_) => { | ||||
|             // 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,14 +136,13 @@ impl PendingSigWaiter { | ||||
|                     if has_interest_signal(&self.interest, &self.thread, &self.process) { | ||||
|                         return Ok(()); | ||||
|                     } | ||||
|                 } else { | ||||
|                 } | ||||
|                 // Impossible case
 | ||||
|                 return Err(e); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| 
 | ||||
| impl Drop for PendingSigWaiter { | ||||
|     fn drop(&mut self) { | ||||
| @ -164,17 +163,11 @@ impl Drop for PendingSigWaiter { | ||||
| } | ||||
| 
 | ||||
| fn has_interest_signal(interest: &SigSet, thread: &ThreadRef, process: &ProcessRef) -> bool { | ||||
|     let blocked = !*interest; | ||||
|     process | ||||
|         .sig_queues() | ||||
|         .write() | ||||
|         .unwrap() | ||||
|         .has_valid_signal(&blocked) | ||||
|         || thread | ||||
|             .sig_queues() | ||||
|             .write() | ||||
|             .unwrap() | ||||
|             .has_valid_signal(&blocked) | ||||
|     let pending = (thread.sig_queues().read().unwrap().pending() | ||||
|         | process.sig_queues().read().unwrap().pending()) | ||||
|         & *interest; | ||||
| 
 | ||||
|     !pending.empty() | ||||
| } | ||||
| 
 | ||||
| fn dequeue_pending_signal( | ||||
|  | ||||
| @ -22,6 +22,7 @@ mod do_kill; | ||||
| mod do_sigaction; | ||||
| mod do_sigaltstack; | ||||
| mod do_sigpending; | ||||
| mod do_sigprocmask; | ||||
| mod do_sigreturn; | ||||
| mod do_sigsuspend; | ||||
| mod do_sigtimedwait; | ||||
| @ -35,4 +36,3 @@ mod signals; | ||||
| mod syscalls; | ||||
| 
 | ||||
| pub mod constants; | ||||
| pub mod do_sigprocmask; | ||||
|  | ||||
| @ -38,41 +38,6 @@ impl SigQueues { | ||||
|         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>) { | ||||
|         let signum = signal.num(); | ||||
|         if signum.is_std() { | ||||
|  | ||||
| @ -89,23 +89,25 @@ pub fn do_rt_sigprocmask( | ||||
|     if sigset_size != std::mem::size_of::<sigset_t>() { | ||||
|         return_errno!(EINVAL, "unexpected sigset size"); | ||||
|     } | ||||
| 
 | ||||
|     let mut set_sig = SigSet::default(); | ||||
|     let op_and_set = { | ||||
|         if !set_ptr.is_null() { | ||||
|             let op = MaskOp::from_u32(how as u32)?; | ||||
|             let set = unsafe { &*set_ptr }; | ||||
|             Some((op, set)) | ||||
|             set_sig = SigSet::from_c(unsafe { *set_ptr }); | ||||
|             Some((op, &set_sig)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     }; | ||||
|     let old_set = { | ||||
| 
 | ||||
|     let old_set = super::do_sigprocmask::do_rt_sigprocmask(op_and_set)?; | ||||
|     if !oldset_ptr.is_null() { | ||||
|             Some(unsafe { &mut *oldset_ptr }) | ||||
|         } else { | ||||
|             None | ||||
|         unsafe { | ||||
|             *oldset_ptr = old_set.to_c(); | ||||
|         } | ||||
|     }; | ||||
|     super::do_sigprocmask::do_rt_sigprocmask(op_and_set, old_set)?; | ||||
|     } | ||||
| 
 | ||||
|     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"); | ||||
|         } | ||||
|         from_user::check_ptr(mask_ptr)?; | ||||
|         unsafe { *mask_ptr } | ||||
|         SigSet::from_c(unsafe { *mask_ptr }) | ||||
|     }; | ||||
| 
 | ||||
|     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_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, | ||||
|     Pselect6sig, | ||||
|     sigset_argpack, | ||||
| }; | ||||
| use crate::process::{ | ||||
|     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), | ||||
|             (Fchmodat = 268) => do_fchmodat(dirfd: i32, path: *const i8, mode: u16), | ||||
|             (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), | ||||
|             (Unshare = 272) => handle_unsupported(), | ||||
|             (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 \
 | ||||
| 	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 \
 | ||||
| 	ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait pselect \
 | ||||
| 	spawn_attribute exec statfs random umask pgrp vfork mount flock utimes shm epoll brk posix_shm | ||||
| 	ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs pselect sigsuspend \
 | ||||
| 	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
 | ||||
| BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput | ||||
| 
 | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include <errno.h> | ||||
| #include <stdint.h> // for uint64_t | ||||
| #include <pthread.h> | ||||
| #include "test.h" | ||||
| 
 | ||||
| // Signal handler for SIGUSR1
 | ||||
| void sigusr1_handler(int sig) { | ||||
| @ -36,13 +37,13 @@ int main() { | ||||
|     // 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) { | ||||
|         perror("pthread_create"); | ||||
|         THROW_ERROR("pthread_create"); | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     int timer_fd = timerfd_create(CLOCK_REALTIME, 0); | ||||
|     if (timer_fd == -1) { | ||||
|         perror("timerfd_create"); | ||||
|         THROW_ERROR("timerfd_create"); | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
| @ -52,7 +53,7 @@ int main() { | ||||
|     timerValue.it_interval.tv_sec = 0; | ||||
|     timerValue.it_interval.tv_nsec = 0; | ||||
|     if (timerfd_settime(timer_fd, 0, &timerValue, NULL) == -1) { | ||||
|         perror("timerfd_settime"); | ||||
|         THROW_ERROR("timerfd_settime"); | ||||
|         close(timer_fd); | ||||
|         return 1; | ||||
|     } | ||||
| @ -63,17 +64,17 @@ int main() { | ||||
| 
 | ||||
|     int ready = pselect(timer_fd + 1, &readfds, NULL, NULL, NULL, &sigmask); | ||||
| 
 | ||||
|     if (ready == -1) { | ||||
|         perror("pselect6"); | ||||
|     } else if (ready == 0) { | ||||
|         // Impossible case
 | ||||
|         printf("No input - timeout reached\n"); | ||||
|     } else { | ||||
|     if (ready > 0) { | ||||
|         if (FD_ISSET(timer_fd, &readfds)) { | ||||
|             printf("Timer expired, pselect blocked SIGUSR1 signal successfully\n"); | ||||
|             uint64_t 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); | ||||
|  | ||||
							
								
								
									
										5
									
								
								test/sigsuspend/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										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
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										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; | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user