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:
parent
a69dad1bb2
commit
cb6237403a
|
|
@ -407,6 +407,11 @@ ENTRY(syscall_64)
|
|||
popq %rax
|
||||
addq $0x10, %rsp // 弹出变量FUNC和errcode
|
||||
|
||||
cmpq (%rsp), %rcx
|
||||
jne .L_syscall_must_use_iret
|
||||
cmpq 0x10(%rsp), %r11
|
||||
jne .L_syscall_must_use_iret
|
||||
|
||||
popq %rcx // pop rip到rcx
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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时消耗时间)
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
# 还在修复中
|
||||
SigIretTest.CheckRcxR11
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# getpid() 好像有点问题,还在修
|
||||
SigtimedwaitTest.IgnoredUnmaskedSignal
|
||||
SigtimedwaitTest.IgnoredMaskedSignal
|
||||
|
|
@ -57,6 +57,7 @@ sigaction_test
|
|||
sigprocmask_test
|
||||
sigaltstack_test
|
||||
sigreturn_test
|
||||
sigtimedwait_test
|
||||
|
||||
# 其他测试
|
||||
itimer_test
|
||||
|
|
|
|||
Loading…
Reference in New Issue