diff --git a/src/context/context.rs b/src/context/context.rs index 4986fcc01b..7dce13fd78 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -1,5 +1,5 @@ use alloc::{borrow::Cow, sync::Arc, vec::Vec}; -use syscall::{Sigcontrol, SIGKILL, SIGSTOP}; +use syscall::{SigProcControl, Sigcontrol, SIGKILL, SIGSTOP}; use core::{cmp::Ordering, mem::{self, size_of}, num::NonZeroUsize, sync::atomic::AtomicU64}; use spin::RwLock; @@ -7,11 +7,7 @@ use crate::{ arch::{interrupt::InterruptStack, paging::PAGE_SIZE}, common::aligned_box::AlignedBox, context::{self, arch, file::FileDescriptor, memory::AddrSpace}, cpu_set::{LogicalCpuId, LogicalCpuSet}, ipi::{ipi, IpiKind, IpiTarget}, memory::{allocate_p2frame, deallocate_p2frame, Enomem, Frame, RaiiFrame}, paging::{RmmA, RmmArch}, percpu::PercpuBlock, scheme::{CallerCtx, FileHandle, SchemeNamespace}, sync::WaitMap, }; -use crate::syscall::{ - data::SigAction, - error::{Error, Result, EAGAIN, ESRCH}, - flag::{SigActionFlags, SIG_DFL}, -}; +use crate::syscall::error::{Error, Result, EAGAIN, ESRCH}; /// Unique identifier for a context (i.e. `pid`). use ::core::sync::atomic::AtomicUsize; @@ -141,7 +137,7 @@ pub struct Context { pub ens: SchemeNamespace, /// Signal handler - pub sig: SignalState, + pub sig: Option, /// Process umask pub umask: usize, @@ -206,13 +202,16 @@ pub struct Context { #[derive(Debug)] pub struct SignalState { /// Offset to jump to when a signal is received. - pub user_handler: Option, + pub user_handler: NonZeroUsize, /// Offset to jump to when a program fault occurs. - pub excp_handler: Option, - /// Signal control page, required for signals to work. - pub control: Option, - /// Offset within the control page of a naturally aligned, semiatomically accessed, u128. - pub sigctl_off: u16, + pub excp_handler: NonZeroUsize, + + /// Signal control pages, shared memory + pub thread_control: RaiiFrame, + pub proc_control: RaiiFrame, + /// Offset within the control pages of respective word-aligned structs. + pub threadctl_off: u16, + pub procctl_off: u16, /// Set whenever the kernel is about to have the context jump to its signal trampoline, but the /// context is currently running. @@ -232,13 +231,7 @@ impl Context { euid: 0, egid: 0, ens: SchemeNamespace::from(0), - sig: SignalState { - user_handler: None, - excp_handler: None, - control: None, - sigctl_off: 0, - is_pending: false, - }, + sig: None, umask: 0o022, status: Status::HardBlocked { reason: HardBlockedReason::NotYetStarted }, status_reason: "", @@ -458,14 +451,26 @@ impl Context { }; Some(unsafe { &mut *kstack.initial_top().sub(size_of::()).cast() }) } - pub fn sigcontrol(&self) -> Option<&Sigcontrol> { - assert_eq!(usize::from(self.sig.sigctl_off) % mem::align_of::(), 0); - assert!(usize::from(self.sig.sigctl_off).saturating_add(mem::size_of::()) < PAGE_SIZE); + pub fn sigcontrol(&mut self) -> Option<(&Sigcontrol, &SigProcControl, &mut SignalState)> { + let sig = self.sig.as_mut()?; - Some(unsafe { - &*(RmmA::phys_to_virt(self.sig.control.as_ref()?.get().start_address()) - .data() as *const Sigcontrol).byte_add(usize::from(self.sig.sigctl_off)) - }) + let check = |off| { + assert_eq!(usize::from(off) % mem::align_of::(), 0); + assert!(usize::from(off).saturating_add(mem::size_of::()) < PAGE_SIZE); + }; + check(sig.procctl_off); + check(sig.threadctl_off); + + let for_thread = unsafe { + &*(RmmA::phys_to_virt(sig.thread_control.get().start_address()) + .data() as *const Sigcontrol).byte_add(usize::from(sig.threadctl_off)) + }; + let for_proc = unsafe { + &*(RmmA::phys_to_virt(sig.proc_control.get().start_address()) + .data() as *const SigProcControl).byte_add(usize::from(sig.procctl_off)) + }; + + Some((for_thread, for_proc, sig)) } } diff --git a/src/context/signal.rs b/src/context/signal.rs index c3e7c7a671..ddda03db5f 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -3,9 +3,9 @@ use core::mem::size_of; use syscall::{ flag::{ PTRACE_FLAG_IGNORE, PTRACE_STOP_SIGNAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, - SIGTTIN, SIGTTOU, SIG_DFL, SIG_IGN, + SIGTTIN, SIGTTOU, SIGTERM, }, - ptrace_event, SigActionFlags, IntRegisters, SIGTERM, + ptrace_event, IntRegisters, }; use crate::{ diff --git a/src/context/switch.rs b/src/context/switch.rs index f94c92b8d1..a216153cc0 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -50,7 +50,7 @@ unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> Update // Switch to context if it needs to run if context.status.is_runnable() { - UpdateResult::CanSwitch { signal: mem::take(&mut context.sig.is_pending) } + UpdateResult::CanSwitch { signal: context.sig.as_mut().map_or(false, |s| mem::take(&mut s.is_pending)) } } else { UpdateResult::Skip } diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index af1bde3183..1aee14c0d7 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -8,7 +8,7 @@ use crate::{ scheme::{self, FileHandle, KernelScheme}, syscall::{ self, - data::{GrantDesc, Map, PtraceEvent, SetSighandlerData, SigAction, Stat}, + data::{GrantDesc, Map, PtraceEvent, SetSighandlerData, Stat}, error::*, flag::*, usercopy::{UserSliceRo, UserSliceWo}, @@ -23,6 +23,7 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; +use ::syscall::{SigProcControl, Sigcontrol}; use core::{ mem, num::NonZeroUsize, @@ -1133,28 +1134,38 @@ impl KernelScheme for ProcScheme { return Err(Error::new(EPERM)); } - let (control, sigctl_off) = if data.word_addr != 0 { - let offset = u16::try_from(data.word_addr % PAGE_SIZE).unwrap(); + let state = if data.thread_control_addr != 0 && data.proc_control_addr != 0 { + let offset = u16::try_from(data.thread_control_addr % PAGE_SIZE).unwrap(); - if offset % 16 != 0 { - return Err(Error::new(EINVAL)); - } + let validate_off = |addr, sz| { + let off = addr % PAGE_SIZE; + if off % mem::align_of::() == 0 && off + sz <= PAGE_SIZE { + Ok(off as u16) + } else { + Err(Error::new(EINVAL)) + } + }; - let frame = AddrSpace::current()? - .borrow_frame_enforce_rw_allocated(Page::containing_address(VirtualAddress::new(data.word_addr)))?; + let addrsp = AddrSpace::current()?; - (Some(frame), offset) + + Some(SignalState { + threadctl_off: validate_off(data.thread_control_addr, mem::size_of::())?, + procctl_off: validate_off(data.proc_control_addr, mem::size_of::())?, + user_handler: NonZeroUsize::new(data.user_handler).ok_or(Error::new(EINVAL))?, + excp_handler: NonZeroUsize::new(data.excp_handler).ok_or(Error::new(EINVAL))?, + thread_control: addrsp + .borrow_frame_enforce_rw_allocated(Page::containing_address(VirtualAddress::new(data.thread_control_addr)))?, + proc_control: addrsp + .borrow_frame_enforce_rw_allocated(Page::containing_address(VirtualAddress::new(data.proc_control_addr)))?, + is_pending: false, + }) } else { - (None, 0) + None }; - context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig = SignalState { - user_handler: NonZeroUsize::new(data.user_handler), - excp_handler: NonZeroUsize::new(data.excp_handler), - control, - sigctl_off, - is_pending: false, - }; + + context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig = state; Ok(mem::size_of::()) } diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index 29c4fb3751..8080b192dc 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -15,7 +15,7 @@ pub use self::{ }; use self::{ - data::{Map, SigAction, TimeSpec}, + data::{Map, TimeSpec}, error::{Error, Result, EINTR, EOVERFLOW, ENOSYS}, flag::{EventFlags, MapFlags, WaitFlags}, number::*, diff --git a/src/syscall/process.rs b/src/syscall/process.rs index a1aba9769d..0a18dee279 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -1,5 +1,6 @@ use alloc::{sync::Arc, vec::Vec}; -use core::{mem, num::NonZeroUsize}; +use syscall::{sig_bit, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU}; +use core::{mem, num::NonZeroUsize, sync::atomic::Ordering}; use rmm::Arch; use spin::RwLock; @@ -14,11 +15,10 @@ use crate::{ paging::{Page, VirtualAddress, PAGE_SIZE}, ptrace, syscall::{ - data::SigAction, error::*, flag::{ - wifcontinued, wifstopped, MapFlags, WaitFlags, PTRACE_STOP_EXIT, SIGCONT, - SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK, WCONTINUED, WNOHANG, WUNTRACED, + wifcontinued, wifstopped, MapFlags, WaitFlags, PTRACE_STOP_EXIT, SIGCONT, WCONTINUED, + WNOHANG, WUNTRACED, }, ptrace_event, }, @@ -140,9 +140,11 @@ pub fn kill(pid: ContextId, sig: usize) -> Result { (context.ruid, context.euid, context.pgid) }; - if sig >= 0x3F { + if sig > 0x3F { return Err(Error::new(EINVAL)); } + let sig_group = sig / 32; + let mut found = 0; let mut sent = 0; @@ -154,19 +156,32 @@ pub fn kill(pid: ContextId, sig: usize) -> Result { if euid != 0 && euid != context.ruid && ruid != context.ruid { return false; } - // If sig = 0, test that process exists and can be - // signalled, but don't send any signal. + // If sig = 0, test that process exists and can be signalled, but don't send any + // signal. if sig == 0 { return true; } - todo!(); - // Convert stopped processes to blocked if sending SIGCONT - if sig == SIGCONT { - if let context::Status::Stopped(_sig) = context.status { - context.status = context::Status::Blocked; + if sig == SIGCONT && let context::Status::Stopped(_sig) = context.status { + context.status = context::Status::Blocked; + if let Some((ctl, _, _)) = context.sigcontrol() { + ctl.word[0].fetch_and(!(sig_bit(SIGTTIN) | sig_bit(SIGTTOU) | sig_bit(SIGTSTP)), Ordering::Relaxed); } + } else if sig == SIGSTOP || (matches!(sig, SIGTTIN | SIGTTOU | SIGTSTP) && context.sigcontrol().map_or(false, |(_, proc, _)| proc.signal_will_stop(sig))) { + context.status = context::Status::Stopped(sig); + if let Some((ctl, _, _)) = context.sigcontrol() { + ctl.word[0].fetch_and(!sig_bit(SIGCONT), Ordering::Relaxed); + } + } else if sig == SIGKILL { + context.being_sigkilled = true; + } else if let Some((ctl, _, st)) = context.sigcontrol() { + let was_new = ctl.word[sig_group].fetch_or(sig_bit(sig), Ordering::Relaxed); + if (ctl.word[sig_group].load(Ordering::Relaxed) >> 32) & sig_bit(sig) != 0 { + st.is_pending = true; + } + } else { + context.being_sigkilled = true; } true diff --git a/syscall b/syscall index a4e7729934..5b07568677 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit a4e7729934590a1c6da6449c9f06232dc64557c7 +Subproject commit 5b075686774ef88374d93834c54e339d456a8ec2