Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions kernel/src/process/cputime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};

use alloc::sync::Arc;

use log::warn;

use crate::libs::wait_queue::WaitQueue;

use super::{ProcessControlBlock, ProcessManager};

#[derive(Debug, Default)]
pub struct ProcessCpuTime {
pub utime: AtomicU64,
pub stime: AtomicU64,
pub sum_exec_runtime: AtomicU64,
}

impl ProcessControlBlock {
#[inline(always)]
pub fn cputime_wait_queue(&self) -> &WaitQueue {
&self.cputime_wait_queue
}

#[inline(always)]
pub fn cputime(&self) -> Arc<ProcessCpuTime> {
self.cpu_time.clone()
}

/// 当前线程(PCB)的 CPU 时间(ns),语义对齐 Linux 的 CLOCK_THREAD_CPUTIME_ID:user+system。
#[inline]
pub fn thread_cputime_ns(&self) -> u64 {
// 这里使用 Ordering::Relaxed:
// - 只需要读取两个独立计数器的“某个一致快照”(不要求与其它内存状态建立 happens-before)。
// - 对单个 AtomicU64 保证按地址一致性(coherence),满足 CPU-time 统计的近似/观测语义。
// 如未来需要与其它状态强一致(例如结合序列号/结构体快照),再引入更强的同步原语。
let ct = self.cputime();
ct.utime.load(Ordering::Relaxed) + ct.stime.load(Ordering::Relaxed)
}

/// 当前进程(线程组)的 CPU 时间(ns),语义对齐 Linux 的 CLOCK_PROCESS_CPUTIME_ID。
///
/// 说明:目前通过遍历线程组成员并累加每线程的 user+system 得到。
pub fn process_cputime_ns(&self) -> u64 {
static BAD_TGROUP_LOGGED: AtomicBool = AtomicBool::new(false);

// 尽量选择线程组组长作为“进程”视角。
let leader = if self.is_thread_group_leader() {
self.self_ref
.upgrade()
.unwrap_or_else(ProcessManager::current_pcb)
} else {
self.threads_read_irqsave()
.group_leader()
.or_else(|| self.self_ref.upgrade())
.unwrap_or_else(ProcessManager::current_pcb)
};

if !leader.is_thread_group_leader() {
// 防御:线程组关系未初始化时,退化为本线程。
if BAD_TGROUP_LOGGED
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
warn!(
"process_cputime_ns fallback: invalid thread-group relation (pid={:?} tgid={:?} leader_pid={:?} leader_tgid={:?})",
self.raw_pid(),
self.tgid,
leader.raw_pid(),
leader.tgid,
);
}
return self.thread_cputime_ns();
}

let mut total = leader.thread_cputime_ns();
let ti = leader.threads_read_irqsave();
for t in &ti.group_tasks {
if let Some(p) = t.upgrade() {
total = total.saturating_add(p.thread_cputime_ns());
}
}
total
}

#[inline(always)]
pub fn account_utime(&self, ns: u64) {
if ns == 0 {
return;
}
self.cpu_time.utime.fetch_add(ns, Ordering::Relaxed);
}

#[inline(always)]
pub fn account_stime(&self, ns: u64) {
if ns == 0 {
return;
}
self.cpu_time.stime.fetch_add(ns, Ordering::Relaxed);
}

#[inline(always)]
pub fn add_sum_exec_runtime(&self, ns: u64) {
self.cpu_time
.sum_exec_runtime
.fetch_add(ns, Ordering::Relaxed);
}
}
42 changes: 8 additions & 34 deletions kernel/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::{
hint::spin_loop,
intrinsics::unlikely,
mem::ManuallyDrop,
sync::atomic::{compiler_fence, fence, AtomicBool, AtomicU64, AtomicUsize, Ordering},
sync::atomic::{compiler_fence, fence, AtomicBool, AtomicUsize, Ordering},
};

use alloc::{
Expand Down Expand Up @@ -75,6 +75,7 @@ use self::{cred::Cred, kthread::WorkerPrivate};
use crate::process::namespace::nsproxy::NsProxy;

pub mod abi;
pub mod cputime;
pub mod cred;
pub mod exec;
pub mod execve;
Expand All @@ -97,6 +98,8 @@ pub mod syscall;
pub mod timer;
pub mod utils;

pub use cputime::ProcessCpuTime;

/// 系统中所有进程的pcb
static ALL_PROCESS: SpinLock<Option<HashMap<RawPid, Arc<ProcessControlBlock>>>> =
SpinLock::new(None);
Expand Down Expand Up @@ -830,14 +833,6 @@ impl ProcessFlags {
}
}

// TODO 完善相关的方法
#[derive(Debug, Default)]
pub struct ProcessCpuTime {
pub utime: AtomicU64,
pub stime: AtomicU64,
pub sum_exec_runtime: AtomicU64,
}

#[derive(Debug, Default)]
pub struct CpuItimer {
pub value: u64, // 剩余时间 ns
Expand Down Expand Up @@ -910,6 +905,9 @@ pub struct ProcessControlBlock {
/// 等待队列
wait_queue: WaitQueue,

/// CPU-time 等待队列:用于 CLOCK_{PROCESS,THREAD}_CPUTIME_ID 的 clock_nanosleep
cputime_wait_queue: WaitQueue,

/// 线程信息
thread: RwLock<ThreadInfo>,

Expand Down Expand Up @@ -1052,6 +1050,7 @@ impl ProcessControlBlock {
real_parent_pcb: RwLock::new(ppcb),
children: RwLock::new(Vec::new()),
wait_queue: WaitQueue::default(),
cputime_wait_queue: WaitQueue::default(),
thread: RwLock::new(ThreadInfo::new()),
fs: RwLock::new(Arc::new(FsStruct::new())),
alarm_timer: SpinLock::new(None),
Expand Down Expand Up @@ -1624,31 +1623,6 @@ impl ProcessControlBlock {
return self.posix_timers.lock_irqsave();
}

#[inline(always)]
pub fn cputime(&self) -> Arc<ProcessCpuTime> {
return self.cpu_time.clone();
}
#[inline(always)]
pub fn account_utime(&self, ns: u64) {
if ns == 0 {
return;
}
self.cpu_time.utime.fetch_add(ns, Ordering::Relaxed);
}
#[inline(always)]
pub fn account_stime(&self, ns: u64) {
if ns == 0 {
return;
}
self.cpu_time.stime.fetch_add(ns, Ordering::Relaxed);
}
#[inline(always)]
pub fn add_sum_exec_runtime(&self, ns: u64) {
self.cpu_time
.sum_exec_runtime
.fetch_add(ns, Ordering::Relaxed);
}

/// Exit fd table when process exit
fn exit_files(&self) {
// 关闭文件描述符表
Expand Down
21 changes: 20 additions & 1 deletion kernel/src/sched/cputime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
arch::{ipc::signal::Signal, CurrentIrqArch},
exception::InterruptArch,
ipc::kill::send_signal_to_pcb,
process::ProcessControlBlock,
process::{ProcessControlBlock, ProcessState},
smp::{core::smp_get_processor_id, cpu::ProcessorId},
time::jiffies::TICK_NESC,
};
Expand Down Expand Up @@ -97,6 +97,25 @@ impl CpuTimeFunc {
}
pcb.add_sum_exec_runtime(accounted_cputime);

// 唤醒可能在等待 CPU-time 时钟的线程(clock_nanosleep: PROCESS/THREAD_CPUTIME)。
// 线程 CPU-time:仅在该线程运行时推进,因此唤醒该 PCB 的等待队列即可。
if !pcb.cputime_wait_queue().is_empty() {
pcb.cputime_wait_queue()
.wakeup_all(Some(ProcessState::Blocked(true)));
}

// 进程 CPU-time:需要在任一线程推进时唤醒线程组组长上的等待队列。
// 这样“主线程 sleep + 子线程 busy loop”的场景才能正确返回。
if !pcb.is_thread_group_leader() {
if let Some(leader) = pcb.threads_read_irqsave().group_leader() {
if !leader.cputime_wait_queue().is_empty() {
leader
.cputime_wait_queue()
.wakeup_all(Some(ProcessState::Blocked(true)));
}
}
}

// 检查并处理CPU时间定时器
let mut itimers = pcb.itimers_irqsave();
// 处理 ITIMER_VIRTUAL (仅在用户态tick时消耗时间)
Expand Down
8 changes: 8 additions & 0 deletions kernel/src/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ impl PosixTimeSpec {
pub fn total_nanos(&self) -> i64 {
self.tv_sec * 1000000000 + self.tv_nsec
}

/// 从纳秒创建 PosixTimeSpec
pub fn from_ns(ns: u64) -> PosixTimeSpec {
PosixTimeSpec {
tv_sec: (ns / 1_000_000_000) as i64,
tv_nsec: (ns % 1_000_000_000) as i64,
}
}
}

impl Sub for PosixTimeSpec {
Expand Down
25 changes: 21 additions & 4 deletions kernel/src/time/syscall/sys_clock_gettime.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::arch::interrupt::TrapFrame;
use crate::arch::syscall::nr::SYS_CLOCK_GETTIME;
use crate::process::ProcessManager;
use crate::syscall::table::{FormattedSyscallParam, Syscall};
use crate::syscall::user_access::UserBufferWriter;
use crate::time::timekeeping::getnstimeofday;
Expand All @@ -26,9 +27,6 @@ impl Syscall for SysClockGettime {

fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
let clock_id = PosixClockID::try_from(Self::clock_id(args))?;
if clock_id != PosixClockID::Realtime {
// warn!("clock_gettime: currently only support Realtime clock, but got {:?}. Defaultly return realtime!!!\n", clock_id);
}

let tp = Self::timespec_ptr(args);
if tp.is_null() {
Expand All @@ -41,7 +39,26 @@ impl Syscall for SysClockGettime {
true,
)?;

let timespec = getnstimeofday();
let timespec = match clock_id {
PosixClockID::Realtime => getnstimeofday(),
// 单调/boottime 等目前仍复用 realtime(后续可补齐真正语义)。
PosixClockID::Monotonic
| PosixClockID::Boottime
| PosixClockID::MonotonicRaw
| PosixClockID::RealtimeCoarse
| PosixClockID::MonotonicCoarse
| PosixClockID::RealtimeAlarm
| PosixClockID::BoottimeAlarm => getnstimeofday(),

PosixClockID::ProcessCPUTimeID => {
let pcb = ProcessManager::current_pcb();
PosixTimeSpec::from_ns(pcb.process_cputime_ns())
}
PosixClockID::ThreadCPUTimeID => {
let pcb = ProcessManager::current_pcb();
PosixTimeSpec::from_ns(pcb.thread_cputime_ns())
}
};

tp_buf.copy_one_to_user(&timespec, 0)?;

Expand Down
61 changes: 54 additions & 7 deletions kernel/src/time/syscall/sys_clock_nanosleep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,29 @@ impl SysClockNanosleep {
match clockid {
Realtime => getnstimeofday(),
Monotonic | Boottime => getnstimeofday(),
ProcessCPUTimeID => {
let pcb = ProcessManager::current_pcb();
PosixTimeSpec::from_ns(pcb.process_cputime_ns())
}
ThreadCPUTimeID => {
let pcb = ProcessManager::current_pcb();
PosixTimeSpec::from_ns(pcb.thread_cputime_ns())
}
_ => getnstimeofday(),
}
}

#[inline]
fn is_valid_timespec(ts: &PosixTimeSpec) -> bool {
ts.tv_nsec >= 0 && ts.tv_nsec < 1_000_000_000
ts.tv_sec >= 0 && ts.tv_nsec >= 0 && ts.tv_nsec < 1_000_000_000
}

#[inline]
fn to_ns(ts: &PosixTimeSpec) -> u64 {
// 这里已经保证了 tv_sec/tv_nsec 非负且 tv_nsec < 1e9
(ts.tv_sec as u64)
.saturating_mul(1_000_000_000)
.saturating_add(ts.tv_nsec as u64)
}

#[inline]
Expand Down Expand Up @@ -79,12 +95,43 @@ impl SysClockNanosleep {
}

fn do_wait_until(deadline: &PosixTimeSpec, clockid: PosixClockID) -> Result<(), SystemError> {
let now = Self::ktime_now(clockid);
let remain = Self::calc_remaining(deadline, &now);
if remain.tv_sec == 0 && remain.tv_nsec == 0 {
return Ok(());
match clockid {
ProcessCPUTimeID => {
let current = ProcessManager::current_pcb();
let leader = if current.is_thread_group_leader() {
current
} else {
current
.threads_read_irqsave()
.group_leader()
.unwrap_or_else(ProcessManager::current_pcb)
};

let deadline_ns = Self::to_ns(deadline);
leader.cputime_wait_queue().wait_event_interruptible(
|| leader.process_cputime_ns() >= deadline_ns,
None::<fn()>,
)?;
Ok(())
}
ThreadCPUTimeID => {
let pcb = ProcessManager::current_pcb();
let deadline_ns = Self::to_ns(deadline);
pcb.cputime_wait_queue().wait_event_interruptible(
|| pcb.thread_cputime_ns() >= deadline_ns,
None::<fn()>,
)?;
Ok(())
}
_ => {
let now = Self::ktime_now(clockid);
let remain = Self::calc_remaining(deadline, &now);
if remain.tv_sec == 0 && remain.tv_nsec == 0 {
return Ok(());
}
nanosleep(remain).map(|_| ())
}
}
nanosleep(remain).map(|_| ())
}
}

Expand All @@ -97,7 +144,7 @@ impl Syscall for SysClockNanosleep {
// 解析/校验参数
let clockid = PosixClockID::try_from(Self::which_clock(args))?;
match clockid {
Realtime | Monotonic | Boottime => {}
Realtime | Monotonic | Boottime | ProcessCPUTimeID | ThreadCPUTimeID => {}
_ => return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP),
}
let flags = Self::flags(args);
Expand Down
Loading
Loading