Skip to content

Commit

Permalink
refactor: process groups (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
llenotre committed Nov 11, 2024
1 parent 42b7686 commit db0d084
Show file tree
Hide file tree
Showing 14 changed files with 64 additions and 81 deletions.
2 changes: 1 addition & 1 deletion kernel/src/device/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl TTYDeviceHandle {
/// This function must be called before performing the read operation.
fn check_sigttin(&self, tty: &TTYDisplay) -> EResult<()> {
let proc = Process::current();
if proc.pgid == tty.get_pgrp() {
if proc.get_pgid() == tty.get_pgrp() {
return Ok(());
}
// Hold the signal handlers table to avoid a race condition
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/file/fs/proc/proc_dir/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ TODO TODO TODO TODO TODO TODO TODO TODO TODO",
name = DisplayableStr(name),
state_char = self.0.get_state().as_char(),
ppid = self.0.get_parent_pid(),
pgid = self.0.pgid,
pgid = self.0.get_pgid(),
sid = 0, // TODO
user_jiffies = 0, // TODO
kernel_jiffies = 0, // TODO
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/file/fs/proc/proc_dir/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Mems_allowed_list: 0
voluntary_ctxt_switches: 0
nonvoluntary_ctxt_switches: 0",
name = DisplayableStr(name),
umask = self.0.umask,
umask = self.0.umask(),
state_char = state.as_char(),
state_name = state.as_str(),
pid = self.0.get_pid(),
Expand Down
100 changes: 41 additions & 59 deletions kernel/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
//! several processes to run at the same time by sharing the CPU resources using
//! a scheduler.

// TODO Do not reallocate a PID of used as a pgid
// TODO When a process receives a signal or exits, log it if the `strace` feature is enabled

pub mod exec;
pub mod iovec;
pub mod mem_space;
Expand All @@ -51,6 +48,7 @@ use crate::{
process::{
mem_space::{copy, copy::SyscallPtr},
pid::PidHandle,
rusage::RUsage,
scheduler::{Scheduler, SCHEDULER},
signal::SigSet,
},
Expand All @@ -67,12 +65,11 @@ use core::{
ptr::{null_mut, NonNull},
sync::{
atomic,
atomic::{AtomicPtr, AtomicU8},
atomic::{AtomicPtr, AtomicU32, AtomicU8},
},
};
use mem_space::MemSpace;
use pid::Pid;
use rusage::RUsage;
use signal::{Signal, SignalAction, SignalHandler};
use utils::{
collections::{
Expand Down Expand Up @@ -221,8 +218,6 @@ enum VForkState {
pub struct Process {
/// The ID of the process.
pid: PidHandle,
/// The ID of the process group.
pub pgid: Pid,
/// The thread ID of the process.
pub tid: Pid,

Expand All @@ -236,7 +231,7 @@ pub struct Process {
/// The process's access profile, containing user and group IDs.
pub access_profile: AccessProfile,
/// The process's current umask.
pub umask: file::Mode,
pub umask: AtomicU32,

/// The current state of the process.
state: AtomicU8,
Expand All @@ -253,6 +248,10 @@ pub struct Process {
parent: Option<Arc<Process>>,
/// The list of children processes.
children: Vec<Pid>,
/// The process's group leader. The PID of the group leader is the PGID of this process.
///
/// If `None`, the process is its own leader (to avoid self reference).
group_leader: Option<Arc<Process>>,
/// The list of processes in the process group.
process_group: Vec<Pid>,

Expand Down Expand Up @@ -288,7 +287,7 @@ pub struct Process {
pub tls_entries: [gdt::Entry; TLS_ENTRIES_COUNT],

/// The process's resources usage.
rusage: RUsage,
pub rusage: RUsage,

/// The exit status of the process after exiting.
exit_status: ExitStatus,
Expand Down Expand Up @@ -434,15 +433,14 @@ impl Process {
let pid = PidHandle::init()?;
let process = Self {
pid,
pgid: pid::INIT_PID,
tid: pid::INIT_PID,

argv: Arc::new(Vec::new())?,
envp: Arc::new(String::new())?,
exec_path: Arc::new(PathBuf::root()?)?,

access_profile: rs.access_profile,
umask: DEFAULT_UMASK,
umask: AtomicU32::new(DEFAULT_UMASK),

state: AtomicU8::new(State::Running as _),
vfork_state: VForkState::None,
Expand All @@ -452,6 +450,7 @@ impl Process {

parent: None,
children: Vec::new(),
group_leader: None,
process_group: Vec::new(),

timer_manager: Arc::new(Mutex::new(TimerManager::new(pid::INIT_PID)?))?,
Expand Down Expand Up @@ -491,42 +490,23 @@ impl Process {
self.pid.get() == pid::INIT_PID
}

/// Tells whether the process is among a group and is not its owner.
#[inline(always)]
pub fn is_in_group(&self) -> bool {
self.pgid != 0 && self.pgid != self.pid.get()
/// Returns the process group ID.
pub fn get_pgid(&self) -> Pid {
self.group_leader
.as_ref()
.map(|p| p.get_pid())
.unwrap_or(self.get_pid())
}

/// Sets the process's group ID to the given value `pgid`, updating the associated group.
pub fn set_pgid(&self, pgid: Pid) -> EResult<()> {
let old_pgid = self.pgid;
let new_pgid = if pgid == 0 { self.pid.get() } else { pgid };
if old_pgid == new_pgid {
return Ok(());
}
if new_pgid != self.pid.get() {
// Add the process to the new group
let Some(new_group_process) = Process::get_by_pid(new_pgid) else {
return Err(errno!(ESRCH));
};
let i = new_group_process
.process_group
.binary_search(&self.pid.get())
.unwrap_err();
new_group_process.process_group.insert(i, self.pid.get())?;
}
// Remove the process from its former group
if self.is_in_group() {
if let Some(old_group_process) = Process::get_by_pid(old_pgid) {
if let Ok(i) = old_group_process
.process_group
.binary_search(&self.pid.get())
{
old_group_process.process_group.remove(i);
}
}
}
self.pgid = new_pgid;
let new_group_leader = (pgid != 0 && pgid != self.get_pid())
.then(|| Process::get_by_pid(pgid).ok_or_else(|| errno!(ESRCH)))
.transpose()?;
// TODO use an atomic swap to get the former group
self.group_leader = new_group_leader;
// TODO remove process from the old group's list
// TODO add process to the new group's list
Ok(())
}

Expand All @@ -538,10 +518,10 @@ impl Process {

/// The function tells whether the process is in an orphaned process group.
pub fn is_in_orphan_process_group(&self) -> bool {
if !self.is_in_group() {
return false;
}
Process::get_by_pid(self.pgid).is_none()
self.group_leader
.as_ref()
.map(|group_leader| group_leader.get_state() == State::Zombie)
.unwrap_or(false)
}

/// Returns the parent process's PID.
Expand All @@ -552,6 +532,11 @@ impl Process {
.unwrap_or(self.get_pid())
}

/// Returns the process's umask.
pub fn umask(&self) -> file::Mode {
self.umask.load(atomic::Ordering::Relaxed)
}

/// Returns the process's current state.
///
/// **Note**: since the process cannot be locked, this function may cause data races. Use with
Expand Down Expand Up @@ -678,13 +663,17 @@ impl Process {
}
}

/// Returns the exit status if the process has ended.
/// Returns the exit status.
///
/// If the process is still running, the value is undefined.
#[inline(always)]
pub fn get_exit_status(&self) -> Option<ExitStatus> {
matches!(self.state, State::Zombie).then_some(self.exit_status)
pub fn get_exit_status(&self) -> ExitStatus {
self.exit_status
}

/// Returns the signal number that killed the process.
///
/// If the process was not killed, the value is undefined.
#[inline(always)]
pub fn get_termsig(&self) -> u8 {
self.termsig
Expand Down Expand Up @@ -741,17 +730,16 @@ impl Process {
let pid_int = pid.get();
let process = Self {
pid,
pgid: this.pgid,
tid: pid_int,

argv: this.argv.clone(),
envp: this.envp.clone(),
exec_path: this.exec_path.clone(),

access_profile: this.access_profile,
umask: this.umask,
umask: this.umask.load(atomic::Ordering::Release),

state: State::Running,
state: AtomicU8::new(State::Running as _),
vfork_state,

priority: this.priority,
Expand Down Expand Up @@ -875,12 +863,6 @@ impl Process {
}
}

/// Returns an immutable reference to the process's resource usage
/// structure.
pub fn get_rusage(&self) -> &RUsage {
&self.rusage
}

/// If the process is a vfork child, resets its state and its parent's
/// state.
pub fn reset_vfork(&self) {
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/process/rusage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

use crate::time::unit::Timeval;

// TODO support 64 bit

/// Usage of each resource by a process.
#[derive(Clone, Default, Debug)]
pub struct RUsage {
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/syscall/getpgid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ use utils::{
pub fn getpgid(Args(pid): Args<Pid>) -> EResult<usize> {
if pid == 0 {
let proc = Process::current();
Ok(proc.pgid as _)
Ok(proc.get_pgid() as _)
} else {
let Some(proc) = Process::get_by_pid(pid) else {
return Err(errno!(ESRCH));
};
Ok(proc.pgid as _)
Ok(proc.get_pgid() as _)
}
}
2 changes: 1 addition & 1 deletion kernel/src/syscall/getrusage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const RUSAGE_CHILDREN: i32 = -1;

pub fn getrusage(Args((who, usage)): Args<(c_int, SyscallPtr<RUsage>)>) -> EResult<usize> {
let rusage = match who {
RUSAGE_SELF => Process::current().get_rusage().clone(),
RUSAGE_SELF => Process::current().rusage.clone(),
RUSAGE_CHILDREN => {
// TODO Return resources of terminated children
RUsage::default()
Expand Down
5 changes: 1 addition & 4 deletions kernel/src/syscall/kill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,7 @@ fn try_kill(pid: Pid, sig: Option<Signal>) -> EResult<()> {
/// there is a process that could be killed.
fn try_kill_group(pid: i32, sig: Option<Signal>) -> EResult<()> {
let pgid = match pid {
0 => {
let proc = Process::current();
proc.pgid
}
0 => Process::current().get_pgid(),
i if i < 0 => -pid as Pid,
_ => pid as Pid,
};
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ pub struct Umask(file::Mode);

impl FromSyscall for Umask {
fn from_syscall(_frame: &IntFrame) -> Self {
Self(Process::current().umask)
Self(Process::current().umask())
}
}

Expand Down
2 changes: 1 addition & 1 deletion kernel/src/syscall/openat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub fn do_openat(
.map(PathBuf::try_from)
.ok_or_else(|| errno!(EFAULT))??;
let fds_mutex = proc.file_descriptors.clone().unwrap();
let mode = mode & !proc.umask;
let mode = mode & !proc.umask();
(rs, pathname, fds_mutex, mode)
};

Expand Down
4 changes: 2 additions & 2 deletions kernel/src/syscall/umask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
//! The `umask` syscall is used to set the process's file creation mask.

use crate::{file, process::Process, syscall::Args};
use core::mem;
use core::{mem, sync::atomic};
use utils::{
errno::{EResult, Errno},
lock::{IntMutex, IntMutexGuard},
ptr::arc::Arc,
};

pub fn umask(Args(mask): Args<file::Mode>, proc: Arc<Process>) -> EResult<usize> {
let prev = mem::replace(&mut proc.umask, mask & 0o777);
let prev = proc.umask.swap(mask & 0o777, atomic::Ordering::Relaxed);
Ok(prev as _)
}
6 changes: 3 additions & 3 deletions kernel/src/syscall/waitpid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn iter_targets(curr_proc: &Process, pid: i32) -> impl Iterator<Item = Pid> + '_

/// Returns the wait status for the given process.
fn get_wstatus(proc: &Process) -> i32 {
let status = proc.get_exit_status().unwrap_or(0);
let status = proc.get_exit_status();
let termsig = proc.get_termsig();
#[allow(clippy::let_and_return)]
let wstatus = match proc.get_state() {
Expand Down Expand Up @@ -128,7 +128,7 @@ fn get_waitable(
let pid = proc.get_pid();
// Write values back
wstatus.copy_to_user(get_wstatus(&proc))?;
rusage.copy_to_user(proc.get_rusage().clone())?;
rusage.copy_to_user(proc.rusage.clone())?;
// Clear the waitable flag if requested
if options & WNOWAIT == 0 {
proc.clear_waitable();
Expand Down Expand Up @@ -156,7 +156,7 @@ pub fn do_waitpid(
if proc.next_signal(true).is_some() {
return Err(errno!(EINTR));
}
let result = get_waitable(&mut proc, pid, &wstatus, options, &rusage)?;
let result = get_waitable(&proc, pid, &wstatus, options, &rusage)?;
// On success, return
if let Some(p) = result {
return Ok(p as _);
Expand Down
8 changes: 5 additions & 3 deletions kernel/src/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ use core::mem::ManuallyDrop;
use unit::{Timestamp, TimestampScale};
use utils::{boxed::Box, errno::EResult, math::rational::Rational};

/// Timer frequency.
const FREQUENCY: Rational = Rational::from_frac(1, 1024);

/// Initializes time management.
pub(crate) fn init() -> EResult<()> {
// Initialize hardware clocks
Expand All @@ -44,12 +47,11 @@ pub(crate) fn init() -> EResult<()> {
// TODO implement APIC timer
// Link hardware clock to software clock
let rtc = hw_clocks.get_mut(b"rtc".as_slice()).unwrap();
let freq = Rational::from_frac(1, 1024);
rtc.set_frequency(freq);
rtc.set_frequency(FREQUENCY);
let hook = event::register_callback(rtc.get_interrupt_vector(), move |_, _, _, _| {
hw::rtc::RTC::reset();
// FIXME: the value is probably not right
clock::update(i64::from(freq * 1_000_000_000) as _);
clock::update(i64::from(FREQUENCY * 1_000_000_000) as _);
timer::tick();
CallbackResult::Continue
})?;
Expand Down
Loading

0 comments on commit db0d084

Please sign in to comment.