diff --git a/kernel/aster-nix/src/fs/procfs/mod.rs b/kernel/aster-nix/src/fs/procfs/mod.rs index ebf390494..e67233e28 100644 --- a/kernel/aster-nix/src/fs/procfs/mod.rs +++ b/kernel/aster-nix/src/fs/procfs/mod.rs @@ -96,7 +96,7 @@ impl DirOps for RootDirOps { SelfSymOps::new_inode(this_ptr.clone()) } else if let Ok(pid) = name.parse::() { let process_ref = - process_table::get_process(&pid).ok_or_else(|| Error::new(Errno::ENOENT))?; + process_table::get_process(pid).ok_or_else(|| Error::new(Errno::ENOENT))?; PidDirOps::new_inode(process_ref, this_ptr.clone()) } else { return_errno!(Errno::ENOENT); diff --git a/kernel/aster-nix/src/process/exit.rs b/kernel/aster-nix/src/process/exit.rs index 9caaa0786..e6a34530b 100644 --- a/kernel/aster-nix/src/process/exit.rs +++ b/kernel/aster-nix/src/process/exit.rs @@ -63,7 +63,7 @@ const INIT_PROCESS_PID: Pid = 1; /// Get the init process fn get_init_process() -> Option> { - process_table::get_process(&INIT_PROCESS_PID) + process_table::get_process(INIT_PROCESS_PID) } fn is_init_process(process: &Process) -> bool { diff --git a/kernel/aster-nix/src/process/kill.rs b/kernel/aster-nix/src/process/kill.rs index 6825fff73..2e54f7694 100644 --- a/kernel/aster-nix/src/process/kill.rs +++ b/kernel/aster-nix/src/process/kill.rs @@ -20,7 +20,7 @@ use crate::{ /// If `signal` is `None`, this method will only check permission without sending /// any signal. pub fn kill(pid: Pid, signal: Option) -> Result<()> { - let process = process_table::get_process(&pid) + let process = process_table::get_process(pid) .ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process does not exist"))?; kill_process(&process, signal) diff --git a/kernel/aster-nix/src/process/process_table.rs b/kernel/aster-nix/src/process/process_table.rs index a1c5c1656..364d4cc99 100644 --- a/kernel/aster-nix/src/process/process_table.rs +++ b/kernel/aster-nix/src/process/process_table.rs @@ -20,8 +20,8 @@ static SESSION_TABLE: Mutex>> = Mutex::new(BTreeMap:: // ************ Process ************* /// Gets a process with pid -pub fn get_process(pid: &Pid) -> Option> { - PROCESS_TABLE.lock().get(pid).cloned() +pub fn get_process(pid: Pid) -> Option> { + PROCESS_TABLE.lock().get(&pid).cloned() } pub(super) fn process_table_mut() -> MutexGuard<'static, BTreeMap>> { diff --git a/kernel/aster-nix/src/syscall/clock_gettime.rs b/kernel/aster-nix/src/syscall/clock_gettime.rs index 94d8816c3..6283fdf89 100644 --- a/kernel/aster-nix/src/syscall/clock_gettime.rs +++ b/kernel/aster-nix/src/syscall/clock_gettime.rs @@ -8,6 +8,8 @@ use int_to_c_enum::TryFromInt; use super::SyscallReturn; use crate::{ prelude::*, + process::{posix_thread::PosixThreadExt, process_table}, + thread::{thread_table, Thread}, time::{ clockid_t, clocks::{ @@ -20,10 +22,9 @@ use crate::{ }; pub fn sys_clock_gettime(clockid: clockid_t, timespec_addr: Vaddr) -> Result { - let clock_id = ClockID::try_from(clockid)?; - debug!("clockid = {:?}", clock_id); + debug!("clockid = {:?}", clockid); - let time_duration = read_clock(&clock_id)?; + let time_duration = read_clock(clockid)?; let timespec = timespec_t::from(time_duration); write_val_to_user(timespec_addr, ×pec)?; @@ -31,9 +32,10 @@ pub fn sys_clock_gettime(clockid: clockid_t, timespec_addr: Vaddr) -> Result Result { - match clock_id { - ClockID::CLOCK_REALTIME => Ok(RealTimeClock::get().read_time()), - ClockID::CLOCK_MONOTONIC => Ok(MonotonicClock::get().read_time()), - ClockID::CLOCK_MONOTONIC_RAW => Ok(MonotonicRawClock::get().read_time()), - ClockID::CLOCK_REALTIME_COARSE => Ok(RealTimeCoarseClock::get().read_time()), - ClockID::CLOCK_MONOTONIC_COARSE => Ok(MonotonicCoarseClock::get().read_time()), - ClockID::CLOCK_BOOTTIME => Ok(BootTimeClock::get().read_time()), - _ => { - return_errno_with_message!(Errno::EINVAL, "unsupported clock_id"); +/// Dynamic clocks are the clocks operates on certain +/// character devices, processes or threads. Their IDs will +/// be generated by encoding the file descriptor, PID or TID. +/// Here we follow the rules in Linux: +/// +/// The dynamic clock ID is a 32 bit integer. +/// - The most significant 29 bits hold either a PID or a file descriptor. +/// - Bit 2 indicates whether a cpu clock refers to a thread or a process. +/// - Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or FD=3. +/// - A clock ID is invalid if bits 2, 1, and 0 are all set. +/// +/// Ref: https://github.com/torvalds/linux/blob/master/include/linux/posix-timers_types.h +pub enum DynamicClockIdInfo { + Pid(u32, DynamicClockType), + Tid(u32, DynamicClockType), + Fd(u32), +} + +impl TryFrom for DynamicClockIdInfo { + type Error = crate::Error; + + fn try_from(value: clockid_t) -> core::prelude::v1::Result { + const CPU_CLOCK_TYPE_MASK: i32 = 0b11; + const ID_TYPE_MASK: i32 = 0b100; + const INVALID_MASK: i32 = CPU_CLOCK_TYPE_MASK | ID_TYPE_MASK; + + if (value & INVALID_MASK) == INVALID_MASK { + return_errno_with_message!(Errno::EINVAL, "invalid clock ID"); + } + + let id = !(value >> 3); + let cpu_clock_type = DynamicClockType::try_from(CPU_CLOCK_TYPE_MASK & value)?; + + if let DynamicClockType::FD = cpu_clock_type { + return Ok(DynamicClockIdInfo::Fd(id as u32)); + } + + if ID_TYPE_MASK & value > 0 { + Ok(DynamicClockIdInfo::Tid(id as u32, cpu_clock_type)) + } else { + Ok(DynamicClockIdInfo::Pid(id as u32, cpu_clock_type)) + } + } +} + +#[derive(Debug, Copy, Clone, TryFromInt, PartialEq)] +#[repr(i32)] +pub enum DynamicClockType { + Profiling = 0, + Virtual = 1, + Scheduling = 2, + FD = 3, +} + +/// Reads the time of a clock specified by the input clock ID. +/// +/// If the clock ID does not support, this function will return `Err`. +pub fn read_clock(clockid: clockid_t) -> Result { + if clockid >= 0 { + let clock_id = ClockId::try_from(clockid)?; + match clock_id { + ClockId::CLOCK_REALTIME => Ok(RealTimeClock::get().read_time()), + ClockId::CLOCK_MONOTONIC => Ok(MonotonicClock::get().read_time()), + ClockId::CLOCK_MONOTONIC_RAW => Ok(MonotonicRawClock::get().read_time()), + ClockId::CLOCK_REALTIME_COARSE => Ok(RealTimeCoarseClock::get().read_time()), + ClockId::CLOCK_MONOTONIC_COARSE => Ok(MonotonicCoarseClock::get().read_time()), + ClockId::CLOCK_BOOTTIME => Ok(BootTimeClock::get().read_time()), + ClockId::CLOCK_PROCESS_CPUTIME_ID => { + let process = current!(); + Ok(process.prof_clock().read_time()) + } + ClockId::CLOCK_THREAD_CPUTIME_ID => { + let thread = Thread::current(); + Ok(thread.as_posix_thread().unwrap().prof_clock().read_time()) + } + } + } else { + let dynamic_clockid_info = DynamicClockIdInfo::try_from(clockid)?; + match dynamic_clockid_info { + DynamicClockIdInfo::Pid(pid, clock_type) => { + let process = process_table::get_process(pid) + .ok_or_else(|| crate::Error::with_message(Errno::EINVAL, "invalid clock ID"))?; + match clock_type { + DynamicClockType::Profiling => Ok(process.prof_clock().read_time()), + DynamicClockType::Virtual => Ok(process.prof_clock().user_clock().read_time()), + // TODO: support scheduling clock and fd clock. + _ => unimplemented!(), + } + } + DynamicClockIdInfo::Tid(tid, clock_type) => { + let thread = thread_table::get_thread(tid) + .ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid clock ID"))?; + let posix_thread = thread.as_posix_thread().unwrap(); + match clock_type { + DynamicClockType::Profiling => Ok(posix_thread.prof_clock().read_time()), + DynamicClockType::Virtual => { + Ok(posix_thread.prof_clock().user_clock().read_time()) + } + _ => unimplemented!(), + } + } + DynamicClockIdInfo::Fd(_) => unimplemented!(), } } } diff --git a/kernel/aster-nix/src/syscall/getsid.rs b/kernel/aster-nix/src/syscall/getsid.rs index a7e7e22a5..b0df8a366 100644 --- a/kernel/aster-nix/src/syscall/getsid.rs +++ b/kernel/aster-nix/src/syscall/getsid.rs @@ -16,7 +16,7 @@ pub fn sys_getsid(pid: Pid) -> Result { return Ok(SyscallReturn::Return(sid as _)); } - let Some(process) = process_table::get_process(&pid) else { + let Some(process) = process_table::get_process(pid) else { return_errno_with_message!(Errno::ESRCH, "the process does not exist") }; diff --git a/kernel/aster-nix/src/syscall/nanosleep.rs b/kernel/aster-nix/src/syscall/nanosleep.rs index 91def9a41..bd74f8dfe 100644 --- a/kernel/aster-nix/src/syscall/nanosleep.rs +++ b/kernel/aster-nix/src/syscall/nanosleep.rs @@ -2,7 +2,7 @@ use core::time::Duration; -use super::{clock_gettime::read_clock, ClockID, SyscallReturn}; +use super::{clock_gettime::read_clock, ClockId, SyscallReturn}; use crate::{ prelude::*, process::signal::Pauser, @@ -14,9 +14,14 @@ pub fn sys_nanosleep( request_timespec_addr: Vaddr, remain_timespec_addr: Vaddr, ) -> Result { - let clock_id = ClockID::CLOCK_MONOTONIC; + let clockid = ClockId::CLOCK_MONOTONIC; - do_clock_nanosleep(clock_id, false, request_timespec_addr, remain_timespec_addr) + do_clock_nanosleep( + clockid as clockid_t, + false, + request_timespec_addr, + remain_timespec_addr, + ) } pub fn sys_clock_nanosleep( @@ -25,7 +30,6 @@ pub fn sys_clock_nanosleep( request_timespec_addr: Vaddr, remain_timespec_addr: Vaddr, ) -> Result { - let clock_id = ClockID::try_from(clockid)?; let is_abs_time = if flags == 0 { false } else if flags == TIMER_ABSTIME { @@ -35,7 +39,7 @@ pub fn sys_clock_nanosleep( }; do_clock_nanosleep( - clock_id, + clockid, is_abs_time, request_timespec_addr, remain_timespec_addr, @@ -43,7 +47,7 @@ pub fn sys_clock_nanosleep( } fn do_clock_nanosleep( - clock_id: ClockID, + clockid: clockid_t, is_abs_time: bool, request_timespec_addr: Vaddr, remain_timespec_addr: Vaddr, @@ -55,10 +59,10 @@ fn do_clock_nanosleep( debug!( "clockid = {:?}, is_abs_time = {}, request_time = {:?}, remain_timespec_addr = 0x{:x}", - clock_id, is_abs_time, request_time, remain_timespec_addr + clockid, is_abs_time, request_time, remain_timespec_addr ); - let start_time = read_clock(&clock_id)?; + let start_time = read_clock(clockid)?; let timeout = if is_abs_time { if request_time < start_time { return Ok(SyscallReturn::Return(0)); @@ -77,7 +81,7 @@ fn do_clock_nanosleep( match res { Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)), Err(e) if e.error() == Errno::EINTR => { - let end_time = read_clock(&clock_id)?; + let end_time = read_clock(clockid)?; if end_time >= start_time + timeout { return Ok(SyscallReturn::Return(0)); diff --git a/kernel/aster-nix/src/syscall/set_get_priority.rs b/kernel/aster-nix/src/syscall/set_get_priority.rs index b2c8d81fe..776a0ede2 100644 --- a/kernel/aster-nix/src/syscall/set_get_priority.rs +++ b/kernel/aster-nix/src/syscall/set_get_priority.rs @@ -61,7 +61,7 @@ pub fn sys_get_priority(which: i32, who: u32) -> Result { fn get_processes(prio_target: PriorityTarget) -> Result>> { Ok(match prio_target { PriorityTarget::Process(pid) => { - let process = process_table::get_process(&pid).ok_or(Error::new(Errno::ESRCH))?; + let process = process_table::get_process(pid).ok_or(Error::new(Errno::ESRCH))?; vec![process] } PriorityTarget::ProcessGroup(pgid) => { diff --git a/kernel/aster-nix/src/syscall/setpgid.rs b/kernel/aster-nix/src/syscall/setpgid.rs index 1a5f7d87d..2b60c94ed 100644 --- a/kernel/aster-nix/src/syscall/setpgid.rs +++ b/kernel/aster-nix/src/syscall/setpgid.rs @@ -28,7 +28,7 @@ pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result { return_errno_with_message!(Errno::EPERM, "process group must exist"); } - let process = process_table::get_process(&pid) + let process = process_table::get_process(pid) .ok_or(Error::with_message(Errno::ESRCH, "process does not exist"))?; process.to_other_group(pgid)?;