Files
moss-kernel/src/process/thread_group/builder.rs
Matthew Leach 1d79d6b2df process: refactor signal handling and fix action table sharing
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.
2026-01-09 06:49:48 +00:00

96 lines
3.1 KiB
Rust

use core::sync::atomic::{AtomicU32, AtomicU64};
use alloc::{collections::btree_map::BTreeMap, sync::Arc};
use crate::sync::SpinLock;
use super::{
Pgid, ProcessState, Sid, TG_LIST, Tgid, ThreadGroup,
rsrc_lim::ResourceLimits,
signal::{SigSet, SignalActionState},
wait::ChildNotifiers,
};
/// A builder for creating ThreadGroup instances.
pub struct ThreadGroupBuilder {
tgid: Tgid,
parent: Option<Arc<ThreadGroup>>,
umask: Option<u32>,
pri: Option<i8>,
sigstate: Option<Arc<SpinLock<SignalActionState>>>,
rsrc_lim: Option<Arc<SpinLock<ResourceLimits>>>,
}
impl ThreadGroupBuilder {
/// Creates a new ThreadGroupBuilder with the mandatory thread group ID.
pub fn new(tgid: Tgid) -> Self {
ThreadGroupBuilder {
tgid,
parent: None,
umask: None,
sigstate: None,
rsrc_lim: None,
pri: None,
}
}
/// Sets the parent of the thread group.
pub fn with_parent(mut self, parent: Arc<ThreadGroup>) -> Self {
self.parent = Some(parent);
self
}
/// Sets the signal state of the thread group.
pub fn with_sigstate(mut self, sigstate: Arc<SpinLock<SignalActionState>>) -> Self {
self.sigstate = Some(sigstate);
self
}
pub fn with_rsrc_lim(mut self, rsrc_lim: Arc<SpinLock<ResourceLimits>>) -> Self {
self.rsrc_lim = Some(rsrc_lim);
self
}
pub fn with_priority(mut self, priority: i8) -> Self {
self.pri = Some(priority);
self
}
/// Builds the ThreadGroup.
///
/// If a sigstate has not been provided, a default one will be created.
pub fn build(self) -> Arc<ThreadGroup> {
let ret = Arc::new(ThreadGroup {
tgid: self.tgid,
pgid: SpinLock::new(Pgid(self.tgid.value())),
sid: SpinLock::new(Sid(self.tgid.value())),
parent: SpinLock::new(self.parent.as_ref().map(Arc::downgrade)),
umask: SpinLock::new(self.umask.unwrap_or(0)),
children: SpinLock::new(BTreeMap::new()),
signals: self
.sigstate
.unwrap_or_else(|| Arc::new(SpinLock::new(SignalActionState::new_default()))),
rsrc_lim: self
.rsrc_lim
.unwrap_or_else(|| Arc::new(SpinLock::new(ResourceLimits::default()))),
pending_signals: SpinLock::new(SigSet::empty()),
child_notifiers: ChildNotifiers::new(),
priority: SpinLock::new(self.pri.unwrap_or(0)),
utime: AtomicU64::new(0),
stime: AtomicU64::new(0),
// Don't start from '0'. Since clone expects the parent to return
// the tid and the child to return '0', if we started from '0' we
// couldn't then differentiate between a child and a parent.
next_tid: AtomicU32::new(1),
state: SpinLock::new(ProcessState::Running),
tasks: SpinLock::new(BTreeMap::new()),
});
TG_LIST
.lock_save_irq()
.insert(self.tgid, Arc::downgrade(&ret));
ret
}
}