mod allocation;
mod bounded_stack;
mod cgroup_exit_invariant;
mod cred;
pub mod futex;
pub mod future;
mod interruption;
mod job_control;
mod ops;
mod pid;
pub mod posix_timer;
mod process;
mod process_accounting;
mod process_cgroup;
mod process_identity;
mod process_image;
mod process_memory;
mod process_policy;
mod process_ptrace;
mod process_wait;
mod resources;
mod scheduler_identity;
mod scheduler_task;
mod seccomp;
mod signal;
mod signal_publication;
mod stat;
mod thread;
mod timer;
#[cfg(target_arch = "loongarch64")]
mod unaligned;
mod user;
#[cfg(target_arch = "aarch64")]
mod user_cpu_features;
mod user_memory_access;
mod user_wait;
use alloc::sync::Arc;
pub(crate) use process_ptrace::{PtraceAttachMode, PtraceWaitAction, PtraceWaitStop};
pub use process_ptrace::{PtraceStopFpData, SyscallTraceState};
use starry_signal::{
Signo,
api::{ProcessSignalManager, SignalActions},
};
pub use self::{
cred::*, futex::*, job_control::JobStatus, ops::*, posix_timer::PosixTimerTable, process::*,
process_image::ProcessImage, process_wait::wait_on_pollset, resources::*, scheduler_task::*,
seccomp::*, signal::*, stat::*, thread::Thread, timer::*, user::*,
};
use self::{
job_control::ProcessJobControl, process_accounting::ProcessAccountingState,
process_cgroup::ProcessCgroupState, process_image::ProcessImageState,
process_memory::ProcessMemoryState, process_policy::ProcessPolicyState,
process_ptrace::ProcessPtraceState, process_wait::ProcessWaitState,
};
pub(crate) use self::{
pid::*,
process_identity::*,
process_memory::{PreparedProcessMemory, scheduler_address_space},
};
use crate::{
mm::MmHandle,
namespace::NsProxy,
sync::{IrqMutex, Mutex, MutexGuard, RawSpinLock},
};
pub struct ProcessData {
tgid_lease: IrqMutex<Option<PidRoleLease<Tgid>>>,
pub proc: Arc<Process>,
identity: Arc<PidIdentity>,
image: ProcessImageState,
memory: ProcessMemoryState,
pub uprobe_manager: crate::kprobe::KprobeManager,
pub uprobe_point_list: Mutex<crate::kprobe::KprobePointList>,
pub(crate) nsproxy: IrqMutex<Arc<NsProxy>>,
namespace_update: Mutex<()>,
cgroup: ProcessCgroupState,
policy: ProcessPolicyState,
wait: ProcessWaitState,
pub signal: Arc<ProcessSignalManager>,
accounting: ProcessAccountingState,
ptrace: ProcessPtraceState,
job_control: ProcessJobControl,
}
pub struct ProcessDataInit {
image: ProcessImage,
aspace: MmHandle,
signal_actions: Arc<RawSpinLock<SignalActions>>,
nsproxy: NsProxy,
cgroup: Arc<ax_cgroup::CgroupNode>,
exit_signal: Option<Signo>,
wait_parent_tid: TidNumber,
shared_memory: Option<process_memory::ProcessMemoryShare>,
}
impl ProcessDataInit {
pub fn new(
image: ProcessImage,
aspace: MmHandle,
signal_actions: Arc<RawSpinLock<SignalActions>>,
nsproxy: NsProxy,
exit_signal: Option<Signo>,
wait_parent_tid: TidNumber,
) -> Self {
Self {
image,
aspace,
signal_actions,
nsproxy,
cgroup: crate::cgroup::root(),
exit_signal,
wait_parent_tid,
shared_memory: None,
}
}
pub(crate) fn with_shared_memory(mut self, parent: &ProcessData) -> Self {
self.shared_memory = Some(parent.memory_share());
self
}
pub fn with_cgroup(mut self, cgroup: Arc<ax_cgroup::CgroupNode>) -> Self {
self.cgroup = cgroup;
self
}
}
impl ProcessData {
pub fn new(
proc: Arc<Process>,
identity: Arc<PidIdentity>,
tgid_lease: PidRoleLease<Tgid>,
init: ProcessDataInit,
) -> Arc<Self> {
let ProcessDataInit {
image,
aspace,
signal_actions,
nsproxy,
cgroup,
exit_signal,
wait_parent_tid,
shared_memory,
} = init;
let wait = ProcessWaitState::new(exit_signal, wait_parent_tid);
let exit_event = wait.exit_event_arc();
let this = Arc::new(Self {
proc: proc.clone(),
identity: identity.clone(),
tgid_lease: IrqMutex::new(Some(tgid_lease)),
image: ProcessImageState::new(image),
memory: ProcessMemoryState::new(aspace, shared_memory),
wait,
uprobe_manager: crate::kprobe::KprobeManager::new(),
uprobe_point_list: Mutex::new(crate::kprobe::KprobePointList::new()),
policy: ProcessPolicyState::new(),
accounting: ProcessAccountingState::new(),
signal: Arc::new(ProcessSignalManager::new(
signal_actions,
crate::config::SIGNAL_TRAMPOLINE,
proc.group_exit_state(),
)),
nsproxy: IrqMutex::new(Arc::new(nsproxy)),
namespace_update: Mutex::new(()),
cgroup: ProcessCgroupState::new(&identity, cgroup),
ptrace: ProcessPtraceState::new(),
job_control: ProcessJobControl::new(),
});
identity.bind_process(proc, exit_event, Arc::downgrade(&this));
this
}
pub(crate) fn identity(&self) -> Arc<PidIdentity> {
self.identity.clone()
}
pub(crate) fn take_tgid_lease(&self) -> PidRoleLease<Tgid> {
self.tgid_lease
.lock()
.take()
.expect("process TGID lease transferred twice")
}
pub(crate) fn cgroup_node(&self) -> Arc<ax_cgroup::CgroupNode> {
self.cgroup.current()
}
pub(crate) fn migrate_cgroup(
&self,
target: Arc<ax_cgroup::CgroupNode>,
) -> ax_cgroup::CgroupResult<()> {
self.cgroup.migrate(target)
}
pub(crate) fn begin_cgroup_task(
&self,
child: ax_cgroup::ProcessId,
child_kind: ax_cgroup::CgroupChildKind,
) -> ax_cgroup::CgroupResult<ax_cgroup::CgroupForkGuard> {
self.cgroup.begin_task(child, child_kind)
}
pub(crate) fn finish_thread_exit(
&self,
task: ax_cgroup::ProcessId,
transition: impl FnOnce() -> ThreadExit,
) -> (ThreadExit, ax_cgroup::CgroupResult<()>) {
self.cgroup.finish_thread_exit(task, transition)
}
pub(crate) fn rename_cgroup_task(
&self,
old_task: ax_cgroup::ProcessId,
new_task: ax_cgroup::ProcessId,
) -> ax_cgroup::CgroupResult<()> {
self.cgroup.rename_task(old_task, new_task)
}
pub(crate) fn namespace_snapshot(&self) -> Arc<NsProxy> {
self.nsproxy.lock().clone()
}
pub(crate) fn namespace_update(&self) -> ProcessNamespaceUpdate<'_> {
ProcessNamespaceUpdate {
publication: &self.nsproxy,
_guard: self.namespace_update.lock(),
}
}
pub(crate) fn release_cgroup_namespace(&self) {
let update = self.namespace_update();
let mut replacement = update.snapshot().clone_for_unshare();
replacement.release_cgroup_namespace();
update.publish(replacement);
}
}
impl Drop for ProcessData {
fn drop(&mut self) {
self.retire_mm_owner();
}
}
pub(crate) struct ProcessNamespaceUpdate<'a> {
publication: &'a IrqMutex<Arc<NsProxy>>,
_guard: MutexGuard<'a, ()>,
}
impl ProcessNamespaceUpdate<'_> {
pub(crate) fn snapshot(&self) -> Arc<NsProxy> {
self.publication.lock().clone()
}
pub(crate) fn publish(self, replacement: NsProxy) {
let replacement = Arc::new(replacement);
let previous = {
let mut current = self.publication.lock();
core::mem::replace(&mut *current, replacement)
};
drop(self);
drop(previous);
}
}
#[cfg(axtest)]
pub(crate) fn new_test_process_data(
identity: Arc<PidIdentity>,
tgid: PidRoleLease<Tgid>,
) -> Arc<ProcessData> {
let parent = TidNumber::from(identity.root_number());
ProcessData::new(
Process::new_for_axtest(identity.clone()),
identity,
tgid,
ProcessDataInit::new(
ProcessImage::new(
Default::default(),
Arc::default(),
Arc::default(),
Default::default(),
Default::default(),
Default::default(),
),
MmHandle::from_arc(Arc::new(Mutex::new(
crate::mm::AddrSpace::new_empty(0x10000.into(), 0x10000).unwrap(),
)))
.unwrap(),
Arc::default(),
NsProxy::new_root(),
None,
parent,
),
)
}
#[cfg(all(test, not(axtest)))]
mod tests {
use super::ProcessData;
use crate::{namespace::NsProxy, sync::IrqMutex};
#[test]
fn namespace_publication_lock_only_contains_a_shared_snapshot() {
fn assert_snapshot_lock(_: &IrqMutex<alloc::sync::Arc<NsProxy>>) {}
fn assert_process_lock_type(process: &ProcessData) {
assert_snapshot_lock(&process.nsproxy);
}
let _ = assert_process_lock_type as fn(&ProcessData);
}
}