Support more clock ids

This commit is contained in:
Chen Chengjun
2024-05-31 18:21:46 +08:00
committed by Tate, Hongliang Tian
parent c84efe7a90
commit e952a16954
9 changed files with 130 additions and 33 deletions

View File

@ -96,7 +96,7 @@ impl DirOps for RootDirOps {
SelfSymOps::new_inode(this_ptr.clone())
} else if let Ok(pid) = name.parse::<Pid>() {
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);

View File

@ -63,7 +63,7 @@ const INIT_PROCESS_PID: Pid = 1;
/// Get the init process
fn get_init_process() -> Option<Arc<Process>> {
process_table::get_process(&INIT_PROCESS_PID)
process_table::get_process(INIT_PROCESS_PID)
}
fn is_init_process(process: &Process) -> bool {

View File

@ -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<UserSignal>) -> 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)

View File

@ -20,8 +20,8 @@ static SESSION_TABLE: Mutex<BTreeMap<Sid, Arc<Session>>> = Mutex::new(BTreeMap::
// ************ Process *************
/// Gets a process with pid
pub fn get_process(pid: &Pid) -> Option<Arc<Process>> {
PROCESS_TABLE.lock().get(pid).cloned()
pub fn get_process(pid: Pid) -> Option<Arc<Process>> {
PROCESS_TABLE.lock().get(&pid).cloned()
}
pub(super) fn process_table_mut() -> MutexGuard<'static, BTreeMap<Pid, Arc<Process>>> {

View File

@ -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<SyscallReturn> {
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, &timespec)?;
@ -31,9 +32,10 @@ pub fn sys_clock_gettime(clockid: clockid_t, timespec_addr: Vaddr) -> Result<Sys
Ok(SyscallReturn::Return(0))
}
// The hard-coded clock IDs.
#[derive(Debug, Copy, Clone, TryFromInt, PartialEq)]
#[repr(i32)]
pub enum ClockID {
pub enum ClockId {
CLOCK_REALTIME = 0,
CLOCK_MONOTONIC = 1,
CLOCK_PROCESS_CPUTIME_ID = 2,
@ -44,19 +46,110 @@ pub enum ClockID {
CLOCK_BOOTTIME = 7,
}
/// Read the time of a clock specified by the input `ClockID`.
/// The information decoded from a dynamic clock ID.
///
/// If the `ClockID` does not support, this function will return `Err`.
pub fn read_clock(clock_id: &ClockID) -> Result<Duration> {
/// 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<clockid_t> for DynamicClockIdInfo {
type Error = crate::Error;
fn try_from(value: clockid_t) -> core::prelude::v1::Result<Self, Self::Error> {
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<Duration> {
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()),
_ => {
return_errno_with_message!(Errno::EINVAL, "unsupported 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!(),
}
}
}

View File

@ -16,7 +16,7 @@ pub fn sys_getsid(pid: Pid) -> Result<SyscallReturn> {
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")
};

View File

@ -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<SyscallReturn> {
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<SyscallReturn> {
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));

View File

@ -61,7 +61,7 @@ pub fn sys_get_priority(which: i32, who: u32) -> Result<SyscallReturn> {
fn get_processes(prio_target: PriorityTarget) -> Result<Vec<Arc<Process>>> {
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) => {

View File

@ -28,7 +28,7 @@ pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result<SyscallReturn> {
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)?;