[libos] Implement the rt_sigsuspend syscall
This commit is contained in:
		
							parent
							
								
									d6741c0096
								
							
						
					
					
						commit
						219fdd4e26
					
				
							
								
								
									
										36
									
								
								src/libos/src/signal/do_sigsuspend.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										36
									
								
								src/libos/src/signal/do_sigsuspend.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| use super::do_sigprocmask::do_rt_sigprocmask; | ||||
| use super::do_sigtimedwait::PendingSigWaiter; | ||||
| use super::{sigset_t, MaskOp, SigNum, SigSet, Signal}; | ||||
| use crate::prelude::*; | ||||
| 
 | ||||
| pub fn do_sigsuspend(mask: &sigset_t) -> 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)) | ||||
|             }; | ||||
|             do_rt_sigprocmask(op_and_set, None).unwrap(); | ||||
|             Err(errno!(EINTR, "Wait for EINTR signal successfully")) | ||||
|         } | ||||
|         Err(_) => { | ||||
|             // Impossible path
 | ||||
|             Err(errno!(EFAULT, "No interesting, pending signal")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -35,7 +35,7 @@ pub fn do_sigtimedwait(interest: SigSet, timeout: Option<&Duration>) -> Result<s | ||||
|     Ok(siginfo) | ||||
| } | ||||
| 
 | ||||
| struct PendingSigWaiter { | ||||
| pub struct PendingSigWaiter { | ||||
|     thread: ThreadRef, | ||||
|     process: ProcessRef, | ||||
|     interest: SigSet, | ||||
| @ -109,6 +109,40 @@ impl PendingSigWaiter { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn suspend(&self) -> Result<()> { | ||||
|         let waiter_queue = self.observer.waiter_queue(); | ||||
|         let waiter = Waiter::new(); | ||||
|         // As EINTR may occur even if there are no interesting signals
 | ||||
|         loop { | ||||
|             // Try to search for an interesting signal from the current process or thread
 | ||||
|             if has_interest_signal(&self.interest, &self.thread, &self.process) { | ||||
|                 return Ok(()); | ||||
|             } | ||||
| 
 | ||||
|             // Enqueue the waiter so that it can be waken up by the queue later.
 | ||||
|             waiter_queue.reset_and_enqueue(&waiter); | ||||
| 
 | ||||
|             // As there is no intersting signal right now, let's wait for
 | ||||
|             // the arrival of an interesting signal.
 | ||||
|             let res = waiter.wait(None); | ||||
| 
 | ||||
|             // Do not try again if some error is encountered. There are only
 | ||||
|             // two possible errors: ETIMEDOUT or EINTR.
 | ||||
|             if let Err(e) = res { | ||||
|                 // When interrupted is reached, it is possible that the interrupting signal happens
 | ||||
|                 // to be an interesting and pending signal. So we attempt to search for signals again.
 | ||||
|                 if e.errno() == Errno::EINTR { | ||||
|                     if has_interest_signal(&self.interest, &self.thread, &self.process) { | ||||
|                         return Ok(()); | ||||
|                     } | ||||
|                 } else { | ||||
|                     // Impossible case
 | ||||
|                     return Err(e); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for PendingSigWaiter { | ||||
| @ -129,6 +163,20 @@ 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) | ||||
| } | ||||
| 
 | ||||
| fn dequeue_pending_signal( | ||||
|     interest: &SigSet, | ||||
|     thread: &ThreadRef, | ||||
|  | ||||
| @ -23,6 +23,7 @@ mod do_sigaction; | ||||
| mod do_sigaltstack; | ||||
| mod do_sigpending; | ||||
| mod do_sigreturn; | ||||
| mod do_sigsuspend; | ||||
| mod do_sigtimedwait; | ||||
| mod sig_action; | ||||
| mod sig_dispositions; | ||||
|  | ||||
| @ -194,3 +194,16 @@ pub fn do_rt_sigtimedwait( | ||||
|     *info = super::do_sigtimedwait::do_sigtimedwait(mask, timeout.as_ref())?; | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| pub fn do_rt_sigsuspend(mask_ptr: *const sigset_t) -> Result<isize> { | ||||
|     let mask = { | ||||
|         if mask_ptr.is_null() { | ||||
|             return_errno!(EFAULT, "ptr must not be null"); | ||||
|         } | ||||
|         from_user::check_ptr(mask_ptr)?; | ||||
|         unsafe { *mask_ptr } | ||||
|     }; | ||||
| 
 | ||||
|     super::do_sigsuspend::do_sigsuspend(&mask)?; | ||||
|     Ok(0) | ||||
| } | ||||
|  | ||||
| @ -60,8 +60,8 @@ use crate::sched::{ | ||||
| }; | ||||
| use crate::signal::{ | ||||
|     do_kill, do_rt_sigaction, do_rt_sigpending, do_rt_sigprocmask, do_rt_sigreturn, | ||||
|     do_rt_sigtimedwait, do_sigaltstack, do_tgkill, do_tkill, sigaction_t, siginfo_t, sigset_t, | ||||
|     stack_t, | ||||
|     do_rt_sigsuspend, do_rt_sigtimedwait, do_sigaltstack, do_tgkill, do_tkill, sigaction_t, | ||||
|     siginfo_t, sigset_t, stack_t, | ||||
| }; | ||||
| use crate::vm::{MMapFlags, MRemapFlags, MSyncFlags, MadviceFlags, VMPerms}; | ||||
| use crate::{fs, process, std, vm}; | ||||
| @ -227,7 +227,7 @@ macro_rules! process_syscall_table_with_callback { | ||||
|             (RtSigpending = 127) => do_rt_sigpending(buf_ptr: *mut sigset_t, buf_size: usize), | ||||
|             (RtSigtimedwait = 128) => do_rt_sigtimedwait(mask_ptr: *const sigset_t, info_ptr: *mut siginfo_t, timeout_ptr: *const timespec_t, mask_size: usize), | ||||
|             (RtSigqueueinfo = 129) => handle_unsupported(), | ||||
|             (RtSigsuspend = 130) => handle_unsupported(), | ||||
|             (RtSigsuspend = 130) => do_rt_sigsuspend(mask_ptr: *const sigset_t), | ||||
|             (Sigaltstack = 131) => do_sigaltstack(ss: *const stack_t, old_ss: *mut stack_t, context: *const CpuContext), | ||||
|             (Utime = 132) => do_utime(path: *const i8, times: *const utimbuf_t), | ||||
|             (Mknod = 133) => handle_unsupported(), | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user