fix(syscall): 修复cputime, sys_rt_sigtimedwait and sys_rt_sigreturn (#1406)

1. **修复:** 进程 CPU 时间统UserUContext 计精度,将统计基准调整为扣除 IRQ 和 Steal 时间后的净时间(accounted_cputime),避免将硬件中断处理时间错误计入进程的 utime/stime
2. **修复:** `sys_rt_sigtimedwait`: 
- 修复了信号等待逻辑,确保即使 等待信号集 为空也能正确进入 do_kernel_rt_sigtimedwait,符合 Linux 行为。
- 修复潜在的无限睡眠问题:当线程被非目标信号或非超时事件唤醒时,将正确返回 EINTR,避免进程一直挂起。
- 修复了bitflags错误移除的bug,应该使用remove()。
3. **修复:** `sys_rt_sigreturn:`:
- 当从信号处理函数返回用户态时,内核错误地使用 sysretq 来处理 sys_rt_sigreturn 的返回,%rcx 和 %r11 这两个寄存器被意外破坏。
- 修复:如果待恢复的 %rcx / %r11 与 sysretq 的行为冲突,则强制跳转到 .L_syscall_must_use_iret 分支,使用 iretq 指令精确恢复完整的上下文。

TODO: 目标线程的 TGID 没有正确设置为 leader 的 PID,导致还有两个sys_rt_sigtimedwait的测例无法通过。
```sh
Value of: tgkill(getpid(), tid, kSigno)
Expected: not -1 (success)
  Actual: -1 (of type int), with errno PosixError(errno=3 No such process)
```

---------

Signed-off-by: aLinChe <1129332011@qq.com>
This commit is contained in:
aLinChe 2025-11-26 00:21:03 +08:00 committed by GitHub
parent a69dad1bb2
commit cb6237403a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 36 additions and 22 deletions

View File

@ -407,6 +407,11 @@ ENTRY(syscall_64)
popq %rax
addq $0x10, %rsp // FUNCerrcode
cmpq (%rsp), %rcx
jne .L_syscall_must_use_iret
cmpq 0x10(%rsp), %r11
jne .L_syscall_must_use_iret
popq %rcx // pop riprcx
addq $0x8, %rsp // cs
@ -415,3 +420,9 @@ ENTRY(syscall_64)
swapgs
sysretq
// sigreturn, ptrace,
// iretq : [RIP, CS, RFLAGS, RSP, SS]
.L_syscall_must_use_iret:
swapgs
iretq

View File

@ -58,19 +58,12 @@ pub fn do_kernel_rt_sigtimedwait(
let reader = UserBufferReader::new(uthese, size_of::<SigSet>(), from_user)?;
let sigset = reader.read_one_from_user::<SigSet>(0)?;
// 移除不可屏蔽的信号SIGKILL 和 SIGSTOP
let sigset_val: SigSet = SigSet::from_bits(sigset.bits()).ok_or(SystemError::EINVAL)?;
let kill_stop_mask: SigSet =
SigSet::from_bits_truncate((Signal::SIGKILL as u64) | (Signal::SIGSTOP as u64));
let result = sigset_val & !kill_stop_mask;
result
let mut sigset_val = SigSet::from_bits(sigset.bits()).ok_or(SystemError::EINVAL)?;
sigset_val.remove(SigSet::from(Signal::SIGKILL));
sigset_val.remove(SigSet::from(Signal::SIGSTOP));
sigset_val
};
// 如果信号集合为空,直接返回 EINVAL根据 POSIX 标准)
if these.is_empty() {
return Err(SystemError::EINVAL);
}
// 构造等待/屏蔽语义与Linux一致
// - 等待集合 these
// - 临时屏蔽集合 = 旧blocked these将这些信号作为masked的常规语义但仍由本系统调用专门消费
@ -134,13 +127,21 @@ pub fn do_kernel_rt_sigtimedwait(
}
}
// 第四步:释放中断,然后真正进入调度睡眠(窗口期内,线程保持可中断阻塞,发送侧会唤醒)
// 第四步:检查是否有其他未屏蔽的待处理信号打断,若被其他信号唤醒了,必须返回 EINTR 让内核去处理那个信号
pcb.recalc_sigpending(None);
if pcb.has_pending_signal_fast() {
drop(preempt_guard);
restore_saved_sigmask();
return Err(SystemError::EINTR);
}
// 第五步:释放中断,然后真正进入调度睡眠(窗口期内,线程保持可中断阻塞,发送侧会唤醒)
// 计算剩余等待时间
let remaining_time = if let Some(deadline) = deadline {
let now = PosixTimeSpec::now();
let remaining = deadline.total_nanos() - now.total_nanos();
if remaining <= 0 {
drop(preempt_guard);
restore_saved_sigmask();
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}

View File

@ -88,15 +88,15 @@ impl CpuTimeFunc {
return;
}
if user_tick {
pcb.account_utime(cputime);
} else {
pcb.account_stime(cputime);
}
pcb.add_sum_exec_runtime(cputime);
let accounted_cputime = cputime - other;
if user_tick {
pcb.account_utime(accounted_cputime);
} else {
pcb.account_stime(accounted_cputime);
}
pcb.add_sum_exec_runtime(accounted_cputime);
let cputime_ns = TICK_NESC as u64 * ticks;
let accounted_cputime = cputime_ns - other;
// 检查并处理CPU时间定时器
let mut itimers = pcb.itimers_irqsave();
// 处理 ITIMER_VIRTUAL (仅在用户态tick时消耗时间)

View File

@ -1,2 +0,0 @@
# 还在修复中
SigIretTest.CheckRcxR11

View File

@ -0,0 +1,3 @@
# getpid() 好像有点问题,还在修
SigtimedwaitTest.IgnoredUnmaskedSignal
SigtimedwaitTest.IgnoredMaskedSignal

View File

@ -57,6 +57,7 @@ sigaction_test
sigprocmask_test
sigaltstack_test
sigreturn_test
sigtimedwait_test
# 其他测试
itimer_test