Skip to content

Commit cb62374

Browse files
authored
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 <[email protected]>
1 parent a69dad1 commit cb62374

File tree

6 files changed

+33
-19
lines changed

6 files changed

+33
-19
lines changed

kernel/src/arch/x86_64/asm/entry.S

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,11 @@ ENTRY(syscall_64)
407407
popq %rax
408408
addq $0x10, %rsp // 弹出变量FUNC和errcode
409409

410+
cmpq (%rsp), %rcx
411+
jne .L_syscall_must_use_iret
412+
cmpq 0x10(%rsp), %r11
413+
jne .L_syscall_must_use_iret
414+
410415
popq %rcx // pop rip到rcx
411416

412417
addq $0x8, %rsp // 弹出cs
@@ -415,3 +420,9 @@ ENTRY(syscall_64)
415420

416421
swapgs
417422
sysretq
423+
424+
// 适用于 sigreturn, ptrace, 或任何修改了上下文的情况
425+
// 此时栈结构完美符合 iretq 要求: [RIP, CS, RFLAGS, RSP, SS]
426+
.L_syscall_must_use_iret:
427+
swapgs
428+
iretq

kernel/src/ipc/syscall/sys_rt_sigtimedwait.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,12 @@ pub fn do_kernel_rt_sigtimedwait(
5858
let reader = UserBufferReader::new(uthese, size_of::<SigSet>(), from_user)?;
5959
let sigset = reader.read_one_from_user::<SigSet>(0)?;
6060
// 移除不可屏蔽的信号(SIGKILL 和 SIGSTOP)
61-
let sigset_val: SigSet = SigSet::from_bits(sigset.bits()).ok_or(SystemError::EINVAL)?;
62-
let kill_stop_mask: SigSet =
63-
SigSet::from_bits_truncate((Signal::SIGKILL as u64) | (Signal::SIGSTOP as u64));
64-
let result = sigset_val & !kill_stop_mask;
65-
66-
result
61+
let mut sigset_val = SigSet::from_bits(sigset.bits()).ok_or(SystemError::EINVAL)?;
62+
sigset_val.remove(SigSet::from(Signal::SIGKILL));
63+
sigset_val.remove(SigSet::from(Signal::SIGSTOP));
64+
sigset_val
6765
};
6866

69-
// 如果信号集合为空,直接返回 EINVAL(根据 POSIX 标准)
70-
if these.is_empty() {
71-
return Err(SystemError::EINVAL);
72-
}
73-
7467
// 构造等待/屏蔽语义:与Linux一致
7568
// - 等待集合 these
7669
// - 临时屏蔽集合 = 旧blocked ∪ these(将这些信号作为masked的常规语义,但仍由本系统调用专门消费)
@@ -134,13 +127,21 @@ pub fn do_kernel_rt_sigtimedwait(
134127
}
135128
}
136129

137-
// 第四步:释放中断,然后真正进入调度睡眠(窗口期内,线程保持可中断阻塞,发送侧会唤醒)
130+
// 第四步:检查是否有其他未屏蔽的待处理信号打断,若被其他信号唤醒了,必须返回 EINTR 让内核去处理那个信号
131+
pcb.recalc_sigpending(None);
132+
if pcb.has_pending_signal_fast() {
133+
drop(preempt_guard);
134+
restore_saved_sigmask();
135+
return Err(SystemError::EINTR);
136+
}
138137

138+
// 第五步:释放中断,然后真正进入调度睡眠(窗口期内,线程保持可中断阻塞,发送侧会唤醒)
139139
// 计算剩余等待时间
140140
let remaining_time = if let Some(deadline) = deadline {
141141
let now = PosixTimeSpec::now();
142142
let remaining = deadline.total_nanos() - now.total_nanos();
143143
if remaining <= 0 {
144+
drop(preempt_guard);
144145
restore_saved_sigmask();
145146
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
146147
}

kernel/src/sched/cputime.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,15 @@ impl CpuTimeFunc {
8888
return;
8989
}
9090

91+
let accounted_cputime = cputime - other;
92+
9193
if user_tick {
92-
pcb.account_utime(cputime);
94+
pcb.account_utime(accounted_cputime);
9395
} else {
94-
pcb.account_stime(cputime);
96+
pcb.account_stime(accounted_cputime);
9597
}
96-
pcb.add_sum_exec_runtime(cputime);
98+
pcb.add_sum_exec_runtime(accounted_cputime);
9799

98-
let cputime_ns = TICK_NESC as u64 * ticks;
99-
let accounted_cputime = cputime_ns - other;
100100
// 检查并处理CPU时间定时器
101101
let mut itimers = pcb.itimers_irqsave();
102102
// 处理 ITIMER_VIRTUAL (仅在用户态tick时消耗时间)

user/apps/tests/syscall/gvisor/blocklists/sigreturn_test

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# getpid() 好像有点问题,还在修
2+
SigtimedwaitTest.IgnoredUnmaskedSignal
3+
SigtimedwaitTest.IgnoredMaskedSignal

user/apps/tests/syscall/gvisor/whitelist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ sigaction_test
5757
sigprocmask_test
5858
sigaltstack_test
5959
sigreturn_test
60+
sigtimedwait_test
6061

6162
# 其他测试
6263
itimer_test

0 commit comments

Comments
 (0)