Skip to content

Commit fa4d785

Browse files
authored
feat(kernel/posix-timer): 实现 POSIX interval timer,修复 gVisor timers_test (#1501)
- 新增 timer_create/timer_settime/timer_gettime/timer_getoverrun/timer_delete 系统调用处理,并接入 syscall table - 实现进程级 POSIX interval timer:基于 CLOCK_MONOTONIC 的创建/删除/设置/查询、周期性重装与到期调度 - 完整实现 SIGEV_NONE/SIGEV_SIGNAL/SIGEV_THREAD_ID(限制 THREAD_ID 只能指向当前线程)与 SI_TIMER siginfo(含 si_timerid/si_overrun/si_value) - 修复 overrun 语义与信号合并:按线程 pending 队列合并并累积 overrun,避免重复入队导致进程被信号杀死 - 修复周期性 timer 的 gettime 剩余时间计算与回调窗口返回 0 的问题(PeriodicSilent) - 修复定时器回调中信号锁/队列访问导致的自锁死(PeriodicGroupDirectedSignal) - clear_child_tid/robust futex 相关用户内存访问改为异常表保护,并避免在失败时继续 futex 操作 Signed-off-by: longjin <[email protected]>
1 parent 601ba6d commit fa4d785

File tree

15 files changed

+989
-21
lines changed

15 files changed

+989
-21
lines changed

AGENTS.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# README for AI Agents
2+
3+
## 项目简介
4+
5+
DragonOS是一个面向云计算轻量化场景的,完全自主内核的,提供Linux二进制兼容性的64位操作系统,旨在为容器化工作负载提供轻量级、高性能的解决方案。
6+
7+
## 设计思想
8+
9+
- Linux兼容性:系统调用接口/procfs/sysfs/devfs等的行为应当符合Linux语义。参考Linux 6.6的行为进行实现。
10+
- 轻量:简化复杂的抽象设计,保留合理的、简洁、符合Rust开发最佳实践的的抽象,提升系统性能。
11+
- 安全:注重内存安全、并发安全
12+
13+
14+
## 开发准则
15+
16+
### 项目目录结构:
17+
18+
- 文档:在`docs/`目录下
19+
- 内核:在`kernel/`目录下
20+
- 自行编写的单元测试程序:在`user/apps/c_unitest`目录下
21+
- gvisor系统调用测试程序:根据用户给出的程序代码片段来读取测试代码。如果用户没有提供,就尝试寻找,如果找不到,则从 https://cnb.cool/DragonOS-Community/gvisor/-/tree/dragonos/release-20250616.0/test/syscalls/linux 下面获取(下载文件然后再尝试读取)
22+
23+
24+
### 开发最佳实践
25+
26+
- 三思而后行!深度研究,掌握解决问题所必要的信息,然后再动手开发/修复。
27+
- 设计要具有合理抽象,避免过度抽象。并且要注意代码复用。
28+
- 实现代码的时候,多问问自己:这代码写在这里合理吗?(架构、正确性等方面)
29+
- 高内聚、低耦合
30+
- 符合Linux语义
31+
- 不得使用workaround的方法绕过问题。要从本质解决问题!
32+
33+
34+
**测试修复相关**
35+
36+
- 符合Linux 6.6的语义
37+
- 结合测例报错、测例代码、DragonOS代码、Linux行为实现来深入分析
38+
39+
### 开发时的一些常见命令
40+
41+
- 格式化代码:在项目根目录下运行`make fmt`,会自动格式化,并且运行clippy检查
42+
- 编译内核:在项目根目录下运行`make kernel`. 当你想检查你编辑的代码有没有语法错误的时候,请执行这个命令
43+
44+

kernel/src/arch/x86_64/mm/fault.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,8 @@ impl X86_64MMArch {
337337
if vm_flags.contains(VmFlags::VM_GROWSDOWN) {
338338
if !space_guard.can_extend_stack(region.start() - address) {
339339
// exceeds stack limit
340-
log::error!(
341-
"pid {} stack limit exceeded, error_code: {:?}, address: {:#x}",
340+
log::warn!(
341+
"pid {} user stack limit exceeded, error_code: {:?}, address: {:#x}",
342342
ProcessManager::current_pid().data(),
343343
error_code,
344344
address.data(),

kernel/src/ipc/sighand.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use system_error::SystemError;
77

88
use crate::{
99
arch::ipc::signal::{SigFlags, SigSet, Signal, MAX_SIG_NUM},
10-
ipc::signal_types::{SaHandlerType, SigInfo, SigPending, SigactionType, SignalFlags},
10+
ipc::signal_types::{SaHandlerType, SigCode, SigInfo, SigPending, SigactionType, SignalFlags},
1111
libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
1212
process::{
1313
pid::{Pid, PidType},
@@ -95,6 +95,54 @@ impl SigHand {
9595
g.shared_pending.queue().find(sig).0.is_some()
9696
}
9797

98+
/// 查找并判断 shared pending 队列中是否已存在指定 timerid 的 POSIX timer 信号。
99+
pub fn shared_pending_posix_timer_exists(&self, sig: Signal, timerid: i32) -> bool {
100+
let mut g = self.inner_mut();
101+
for info in g.shared_pending.queue_mut().q.iter_mut() {
102+
// bump(0) 作为“匹配探测”,不会改变值
103+
if info.is_signal(sig)
104+
&& info.sig_code() == SigCode::Timer
105+
&& info.bump_posix_timer_overrun(timerid, 0)
106+
{
107+
return true;
108+
}
109+
}
110+
false
111+
}
112+
113+
/// 若 shared pending 中已存在该 timer 的信号,则将其 si_overrun 增加 bump,并返回 true。
114+
pub fn shared_pending_posix_timer_bump_overrun(
115+
&self,
116+
sig: Signal,
117+
timerid: i32,
118+
bump: i32,
119+
) -> bool {
120+
let mut g = self.inner_mut();
121+
for info in g.shared_pending.queue_mut().q.iter_mut() {
122+
if info.is_signal(sig)
123+
&& info.sig_code() == SigCode::Timer
124+
&& info.bump_posix_timer_overrun(timerid, bump)
125+
{
126+
return true;
127+
}
128+
}
129+
false
130+
}
131+
132+
/// 将 shared pending 中属于该 timer 的信号的 si_overrun 重置为 0(若找到则返回 true)。
133+
pub fn shared_pending_posix_timer_reset_overrun(&self, sig: Signal, timerid: i32) -> bool {
134+
let mut g = self.inner_mut();
135+
for info in g.shared_pending.queue_mut().q.iter_mut() {
136+
if info.is_signal(sig)
137+
&& info.sig_code() == SigCode::Timer
138+
&& info.reset_posix_timer_overrun(timerid)
139+
{
140+
return true;
141+
}
142+
}
143+
false
144+
}
145+
98146
pub fn shared_pending_dequeue(&self, sig_mask: &SigSet) -> (Signal, Option<SigInfo>) {
99147
let mut g = self.inner_mut();
100148
g.shared_pending.dequeue_signal(sig_mask)

kernel/src/ipc/signal_types.rs

Lines changed: 153 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616

1717
/// siginfo中的si_code的可选值
1818
/// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态
19-
#[derive(Copy, Debug, Clone)]
19+
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
2020
#[repr(i32)]
2121
pub enum SigCode {
2222
/// sent by kill, sigsend, raise
@@ -394,13 +394,48 @@ pub struct PosixSiginfoSigsys {
394394
pub _arch: u32,
395395
}
396396

397+
/// 标准 POSIX sigval_t(union)。
398+
///
399+
/// 用户态会通过 `si_int` / `si_ptr` 访问同一片内存,因此必须是 union,且大小应为 8 字节。
397400
#[repr(C)]
398-
#[derive(Copy, Clone, Debug)]
399-
pub struct PosixSigval {
401+
#[derive(Copy, Clone)]
402+
pub union PosixSigval {
400403
pub sival_int: i32,
401404
pub sival_ptr: u64,
402405
}
403406

407+
impl PosixSigval {
408+
#[inline(always)]
409+
pub const fn from_int(v: i32) -> Self {
410+
Self { sival_int: v }
411+
}
412+
413+
#[inline(always)]
414+
pub const fn from_ptr(v: u64) -> Self {
415+
Self { sival_ptr: v }
416+
}
417+
418+
#[inline(always)]
419+
pub const fn zero() -> Self {
420+
Self { sival_ptr: 0 }
421+
}
422+
}
423+
424+
impl core::fmt::Debug for PosixSigval {
425+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
426+
// union:同时以 int/ptr 两种视角打印,便于调试
427+
let as_int = unsafe { self.sival_int };
428+
let as_ptr = unsafe { self.sival_ptr };
429+
f.debug_struct("PosixSigval")
430+
.field("sival_int", &as_int)
431+
.field("sival_ptr", &as_ptr)
432+
.finish()
433+
}
434+
}
435+
436+
// 编译期校验:sigval_t 在 64-bit 架构下应为 8 字节
437+
const _: [(); 8] = [(); core::mem::size_of::<PosixSigval>()];
438+
404439
/// 获取当前进程的UID
405440
fn get_current_uid() -> u32 {
406441
ProcessManager::current_pcb().cred().uid.data() as u32
@@ -411,10 +446,59 @@ impl SigInfo {
411446
self.sig_code
412447
}
413448

449+
#[inline(always)]
450+
pub fn signo_i32(&self) -> i32 {
451+
self.sig_no
452+
}
453+
454+
#[inline(always)]
455+
pub fn is_signal(&self, sig: Signal) -> bool {
456+
self.sig_no == sig as i32
457+
}
458+
414459
pub fn set_sig_type(&mut self, sig_type: SigType) {
415460
self.sig_type = sig_type;
416461
}
417462

463+
/// 若该 SigInfo 为指定 timerid 的 POSIX timer 信号,则将其 si_overrun 增加 bump,并返回 true。
464+
pub fn bump_posix_timer_overrun(&mut self, timerid: i32, bump: i32) -> bool {
465+
match self.sig_type {
466+
SigType::PosixTimer {
467+
timerid: tid,
468+
overrun,
469+
sigval,
470+
} if tid == timerid => {
471+
let new_overrun = overrun.saturating_add(bump);
472+
self.sig_type = SigType::PosixTimer {
473+
timerid: tid,
474+
overrun: new_overrun,
475+
sigval,
476+
};
477+
true
478+
}
479+
_ => false,
480+
}
481+
}
482+
483+
/// 若该 SigInfo 为指定 timerid 的 POSIX timer 信号,则将其 si_overrun 重置为 0,并返回 true。
484+
pub fn reset_posix_timer_overrun(&mut self, timerid: i32) -> bool {
485+
match self.sig_type {
486+
SigType::PosixTimer {
487+
timerid: tid,
488+
overrun: _,
489+
sigval,
490+
} if tid == timerid => {
491+
self.sig_type = SigType::PosixTimer {
492+
timerid: tid,
493+
overrun: 0,
494+
sigval,
495+
};
496+
true
497+
}
498+
_ => false,
499+
}
500+
}
501+
418502
/// 将内核SigInfo转换为标准PosixSigInfo
419503
#[inline(never)]
420504
pub fn convert_to_posix_siginfo(&self) -> PosixSigInfo {
@@ -438,10 +522,23 @@ impl SigInfo {
438522
_timer: PosixSiginfoTimer {
439523
si_tid: pid.data() as i32,
440524
si_overrun: 0,
441-
si_sigval: PosixSigval {
442-
sival_int: 0,
443-
sival_ptr: 0,
444-
},
525+
si_sigval: PosixSigval::zero(),
526+
},
527+
},
528+
},
529+
SigType::PosixTimer {
530+
timerid,
531+
overrun,
532+
sigval,
533+
} => PosixSigInfo {
534+
si_signo: self.sig_no,
535+
si_errno: self.errno,
536+
si_code: self.sig_code as i32,
537+
_sifields: PosixSiginfoFields {
538+
_timer: PosixSiginfoTimer {
539+
si_tid: timerid,
540+
si_overrun: overrun,
541+
si_sigval: sigval,
445542
},
446543
},
447544
},
@@ -475,6 +572,15 @@ impl SigInfo {
475572
pub enum SigType {
476573
Kill(RawPid),
477574
Alarm(RawPid),
575+
/// POSIX interval timer 发送的信号(SI_TIMER)。
576+
/// - `timerid`: 对应用户态 `siginfo_t::si_timerid`
577+
/// - `overrun`: 对应用户态 `siginfo_t::si_overrun`
578+
/// - `sigval`: 对应用户态 `siginfo_t::si_value`
579+
PosixTimer {
580+
timerid: i32,
581+
overrun: i32,
582+
sigval: PosixSigval,
583+
},
478584
// 后续完善下列中的具体字段
479585
// Timer,
480586
// Rt,
@@ -519,6 +625,46 @@ impl SigPending {
519625
&mut self.queue
520626
}
521627

628+
/// 在当前线程 pending 队列中判断是否已存在指定 timerid 的 POSIX timer 信号。
629+
pub fn posix_timer_exists(&mut self, sig: Signal, timerid: i32) -> bool {
630+
for info in self.queue.q.iter_mut() {
631+
// bump(0) 作为“匹配探测”,不会改变值
632+
if info.is_signal(sig)
633+
&& info.sig_code() == SigCode::Timer
634+
&& info.bump_posix_timer_overrun(timerid, 0)
635+
{
636+
return true;
637+
}
638+
}
639+
false
640+
}
641+
642+
/// 若当前线程 pending 队列中已存在该 timer 的信号,则将其 si_overrun 增加 bump,并返回 true。
643+
pub fn posix_timer_bump_overrun(&mut self, sig: Signal, timerid: i32, bump: i32) -> bool {
644+
for info in self.queue.q.iter_mut() {
645+
if info.is_signal(sig)
646+
&& info.sig_code() == SigCode::Timer
647+
&& info.bump_posix_timer_overrun(timerid, bump)
648+
{
649+
return true;
650+
}
651+
}
652+
false
653+
}
654+
655+
/// 将当前线程 pending 队列中属于该 timer 的信号的 si_overrun 重置为 0(若找到则返回 true)。
656+
pub fn posix_timer_reset_overrun(&mut self, sig: Signal, timerid: i32) -> bool {
657+
for info in self.queue.q.iter_mut() {
658+
if info.is_signal(sig)
659+
&& info.sig_code() == SigCode::Timer
660+
&& info.reset_posix_timer_overrun(timerid)
661+
{
662+
return true;
663+
}
664+
}
665+
false
666+
}
667+
522668
pub fn signal_mut(&mut self) -> &mut SigSet {
523669
&mut self.signal
524670
}

kernel/src/libs/futex/futex.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,10 @@ impl RobustListHead {
828828
mem::size_of::<PosixRobustListHead>(),
829829
true,
830830
)?;
831-
let robust_list_head = *user_buffer_reader.read_one_from_user::<PosixRobustListHead>(0)?;
831+
// 使用异常表保护读取,避免用户地址缺页/无效导致内核崩溃
832+
let robust_list_head = user_buffer_reader
833+
.buffer_protected(0)?
834+
.read_one::<PosixRobustListHead>(0)?;
832835
let robust_list_head = RobustListHead {
833836
posix: robust_list_head,
834837
uaddr: head_uaddr,
@@ -881,7 +884,10 @@ impl RobustListHead {
881884
core::mem::size_of::<usize>(),
882885
true,
883886
)?;
884-
user_writer.copy_one_to_user(&mem::size_of::<PosixRobustListHead>(), 0)?;
887+
// 使用异常表保护写回
888+
user_writer
889+
.buffer_protected(0)?
890+
.write_one::<usize>(0, &mem::size_of::<PosixRobustListHead>())?;
885891

886892
// 获取当前线程的robust list head
887893
let robust_list_head_opt = *pcb.get_robust_list();
@@ -896,7 +902,10 @@ impl RobustListHead {
896902
mem::size_of::<usize>(),
897903
true,
898904
)?;
899-
user_writer.copy_one_to_user(&head_uaddr, 0)?;
905+
// 使用异常表保护写回
906+
user_writer
907+
.buffer_protected(0)?
908+
.write_one::<usize>(0, &head_uaddr)?;
900909

901910
return Ok(0);
902911
}
@@ -927,8 +936,11 @@ impl RobustListHead {
927936
}
928937
};
929938

930-
let posix_head = match user_buffer_reader.read_one_from_user::<PosixRobustListHead>(0) {
931-
Ok(head) => *head,
939+
let posix_head = match user_buffer_reader
940+
.buffer_protected(0)
941+
.and_then(|b| b.read_one::<PosixRobustListHead>(0))
942+
{
943+
Ok(head) => head,
932944
Err(_) => {
933945
return;
934946
}
@@ -967,8 +979,9 @@ impl RobustListHead {
967979

968980
/// # 安全地从用户空间读取u32值,如果地址无效则返回None
969981
fn safe_read_u32(addr: VirtAddr) -> Option<u32> {
970-
Self::safe_read::<u32>(addr)
971-
.and_then(|reader| reader.read_one_from_user::<u32>(0).ok().cloned())
982+
let reader =
983+
UserBufferReader::new(addr.as_ptr::<u32>(), core::mem::size_of::<u32>(), true).ok()?;
984+
reader.buffer_protected(0).ok()?.read_one::<u32>(0).ok()
972985
}
973986

974987
/// # 处理进程即将死亡时,进程已经持有的futex,唤醒其他等待该futex的线程

0 commit comments

Comments
 (0)