mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 16:33:24 +00:00
156 lines
5.4 KiB
Rust
156 lines
5.4 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
use core::time::Duration;
|
|
|
|
use int_to_c_enum::TryFromInt;
|
|
|
|
use super::SyscallReturn;
|
|
use crate::{
|
|
prelude::*,
|
|
process::{
|
|
posix_thread::{thread_table, AsPosixThread},
|
|
process_table,
|
|
},
|
|
time::{
|
|
clockid_t,
|
|
clocks::{
|
|
BootTimeClock, MonotonicClock, MonotonicCoarseClock, MonotonicRawClock, RealTimeClock,
|
|
RealTimeCoarseClock,
|
|
},
|
|
timespec_t, Clock,
|
|
},
|
|
};
|
|
|
|
pub fn sys_clock_gettime(
|
|
clockid: clockid_t,
|
|
timespec_addr: Vaddr,
|
|
ctx: &Context,
|
|
) -> Result<SyscallReturn> {
|
|
debug!("clockid = {:?}", clockid);
|
|
|
|
let time_duration = read_clock(clockid, ctx)?;
|
|
|
|
let timespec = timespec_t::from(time_duration);
|
|
ctx.get_user_space().write_val(timespec_addr, ×pec)?;
|
|
|
|
Ok(SyscallReturn::Return(0))
|
|
}
|
|
|
|
// The hard-coded clock IDs.
|
|
#[derive(Debug, Copy, Clone, TryFromInt, PartialEq)]
|
|
#[repr(i32)]
|
|
#[allow(non_camel_case_types)]
|
|
pub enum ClockId {
|
|
CLOCK_REALTIME = 0,
|
|
CLOCK_MONOTONIC = 1,
|
|
CLOCK_PROCESS_CPUTIME_ID = 2,
|
|
CLOCK_THREAD_CPUTIME_ID = 3,
|
|
CLOCK_MONOTONIC_RAW = 4,
|
|
CLOCK_REALTIME_COARSE = 5,
|
|
CLOCK_MONOTONIC_COARSE = 6,
|
|
CLOCK_BOOTTIME = 7,
|
|
}
|
|
|
|
/// The information decoded from a dynamic 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),
|
|
#[allow(dead_code)]
|
|
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, ctx: &Context) -> 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 => Ok(ctx.process.prof_clock().read_time()),
|
|
ClockId::CLOCK_THREAD_CPUTIME_ID => Ok(ctx.posix_thread.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!(),
|
|
}
|
|
}
|
|
}
|