mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 17:33:23 +00:00
Support more clock ids
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
c84efe7a90
commit
e952a16954
@ -96,7 +96,7 @@ impl DirOps for RootDirOps {
|
|||||||
SelfSymOps::new_inode(this_ptr.clone())
|
SelfSymOps::new_inode(this_ptr.clone())
|
||||||
} else if let Ok(pid) = name.parse::<Pid>() {
|
} else if let Ok(pid) = name.parse::<Pid>() {
|
||||||
let process_ref =
|
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())
|
PidDirOps::new_inode(process_ref, this_ptr.clone())
|
||||||
} else {
|
} else {
|
||||||
return_errno!(Errno::ENOENT);
|
return_errno!(Errno::ENOENT);
|
||||||
|
@ -63,7 +63,7 @@ const INIT_PROCESS_PID: Pid = 1;
|
|||||||
|
|
||||||
/// Get the init process
|
/// Get the init process
|
||||||
fn get_init_process() -> Option<Arc<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 {
|
fn is_init_process(process: &Process) -> bool {
|
||||||
|
@ -20,7 +20,7 @@ use crate::{
|
|||||||
/// If `signal` is `None`, this method will only check permission without sending
|
/// If `signal` is `None`, this method will only check permission without sending
|
||||||
/// any signal.
|
/// any signal.
|
||||||
pub fn kill(pid: Pid, signal: Option<UserSignal>) -> Result<()> {
|
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"))?;
|
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process does not exist"))?;
|
||||||
|
|
||||||
kill_process(&process, signal)
|
kill_process(&process, signal)
|
||||||
|
@ -20,8 +20,8 @@ static SESSION_TABLE: Mutex<BTreeMap<Sid, Arc<Session>>> = Mutex::new(BTreeMap::
|
|||||||
// ************ Process *************
|
// ************ Process *************
|
||||||
|
|
||||||
/// Gets a process with pid
|
/// Gets a process with pid
|
||||||
pub fn get_process(pid: &Pid) -> Option<Arc<Process>> {
|
pub fn get_process(pid: Pid) -> Option<Arc<Process>> {
|
||||||
PROCESS_TABLE.lock().get(pid).cloned()
|
PROCESS_TABLE.lock().get(&pid).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn process_table_mut() -> MutexGuard<'static, BTreeMap<Pid, Arc<Process>>> {
|
pub(super) fn process_table_mut() -> MutexGuard<'static, BTreeMap<Pid, Arc<Process>>> {
|
||||||
|
@ -8,6 +8,8 @@ use int_to_c_enum::TryFromInt;
|
|||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
process::{posix_thread::PosixThreadExt, process_table},
|
||||||
|
thread::{thread_table, Thread},
|
||||||
time::{
|
time::{
|
||||||
clockid_t,
|
clockid_t,
|
||||||
clocks::{
|
clocks::{
|
||||||
@ -20,10 +22,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn sys_clock_gettime(clockid: clockid_t, timespec_addr: Vaddr) -> Result<SyscallReturn> {
|
pub fn sys_clock_gettime(clockid: clockid_t, timespec_addr: Vaddr) -> Result<SyscallReturn> {
|
||||||
let clock_id = ClockID::try_from(clockid)?;
|
debug!("clockid = {:?}", clockid);
|
||||||
debug!("clockid = {:?}", clock_id);
|
|
||||||
|
|
||||||
let time_duration = read_clock(&clock_id)?;
|
let time_duration = read_clock(clockid)?;
|
||||||
|
|
||||||
let timespec = timespec_t::from(time_duration);
|
let timespec = timespec_t::from(time_duration);
|
||||||
write_val_to_user(timespec_addr, ×pec)?;
|
write_val_to_user(timespec_addr, ×pec)?;
|
||||||
@ -31,9 +32,10 @@ pub fn sys_clock_gettime(clockid: clockid_t, timespec_addr: Vaddr) -> Result<Sys
|
|||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The hard-coded clock IDs.
|
||||||
#[derive(Debug, Copy, Clone, TryFromInt, PartialEq)]
|
#[derive(Debug, Copy, Clone, TryFromInt, PartialEq)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum ClockID {
|
pub enum ClockId {
|
||||||
CLOCK_REALTIME = 0,
|
CLOCK_REALTIME = 0,
|
||||||
CLOCK_MONOTONIC = 1,
|
CLOCK_MONOTONIC = 1,
|
||||||
CLOCK_PROCESS_CPUTIME_ID = 2,
|
CLOCK_PROCESS_CPUTIME_ID = 2,
|
||||||
@ -44,19 +46,110 @@ pub enum ClockID {
|
|||||||
CLOCK_BOOTTIME = 7,
|
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`.
|
/// Dynamic clocks are the clocks operates on certain
|
||||||
pub fn read_clock(clock_id: &ClockID) -> Result<Duration> {
|
/// character devices, processes or threads. Their IDs will
|
||||||
match clock_id {
|
/// be generated by encoding the file descriptor, PID or TID.
|
||||||
ClockID::CLOCK_REALTIME => Ok(RealTimeClock::get().read_time()),
|
/// Here we follow the rules in Linux:
|
||||||
ClockID::CLOCK_MONOTONIC => Ok(MonotonicClock::get().read_time()),
|
///
|
||||||
ClockID::CLOCK_MONOTONIC_RAW => Ok(MonotonicRawClock::get().read_time()),
|
/// The dynamic clock ID is a 32 bit integer.
|
||||||
ClockID::CLOCK_REALTIME_COARSE => Ok(RealTimeCoarseClock::get().read_time()),
|
/// - The most significant 29 bits hold either a PID or a file descriptor.
|
||||||
ClockID::CLOCK_MONOTONIC_COARSE => Ok(MonotonicCoarseClock::get().read_time()),
|
/// - Bit 2 indicates whether a cpu clock refers to a thread or a process.
|
||||||
ClockID::CLOCK_BOOTTIME => Ok(BootTimeClock::get().read_time()),
|
/// - 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.
|
||||||
return_errno_with_message!(Errno::EINVAL, "unsupported clock_id");
|
///
|
||||||
|
/// 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()),
|
||||||
|
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!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ pub fn sys_getsid(pid: Pid) -> Result<SyscallReturn> {
|
|||||||
return Ok(SyscallReturn::Return(sid as _));
|
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")
|
return_errno_with_message!(Errno::ESRCH, "the process does not exist")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use super::{clock_gettime::read_clock, ClockID, SyscallReturn};
|
use super::{clock_gettime::read_clock, ClockId, SyscallReturn};
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::signal::Pauser,
|
process::signal::Pauser,
|
||||||
@ -14,9 +14,14 @@ pub fn sys_nanosleep(
|
|||||||
request_timespec_addr: Vaddr,
|
request_timespec_addr: Vaddr,
|
||||||
remain_timespec_addr: Vaddr,
|
remain_timespec_addr: Vaddr,
|
||||||
) -> Result<SyscallReturn> {
|
) -> 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(
|
pub fn sys_clock_nanosleep(
|
||||||
@ -25,7 +30,6 @@ pub fn sys_clock_nanosleep(
|
|||||||
request_timespec_addr: Vaddr,
|
request_timespec_addr: Vaddr,
|
||||||
remain_timespec_addr: Vaddr,
|
remain_timespec_addr: Vaddr,
|
||||||
) -> Result<SyscallReturn> {
|
) -> Result<SyscallReturn> {
|
||||||
let clock_id = ClockID::try_from(clockid)?;
|
|
||||||
let is_abs_time = if flags == 0 {
|
let is_abs_time = if flags == 0 {
|
||||||
false
|
false
|
||||||
} else if flags == TIMER_ABSTIME {
|
} else if flags == TIMER_ABSTIME {
|
||||||
@ -35,7 +39,7 @@ pub fn sys_clock_nanosleep(
|
|||||||
};
|
};
|
||||||
|
|
||||||
do_clock_nanosleep(
|
do_clock_nanosleep(
|
||||||
clock_id,
|
clockid,
|
||||||
is_abs_time,
|
is_abs_time,
|
||||||
request_timespec_addr,
|
request_timespec_addr,
|
||||||
remain_timespec_addr,
|
remain_timespec_addr,
|
||||||
@ -43,7 +47,7 @@ pub fn sys_clock_nanosleep(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn do_clock_nanosleep(
|
fn do_clock_nanosleep(
|
||||||
clock_id: ClockID,
|
clockid: clockid_t,
|
||||||
is_abs_time: bool,
|
is_abs_time: bool,
|
||||||
request_timespec_addr: Vaddr,
|
request_timespec_addr: Vaddr,
|
||||||
remain_timespec_addr: Vaddr,
|
remain_timespec_addr: Vaddr,
|
||||||
@ -55,10 +59,10 @@ fn do_clock_nanosleep(
|
|||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"clockid = {:?}, is_abs_time = {}, request_time = {:?}, remain_timespec_addr = 0x{:x}",
|
"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 {
|
let timeout = if is_abs_time {
|
||||||
if request_time < start_time {
|
if request_time < start_time {
|
||||||
return Ok(SyscallReturn::Return(0));
|
return Ok(SyscallReturn::Return(0));
|
||||||
@ -77,7 +81,7 @@ fn do_clock_nanosleep(
|
|||||||
match res {
|
match res {
|
||||||
Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)),
|
Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)),
|
||||||
Err(e) if e.error() == Errno::EINTR => {
|
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 {
|
if end_time >= start_time + timeout {
|
||||||
return Ok(SyscallReturn::Return(0));
|
return Ok(SyscallReturn::Return(0));
|
||||||
|
@ -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>>> {
|
fn get_processes(prio_target: PriorityTarget) -> Result<Vec<Arc<Process>>> {
|
||||||
Ok(match prio_target {
|
Ok(match prio_target {
|
||||||
PriorityTarget::Process(pid) => {
|
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]
|
vec![process]
|
||||||
}
|
}
|
||||||
PriorityTarget::ProcessGroup(pgid) => {
|
PriorityTarget::ProcessGroup(pgid) => {
|
||||||
|
@ -28,7 +28,7 @@ pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result<SyscallReturn> {
|
|||||||
return_errno_with_message!(Errno::EPERM, "process group must exist");
|
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"))?;
|
.ok_or(Error::with_message(Errno::ESRCH, "process does not exist"))?;
|
||||||
|
|
||||||
process.to_other_group(pgid)?;
|
process.to_other_group(pgid)?;
|
||||||
|
Reference in New Issue
Block a user