mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2026-02-05 20:11:47 -05:00
This commit refactors the signal handling subsystem to address a bug in process creation and to improve the separation of concerns between signal delivery and signal disposition. 1. Fix Action Table Sharing: Previously, the signal action table was wrapped in an `Arc`, causing forked child processes to inadvertently share signal dispositions with the parent. `SignalActionState` now contains a direct `SigActionSet` and implements Clone, ensuring that processes receive a private copy of the action table upon fork/clone. 2. Decouple Signal Selection from Execution: The logic for selecting a pending signal has been moved from the disposition state into a new `take_signal` method on `OwnedTask`. This decouples the "taking" of a signal (respecting masks and priorities) from the "actioning" of that signal. This is a prerequisite for implementing ptrace. 3. Various cleanup bits: - Renamed `SignalState` to `SignalActionState` to more accurately reflect that it manages signal dispositions. - Removed the `pending` signal set out of the action state and directly into the `ThreadGroup` and `OwnedTask`. - Renamed `set_pending` to `set_signal` for consistency. - Simplified the signal delivery loop in `dispatch_userspace_task` using the new `take_signal` API.
145 lines
4.6 KiB
Rust
145 lines
4.6 KiB
Rust
use core::ops::Deref;
|
|
|
|
use super::{
|
|
Comm, Task, TaskState, Tid,
|
|
creds::Credentials,
|
|
ctx::{Context, UserCtx},
|
|
fd_table::FileDescriptorTable,
|
|
thread_group::{
|
|
Tgid,
|
|
builder::ThreadGroupBuilder,
|
|
signal::{SigId, SigSet, SignalActionState},
|
|
},
|
|
threading::RobustListHead,
|
|
};
|
|
use crate::{
|
|
arch::{Arch, ArchImpl},
|
|
fs::DummyInode,
|
|
kernel::cpu_id::CpuId,
|
|
sync::SpinLock,
|
|
};
|
|
use alloc::sync::Arc;
|
|
use libkernel::{
|
|
VirtualMemory,
|
|
fs::pathbuf::PathBuf,
|
|
memory::{
|
|
address::{TUA, VA},
|
|
proc_vm::{ProcessVM, vmarea::VMArea},
|
|
},
|
|
};
|
|
|
|
/// Task state which is exclusively owned by this CPU/runqueue, it is not shared
|
|
/// between other tasks and can therefore be access lock-free.
|
|
pub struct OwnedTask {
|
|
pub ctx: Context,
|
|
pub sig_mask: SigSet,
|
|
pub pending_signals: SigSet,
|
|
pub priority: Option<i8>,
|
|
pub robust_list: Option<TUA<RobustListHead>>,
|
|
pub child_tid_ptr: Option<TUA<u32>>,
|
|
pub t_shared: Arc<Task>,
|
|
}
|
|
|
|
unsafe impl Send for OwnedTask {}
|
|
unsafe impl Sync for OwnedTask {}
|
|
|
|
impl Deref for OwnedTask {
|
|
type Target = Task;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.t_shared
|
|
}
|
|
}
|
|
|
|
impl OwnedTask {
|
|
pub fn create_idle_task(
|
|
addr_space: <ArchImpl as VirtualMemory>::ProcessAddressSpace,
|
|
user_ctx: UserCtx,
|
|
code_map: VMArea,
|
|
) -> Self {
|
|
// SAFETY: The code page will have been mapped corresponding to the VMA.
|
|
let vm = unsafe { ProcessVM::from_vma_and_address_space(code_map, addr_space) };
|
|
|
|
let thread_group_builder = ThreadGroupBuilder::new(Tgid::idle())
|
|
.with_priority(i8::MIN)
|
|
.with_sigstate(Arc::new(SpinLock::new(SignalActionState::new_ignore())));
|
|
|
|
let task = Task {
|
|
tid: Tid::idle_for_cpu(),
|
|
comm: Arc::new(SpinLock::new(Comm::new("idle"))),
|
|
process: thread_group_builder.build(),
|
|
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
|
cwd: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
|
|
root: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
|
|
creds: SpinLock::new(Credentials::new_root()),
|
|
vm: Arc::new(SpinLock::new(vm)),
|
|
fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())),
|
|
last_cpu: SpinLock::new(CpuId::this()),
|
|
};
|
|
|
|
Self {
|
|
priority: Some(i8::MIN),
|
|
ctx: Context::from_user_ctx(user_ctx),
|
|
sig_mask: SigSet::empty(),
|
|
pending_signals: SigSet::empty(),
|
|
robust_list: None,
|
|
child_tid_ptr: None,
|
|
t_shared: Arc::new(task),
|
|
}
|
|
}
|
|
|
|
pub fn create_init_task() -> Self {
|
|
let task = Task {
|
|
tid: Tid(1),
|
|
comm: Arc::new(SpinLock::new(Comm::new("init"))),
|
|
process: ThreadGroupBuilder::new(Tgid::init()).build(),
|
|
state: Arc::new(SpinLock::new(TaskState::Runnable)),
|
|
cwd: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
|
|
root: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
|
|
creds: SpinLock::new(Credentials::new_root()),
|
|
vm: Arc::new(SpinLock::new(
|
|
ProcessVM::empty().expect("Could not create init process's VM"),
|
|
)),
|
|
fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())),
|
|
last_cpu: SpinLock::new(CpuId::this()),
|
|
};
|
|
|
|
Self {
|
|
pending_signals: SigSet::empty(),
|
|
sig_mask: SigSet::empty(),
|
|
priority: None,
|
|
ctx: Context::from_user_ctx(<ArchImpl as Arch>::new_user_context(
|
|
VA::null(),
|
|
VA::null(),
|
|
)),
|
|
robust_list: None,
|
|
child_tid_ptr: None,
|
|
t_shared: Arc::new(task),
|
|
}
|
|
}
|
|
|
|
pub fn priority(&self) -> i8 {
|
|
self.priority
|
|
.unwrap_or_else(|| *self.process.priority.lock_save_irq())
|
|
}
|
|
|
|
pub fn set_priority(&mut self, priority: i8) {
|
|
self.priority = Some(priority);
|
|
}
|
|
|
|
pub fn raise_task_signal(&mut self, signal: SigId) {
|
|
self.pending_signals.insert(signal.into());
|
|
}
|
|
|
|
/// Take a pending signal from this task's pending signal queue, or the
|
|
/// process's pending signal queue, while repsecting the signal mask.
|
|
pub fn take_signal(&mut self) -> Option<SigId> {
|
|
self.pending_signals.take_signal(self.sig_mask).or_else(|| {
|
|
self.process
|
|
.pending_signals
|
|
.lock_save_irq()
|
|
.take_signal(self.sig_mask)
|
|
})
|
|
}
|
|
}
|