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 <longjin@DragonOS.org>
This commit is contained in:
parent
601ba6d092
commit
fa4d785eaa
|
|
@ -0,0 +1,44 @@
|
|||
# README for AI Agents
|
||||
|
||||
## 项目简介
|
||||
|
||||
DragonOS是一个面向云计算轻量化场景的,完全自主内核的,提供Linux二进制兼容性的64位操作系统,旨在为容器化工作负载提供轻量级、高性能的解决方案。
|
||||
|
||||
## 设计思想
|
||||
|
||||
- Linux兼容性:系统调用接口/procfs/sysfs/devfs等的行为应当符合Linux语义。参考Linux 6.6的行为进行实现。
|
||||
- 轻量:简化复杂的抽象设计,保留合理的、简洁、符合Rust开发最佳实践的的抽象,提升系统性能。
|
||||
- 安全:注重内存安全、并发安全
|
||||
|
||||
|
||||
## 开发准则
|
||||
|
||||
### 项目目录结构:
|
||||
|
||||
- 文档:在`docs/`目录下
|
||||
- 内核:在`kernel/`目录下
|
||||
- 自行编写的单元测试程序:在`user/apps/c_unitest`目录下
|
||||
- gvisor系统调用测试程序:根据用户给出的程序代码片段来读取测试代码。如果用户没有提供,就尝试寻找,如果找不到,则从 https://cnb.cool/DragonOS-Community/gvisor/-/tree/dragonos/release-20250616.0/test/syscalls/linux 下面获取(下载文件然后再尝试读取)
|
||||
|
||||
|
||||
### 开发最佳实践
|
||||
|
||||
- 三思而后行!深度研究,掌握解决问题所必要的信息,然后再动手开发/修复。
|
||||
- 设计要具有合理抽象,避免过度抽象。并且要注意代码复用。
|
||||
- 实现代码的时候,多问问自己:这代码写在这里合理吗?(架构、正确性等方面)
|
||||
- 高内聚、低耦合
|
||||
- 符合Linux语义
|
||||
- 不得使用workaround的方法绕过问题。要从本质解决问题!
|
||||
|
||||
|
||||
**测试修复相关**
|
||||
|
||||
- 符合Linux 6.6的语义
|
||||
- 结合测例报错、测例代码、DragonOS代码、Linux行为实现来深入分析
|
||||
|
||||
### 开发时的一些常见命令
|
||||
|
||||
- 格式化代码:在项目根目录下运行`make fmt`,会自动格式化,并且运行clippy检查
|
||||
- 编译内核:在项目根目录下运行`make kernel`. 当你想检查你编辑的代码有没有语法错误的时候,请执行这个命令
|
||||
|
||||
|
||||
|
|
@ -337,8 +337,8 @@ impl X86_64MMArch {
|
|||
if vm_flags.contains(VmFlags::VM_GROWSDOWN) {
|
||||
if !space_guard.can_extend_stack(region.start() - address) {
|
||||
// exceeds stack limit
|
||||
log::error!(
|
||||
"pid {} stack limit exceeded, error_code: {:?}, address: {:#x}",
|
||||
log::warn!(
|
||||
"pid {} user stack limit exceeded, error_code: {:?}, address: {:#x}",
|
||||
ProcessManager::current_pid().data(),
|
||||
error_code,
|
||||
address.data(),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use system_error::SystemError;
|
|||
|
||||
use crate::{
|
||||
arch::ipc::signal::{SigFlags, SigSet, Signal, MAX_SIG_NUM},
|
||||
ipc::signal_types::{SaHandlerType, SigInfo, SigPending, SigactionType, SignalFlags},
|
||||
ipc::signal_types::{SaHandlerType, SigCode, SigInfo, SigPending, SigactionType, SignalFlags},
|
||||
libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
process::{
|
||||
pid::{Pid, PidType},
|
||||
|
|
@ -95,6 +95,54 @@ impl SigHand {
|
|||
g.shared_pending.queue().find(sig).0.is_some()
|
||||
}
|
||||
|
||||
/// 查找并判断 shared pending 队列中是否已存在指定 timerid 的 POSIX timer 信号。
|
||||
pub fn shared_pending_posix_timer_exists(&self, sig: Signal, timerid: i32) -> bool {
|
||||
let mut g = self.inner_mut();
|
||||
for info in g.shared_pending.queue_mut().q.iter_mut() {
|
||||
// bump(0) 作为“匹配探测”,不会改变值
|
||||
if info.is_signal(sig)
|
||||
&& info.sig_code() == SigCode::Timer
|
||||
&& info.bump_posix_timer_overrun(timerid, 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// 若 shared pending 中已存在该 timer 的信号,则将其 si_overrun 增加 bump,并返回 true。
|
||||
pub fn shared_pending_posix_timer_bump_overrun(
|
||||
&self,
|
||||
sig: Signal,
|
||||
timerid: i32,
|
||||
bump: i32,
|
||||
) -> bool {
|
||||
let mut g = self.inner_mut();
|
||||
for info in g.shared_pending.queue_mut().q.iter_mut() {
|
||||
if info.is_signal(sig)
|
||||
&& info.sig_code() == SigCode::Timer
|
||||
&& info.bump_posix_timer_overrun(timerid, bump)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// 将 shared pending 中属于该 timer 的信号的 si_overrun 重置为 0(若找到则返回 true)。
|
||||
pub fn shared_pending_posix_timer_reset_overrun(&self, sig: Signal, timerid: i32) -> bool {
|
||||
let mut g = self.inner_mut();
|
||||
for info in g.shared_pending.queue_mut().q.iter_mut() {
|
||||
if info.is_signal(sig)
|
||||
&& info.sig_code() == SigCode::Timer
|
||||
&& info.reset_posix_timer_overrun(timerid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn shared_pending_dequeue(&self, sig_mask: &SigSet) -> (Signal, Option<SigInfo>) {
|
||||
let mut g = self.inner_mut();
|
||||
g.shared_pending.dequeue_signal(sig_mask)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
|
||||
/// siginfo中的si_code的可选值
|
||||
/// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态
|
||||
#[derive(Copy, Debug, Clone)]
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum SigCode {
|
||||
/// sent by kill, sigsend, raise
|
||||
|
|
@ -394,13 +394,48 @@ pub struct PosixSiginfoSigsys {
|
|||
pub _arch: u32,
|
||||
}
|
||||
|
||||
/// 标准 POSIX sigval_t(union)。
|
||||
///
|
||||
/// 用户态会通过 `si_int` / `si_ptr` 访问同一片内存,因此必须是 union,且大小应为 8 字节。
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PosixSigval {
|
||||
#[derive(Copy, Clone)]
|
||||
pub union PosixSigval {
|
||||
pub sival_int: i32,
|
||||
pub sival_ptr: u64,
|
||||
}
|
||||
|
||||
impl PosixSigval {
|
||||
#[inline(always)]
|
||||
pub const fn from_int(v: i32) -> Self {
|
||||
Self { sival_int: v }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn from_ptr(v: u64) -> Self {
|
||||
Self { sival_ptr: v }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn zero() -> Self {
|
||||
Self { sival_ptr: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for PosixSigval {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
// union:同时以 int/ptr 两种视角打印,便于调试
|
||||
let as_int = unsafe { self.sival_int };
|
||||
let as_ptr = unsafe { self.sival_ptr };
|
||||
f.debug_struct("PosixSigval")
|
||||
.field("sival_int", &as_int)
|
||||
.field("sival_ptr", &as_ptr)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// 编译期校验:sigval_t 在 64-bit 架构下应为 8 字节
|
||||
const _: [(); 8] = [(); core::mem::size_of::<PosixSigval>()];
|
||||
|
||||
/// 获取当前进程的UID
|
||||
fn get_current_uid() -> u32 {
|
||||
ProcessManager::current_pcb().cred().uid.data() as u32
|
||||
|
|
@ -411,10 +446,59 @@ impl SigInfo {
|
|||
self.sig_code
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn signo_i32(&self) -> i32 {
|
||||
self.sig_no
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_signal(&self, sig: Signal) -> bool {
|
||||
self.sig_no == sig as i32
|
||||
}
|
||||
|
||||
pub fn set_sig_type(&mut self, sig_type: SigType) {
|
||||
self.sig_type = sig_type;
|
||||
}
|
||||
|
||||
/// 若该 SigInfo 为指定 timerid 的 POSIX timer 信号,则将其 si_overrun 增加 bump,并返回 true。
|
||||
pub fn bump_posix_timer_overrun(&mut self, timerid: i32, bump: i32) -> bool {
|
||||
match self.sig_type {
|
||||
SigType::PosixTimer {
|
||||
timerid: tid,
|
||||
overrun,
|
||||
sigval,
|
||||
} if tid == timerid => {
|
||||
let new_overrun = overrun.saturating_add(bump);
|
||||
self.sig_type = SigType::PosixTimer {
|
||||
timerid: tid,
|
||||
overrun: new_overrun,
|
||||
sigval,
|
||||
};
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 若该 SigInfo 为指定 timerid 的 POSIX timer 信号,则将其 si_overrun 重置为 0,并返回 true。
|
||||
pub fn reset_posix_timer_overrun(&mut self, timerid: i32) -> bool {
|
||||
match self.sig_type {
|
||||
SigType::PosixTimer {
|
||||
timerid: tid,
|
||||
overrun: _,
|
||||
sigval,
|
||||
} if tid == timerid => {
|
||||
self.sig_type = SigType::PosixTimer {
|
||||
timerid: tid,
|
||||
overrun: 0,
|
||||
sigval,
|
||||
};
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 将内核SigInfo转换为标准PosixSigInfo
|
||||
#[inline(never)]
|
||||
pub fn convert_to_posix_siginfo(&self) -> PosixSigInfo {
|
||||
|
|
@ -438,10 +522,23 @@ impl SigInfo {
|
|||
_timer: PosixSiginfoTimer {
|
||||
si_tid: pid.data() as i32,
|
||||
si_overrun: 0,
|
||||
si_sigval: PosixSigval {
|
||||
sival_int: 0,
|
||||
sival_ptr: 0,
|
||||
},
|
||||
si_sigval: PosixSigval::zero(),
|
||||
},
|
||||
},
|
||||
},
|
||||
SigType::PosixTimer {
|
||||
timerid,
|
||||
overrun,
|
||||
sigval,
|
||||
} => PosixSigInfo {
|
||||
si_signo: self.sig_no,
|
||||
si_errno: self.errno,
|
||||
si_code: self.sig_code as i32,
|
||||
_sifields: PosixSiginfoFields {
|
||||
_timer: PosixSiginfoTimer {
|
||||
si_tid: timerid,
|
||||
si_overrun: overrun,
|
||||
si_sigval: sigval,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -475,6 +572,15 @@ impl SigInfo {
|
|||
pub enum SigType {
|
||||
Kill(RawPid),
|
||||
Alarm(RawPid),
|
||||
/// POSIX interval timer 发送的信号(SI_TIMER)。
|
||||
/// - `timerid`: 对应用户态 `siginfo_t::si_timerid`
|
||||
/// - `overrun`: 对应用户态 `siginfo_t::si_overrun`
|
||||
/// - `sigval`: 对应用户态 `siginfo_t::si_value`
|
||||
PosixTimer {
|
||||
timerid: i32,
|
||||
overrun: i32,
|
||||
sigval: PosixSigval,
|
||||
},
|
||||
// 后续完善下列中的具体字段
|
||||
// Timer,
|
||||
// Rt,
|
||||
|
|
@ -519,6 +625,46 @@ impl SigPending {
|
|||
&mut self.queue
|
||||
}
|
||||
|
||||
/// 在当前线程 pending 队列中判断是否已存在指定 timerid 的 POSIX timer 信号。
|
||||
pub fn posix_timer_exists(&mut self, sig: Signal, timerid: i32) -> bool {
|
||||
for info in self.queue.q.iter_mut() {
|
||||
// bump(0) 作为“匹配探测”,不会改变值
|
||||
if info.is_signal(sig)
|
||||
&& info.sig_code() == SigCode::Timer
|
||||
&& info.bump_posix_timer_overrun(timerid, 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// 若当前线程 pending 队列中已存在该 timer 的信号,则将其 si_overrun 增加 bump,并返回 true。
|
||||
pub fn posix_timer_bump_overrun(&mut self, sig: Signal, timerid: i32, bump: i32) -> bool {
|
||||
for info in self.queue.q.iter_mut() {
|
||||
if info.is_signal(sig)
|
||||
&& info.sig_code() == SigCode::Timer
|
||||
&& info.bump_posix_timer_overrun(timerid, bump)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// 将当前线程 pending 队列中属于该 timer 的信号的 si_overrun 重置为 0(若找到则返回 true)。
|
||||
pub fn posix_timer_reset_overrun(&mut self, sig: Signal, timerid: i32) -> bool {
|
||||
for info in self.queue.q.iter_mut() {
|
||||
if info.is_signal(sig)
|
||||
&& info.sig_code() == SigCode::Timer
|
||||
&& info.reset_posix_timer_overrun(timerid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn signal_mut(&mut self) -> &mut SigSet {
|
||||
&mut self.signal
|
||||
}
|
||||
|
|
|
|||
|
|
@ -828,7 +828,10 @@ impl RobustListHead {
|
|||
mem::size_of::<PosixRobustListHead>(),
|
||||
true,
|
||||
)?;
|
||||
let robust_list_head = *user_buffer_reader.read_one_from_user::<PosixRobustListHead>(0)?;
|
||||
// 使用异常表保护读取,避免用户地址缺页/无效导致内核崩溃
|
||||
let robust_list_head = user_buffer_reader
|
||||
.buffer_protected(0)?
|
||||
.read_one::<PosixRobustListHead>(0)?;
|
||||
let robust_list_head = RobustListHead {
|
||||
posix: robust_list_head,
|
||||
uaddr: head_uaddr,
|
||||
|
|
@ -881,7 +884,10 @@ impl RobustListHead {
|
|||
core::mem::size_of::<usize>(),
|
||||
true,
|
||||
)?;
|
||||
user_writer.copy_one_to_user(&mem::size_of::<PosixRobustListHead>(), 0)?;
|
||||
// 使用异常表保护写回
|
||||
user_writer
|
||||
.buffer_protected(0)?
|
||||
.write_one::<usize>(0, &mem::size_of::<PosixRobustListHead>())?;
|
||||
|
||||
// 获取当前线程的robust list head
|
||||
let robust_list_head_opt = *pcb.get_robust_list();
|
||||
|
|
@ -896,7 +902,10 @@ impl RobustListHead {
|
|||
mem::size_of::<usize>(),
|
||||
true,
|
||||
)?;
|
||||
user_writer.copy_one_to_user(&head_uaddr, 0)?;
|
||||
// 使用异常表保护写回
|
||||
user_writer
|
||||
.buffer_protected(0)?
|
||||
.write_one::<usize>(0, &head_uaddr)?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
|
@ -927,8 +936,11 @@ impl RobustListHead {
|
|||
}
|
||||
};
|
||||
|
||||
let posix_head = match user_buffer_reader.read_one_from_user::<PosixRobustListHead>(0) {
|
||||
Ok(head) => *head,
|
||||
let posix_head = match user_buffer_reader
|
||||
.buffer_protected(0)
|
||||
.and_then(|b| b.read_one::<PosixRobustListHead>(0))
|
||||
{
|
||||
Ok(head) => head,
|
||||
Err(_) => {
|
||||
return;
|
||||
}
|
||||
|
|
@ -967,8 +979,9 @@ impl RobustListHead {
|
|||
|
||||
/// # 安全地从用户空间读取u32值,如果地址无效则返回None
|
||||
fn safe_read_u32(addr: VirtAddr) -> Option<u32> {
|
||||
Self::safe_read::<u32>(addr)
|
||||
.and_then(|reader| reader.read_one_from_user::<u32>(0).ok().cloned())
|
||||
let reader =
|
||||
UserBufferReader::new(addr.as_ptr::<u32>(), core::mem::size_of::<u32>(), true).ok()?;
|
||||
reader.buffer_protected(0).ok()?.read_one::<u32>(0).ok()
|
||||
}
|
||||
|
||||
/// # 处理进程即将死亡时,进程已经持有的futex,唤醒其他等待该futex的线程
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ pub mod idle;
|
|||
pub mod kthread;
|
||||
pub mod namespace;
|
||||
pub mod pid;
|
||||
pub mod posix_timer;
|
||||
pub mod preempt;
|
||||
pub mod process_group;
|
||||
pub mod resource;
|
||||
|
|
@ -479,11 +480,20 @@ impl ProcessManager {
|
|||
|
||||
if let Some(addr) = thread.clear_child_tid {
|
||||
// 按 Linux 语义:先清零 userland 的 *clear_child_tid,再 futex_wake(addr)
|
||||
unsafe {
|
||||
clear_user_protected(addr, core::mem::size_of::<i32>())
|
||||
.expect("clear tid failed")
|
||||
let cleared_ok = unsafe {
|
||||
match clear_user_protected(addr, core::mem::size_of::<i32>()) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
// clear_child_tid 指针可能无效或已拆映射:不能因此 panic。
|
||||
warn!("clear tid failed: {e:?}");
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
if Arc::strong_count(&pcb.basic().user_vm().expect("User VM Not found")) > 1 {
|
||||
// 若无法清零 *clear_child_tid,则也不要 futex_wake(避免进一步的非法用户态访问)
|
||||
if cleared_ok
|
||||
&& Arc::strong_count(&pcb.basic().user_vm().expect("User VM Not found")) > 1
|
||||
{
|
||||
// Linux 使用 FUTEX_SHARED 标志来唤醒 clear_child_tid
|
||||
// 这允许跨进程/线程的同步(例如 pthread_join)
|
||||
let _ =
|
||||
|
|
@ -905,6 +915,8 @@ pub struct ProcessControlBlock {
|
|||
///闹钟定时器
|
||||
alarm_timer: SpinLock<Option<AlarmTimer>>,
|
||||
itimers: SpinLock<ProcessItimers>,
|
||||
/// POSIX interval timers(timer_create/timer_settime/...)
|
||||
posix_timers: SpinLock<posix_timer::ProcessPosixTimers>,
|
||||
|
||||
/// CPU时间片
|
||||
cpu_time: Arc<ProcessCpuTime>,
|
||||
|
|
@ -1040,6 +1052,7 @@ impl ProcessControlBlock {
|
|||
fs: RwLock::new(Arc::new(FsStruct::new())),
|
||||
alarm_timer: SpinLock::new(None),
|
||||
itimers: SpinLock::new(ProcessItimers::default()),
|
||||
posix_timers: SpinLock::new(posix_timer::ProcessPosixTimers::default()),
|
||||
cpu_time: Arc::new(ProcessCpuTime::default()),
|
||||
robust_list: RwLock::new(None),
|
||||
cred: SpinLock::new(cred),
|
||||
|
|
@ -1603,6 +1616,10 @@ impl ProcessControlBlock {
|
|||
return self.itimers.lock_irqsave();
|
||||
}
|
||||
|
||||
pub fn posix_timers_irqsave(&self) -> SpinLockGuard<'_, posix_timer::ProcessPosixTimers> {
|
||||
return self.posix_timers.lock_irqsave();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn cputime(&self) -> Arc<ProcessCpuTime> {
|
||||
return self.cpu_time.clone();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,406 @@
|
|||
//! POSIX interval timers (timer_create/timer_settime/...) for a process.
|
||||
//!
|
||||
//! This is a minimal-but-correct implementation for gVisor `timers.cc` tests:
|
||||
//! - CLOCK_MONOTONIC based timers
|
||||
//! - SIGEV_NONE / SIGEV_SIGNAL / SIGEV_THREAD_ID (thread id must be current thread)
|
||||
//! - coalescing: at most one pending signal per (signo,timerid); overruns accumulate
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::ipc::signal::Signal,
|
||||
ipc::signal_types::{PosixSigval, SigCode, SigInfo, SigType},
|
||||
process::{ProcessControlBlock, ProcessFlags, ProcessManager, RawPid},
|
||||
time::{
|
||||
jiffies::NSEC_PER_JIFFY,
|
||||
syscall::PosixClockID,
|
||||
timer::{clock, Jiffies, Timer, TimerFunction},
|
||||
PosixTimeSpec,
|
||||
},
|
||||
};
|
||||
|
||||
use core::{mem::size_of, time::Duration};
|
||||
|
||||
/// 用户态 itimerspec
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
pub struct PosixItimerspec {
|
||||
pub it_interval: PosixTimeSpec,
|
||||
pub it_value: PosixTimeSpec,
|
||||
}
|
||||
|
||||
/// 用户态 sigevent(Linux x86_64 下大小为 64B;这里保守定义为 64B)
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PosixSigevent {
|
||||
pub sigev_value: u64,
|
||||
pub sigev_signo: i32,
|
||||
pub sigev_notify: i32,
|
||||
pub sigev_notify_thread_id: i32,
|
||||
pub _pad: [u8; 44],
|
||||
}
|
||||
|
||||
const _: [(); 64] = [(); size_of::<PosixSigevent>()];
|
||||
|
||||
/// sigev_notify 常量(Linux)
|
||||
pub const SIGEV_SIGNAL: i32 = 0;
|
||||
pub const SIGEV_NONE: i32 = 1;
|
||||
pub const SIGEV_THREAD_ID: i32 = 4;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PosixTimerNotify {
|
||||
None,
|
||||
Signal {
|
||||
signo: Signal,
|
||||
sigval: PosixSigval,
|
||||
target_tid: RawPid,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PosixIntervalTimer {
|
||||
pub id: i32,
|
||||
pub clockid: PosixClockID,
|
||||
pub notify: PosixTimerNotify,
|
||||
pub interval: PosixTimeSpec,
|
||||
pub timer: Option<Arc<Timer>>,
|
||||
pub expire_jiffies: Option<u64>,
|
||||
pub pending_overrun_acc: i32,
|
||||
pub last_overrun: i32,
|
||||
}
|
||||
|
||||
impl PosixIntervalTimer {
|
||||
fn is_armed(&self) -> bool {
|
||||
self.timer.is_some() && self.expire_jiffies.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ProcessPosixTimers {
|
||||
next_id: i32,
|
||||
timers: HashMap<i32, PosixIntervalTimer>,
|
||||
}
|
||||
|
||||
impl ProcessPosixTimers {
|
||||
pub fn get_timer(&self, timerid: i32) -> Result<&PosixIntervalTimer, SystemError> {
|
||||
self.timers.get(&timerid).ok_or(SystemError::EINVAL)
|
||||
}
|
||||
|
||||
pub fn get_timer_mut(&mut self, timerid: i32) -> Result<&mut PosixIntervalTimer, SystemError> {
|
||||
self.timers.get_mut(&timerid).ok_or(SystemError::EINVAL)
|
||||
}
|
||||
|
||||
fn alloc_id(&mut self) -> i32 {
|
||||
// Linux timer_t 在用户态通常是 int;这里用递增 id,跳过 0。
|
||||
let mut id = self.next_id;
|
||||
if id <= 0 {
|
||||
id = 1;
|
||||
}
|
||||
loop {
|
||||
if !self.timers.contains_key(&id) {
|
||||
self.next_id = id.saturating_add(1);
|
||||
return id;
|
||||
}
|
||||
id = id.saturating_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
&mut self,
|
||||
pcb: &Arc<ProcessControlBlock>,
|
||||
clockid: PosixClockID,
|
||||
sev: Option<PosixSigevent>,
|
||||
) -> Result<i32, SystemError> {
|
||||
// gVisor tests only use CLOCK_MONOTONIC.
|
||||
if clockid != PosixClockID::Monotonic {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let sev = sev.unwrap_or(PosixSigevent {
|
||||
sigev_value: 0,
|
||||
sigev_signo: Signal::SIGALRM as i32,
|
||||
sigev_notify: SIGEV_SIGNAL,
|
||||
sigev_notify_thread_id: pcb.raw_pid().data() as i32,
|
||||
_pad: [0u8; 44],
|
||||
});
|
||||
|
||||
let notify = match sev.sigev_notify {
|
||||
SIGEV_NONE => PosixTimerNotify::None,
|
||||
SIGEV_SIGNAL => {
|
||||
let signo = Signal::from(sev.sigev_signo as usize);
|
||||
if !signo.is_valid() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
PosixTimerNotify::Signal {
|
||||
signo,
|
||||
sigval: PosixSigval::from_ptr(sev.sigev_value),
|
||||
target_tid: pcb.raw_pid(),
|
||||
}
|
||||
}
|
||||
SIGEV_THREAD_ID => {
|
||||
// 当前内核暂无完善的线程模型:只允许指定当前线程(tid)。
|
||||
let tid = RawPid::new(sev.sigev_notify_thread_id as usize);
|
||||
if tid != ProcessManager::current_pcb().raw_pid() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let signo = Signal::from(sev.sigev_signo as usize);
|
||||
if !signo.is_valid() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
PosixTimerNotify::Signal {
|
||||
signo,
|
||||
sigval: PosixSigval::from_ptr(sev.sigev_value),
|
||||
target_tid: tid,
|
||||
}
|
||||
}
|
||||
_ => return Err(SystemError::EINVAL),
|
||||
};
|
||||
|
||||
let id = self.alloc_id();
|
||||
self.timers.insert(
|
||||
id,
|
||||
PosixIntervalTimer {
|
||||
id,
|
||||
clockid,
|
||||
notify,
|
||||
interval: PosixTimeSpec::default(),
|
||||
timer: None,
|
||||
expire_jiffies: None,
|
||||
pending_overrun_acc: 0,
|
||||
last_overrun: 0,
|
||||
},
|
||||
);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn delete(
|
||||
&mut self,
|
||||
pcb: &Arc<ProcessControlBlock>,
|
||||
timerid: i32,
|
||||
) -> Result<(), SystemError> {
|
||||
let t = self.timers.remove(&timerid).ok_or(SystemError::EINVAL)?;
|
||||
if let Some(timer) = t.timer {
|
||||
timer.cancel();
|
||||
}
|
||||
// 删除/停用会将已排队的 SI_TIMER 的 overrun 重置为 0(与 tests 注释一致)
|
||||
if let PosixTimerNotify::Signal { signo, .. } = t.notify {
|
||||
pcb.sig_info_mut()
|
||||
.sig_pending_mut()
|
||||
.posix_timer_reset_overrun(signo, timerid);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn gettime(&self, timerid: i32) -> Result<PosixItimerspec, SystemError> {
|
||||
let t = self.get_timer(timerid)?;
|
||||
let mut out = PosixItimerspec {
|
||||
it_interval: t.interval,
|
||||
..Default::default()
|
||||
};
|
||||
if let Some(exp) = t.expire_jiffies {
|
||||
let now = clock();
|
||||
if exp > now {
|
||||
let remaining_j = exp - now;
|
||||
let remaining_ns: u64 = remaining_j.saturating_mul(NSEC_PER_JIFFY as u64);
|
||||
out.it_value = PosixTimeSpec {
|
||||
tv_sec: (remaining_ns / 1_000_000_000) as i64,
|
||||
tv_nsec: (remaining_ns % 1_000_000_000) as i64,
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn getoverrun(&self, timerid: i32) -> Result<i32, SystemError> {
|
||||
let t = self.get_timer(timerid)?;
|
||||
Ok(t.last_overrun)
|
||||
}
|
||||
|
||||
pub fn settime(
|
||||
&mut self,
|
||||
pcb: &Arc<ProcessControlBlock>,
|
||||
timerid: i32,
|
||||
new_value: PosixItimerspec,
|
||||
) -> Result<PosixItimerspec, SystemError> {
|
||||
let old = self.gettime(timerid)?;
|
||||
let t = self.get_timer_mut(timerid)?;
|
||||
|
||||
// 取消旧 timer
|
||||
if let Some(old_timer) = t.timer.take() {
|
||||
old_timer.cancel();
|
||||
}
|
||||
t.expire_jiffies = None;
|
||||
|
||||
// timer_settime 会重置 overrun(包含已排队信号的 overrun)
|
||||
t.pending_overrun_acc = 0;
|
||||
t.last_overrun = 0;
|
||||
if let PosixTimerNotify::Signal { signo, .. } = t.notify {
|
||||
pcb.sig_info_mut()
|
||||
.sig_pending_mut()
|
||||
.posix_timer_reset_overrun(signo, timerid);
|
||||
}
|
||||
|
||||
// 更新 interval
|
||||
validate_timespec(&new_value.it_interval)?;
|
||||
validate_timespec(&new_value.it_value)?;
|
||||
t.interval = new_value.it_interval;
|
||||
|
||||
// it_value 为 0 => disarm
|
||||
if new_value.it_value.is_empty() {
|
||||
return Ok(old);
|
||||
}
|
||||
|
||||
let delay = timespec_to_duration(&new_value.it_value)?;
|
||||
let expire_jiffies = clock() + <Jiffies as From<Duration>>::from(delay).data();
|
||||
|
||||
let helper = PosixTimerHelper::new(Arc::downgrade(pcb), timerid);
|
||||
let new_timer = Timer::new(helper, expire_jiffies);
|
||||
new_timer.activate();
|
||||
|
||||
t.expire_jiffies = Some(expire_jiffies);
|
||||
t.timer = Some(new_timer);
|
||||
Ok(old)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PosixTimerHelper {
|
||||
pcb: Weak<ProcessControlBlock>,
|
||||
timerid: i32,
|
||||
}
|
||||
|
||||
impl PosixTimerHelper {
|
||||
fn new(pcb: Weak<ProcessControlBlock>, timerid: i32) -> Box<Self> {
|
||||
Box::new(Self { pcb, timerid })
|
||||
}
|
||||
}
|
||||
|
||||
impl TimerFunction for PosixTimerHelper {
|
||||
fn run(&mut self) -> Result<(), SystemError> {
|
||||
let pcb = match self.pcb.upgrade() {
|
||||
Some(p) => p,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
// 在 softirq/timer 上下文执行:核心逻辑放在持锁区域内,避免并发打架。
|
||||
let mut timers = pcb.posix_timers_irqsave();
|
||||
let t = match timers.timers.get_mut(&self.timerid) {
|
||||
Some(t) => t,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
// 已经被 disarm/delete
|
||||
if !t.is_armed() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 周期性定时器:先重建下一次,避免 gettime() 在回调窗口看到 0(PeriodicSilent 期望仍在运行)
|
||||
let is_periodic = !t.interval.is_empty();
|
||||
if is_periodic {
|
||||
let interval = timespec_to_duration(&t.interval)?;
|
||||
let expire_jiffies = clock() + <Jiffies as From<Duration>>::from(interval).data();
|
||||
let helper = PosixTimerHelper::new(Arc::downgrade(&pcb), self.timerid);
|
||||
let next_timer = Timer::new(helper, expire_jiffies);
|
||||
next_timer.activate();
|
||||
t.expire_jiffies = Some(expire_jiffies);
|
||||
t.timer = Some(next_timer);
|
||||
} else {
|
||||
// one-shot:本次触发后应停止
|
||||
t.timer = None;
|
||||
t.expire_jiffies = None;
|
||||
}
|
||||
|
||||
match t.notify {
|
||||
PosixTimerNotify::None => {
|
||||
// 无信号
|
||||
}
|
||||
PosixTimerNotify::Signal {
|
||||
signo,
|
||||
sigval,
|
||||
target_tid,
|
||||
} => {
|
||||
// 注意:DragonOS 当前 signal 发送路径对非 RT 信号的“去重检查”是看 shared_pending,
|
||||
// 但实际入队在 per-thread pending,因此这里必须基于当前线程 pending 来做合并/overrun。
|
||||
let mut siginfo_guard = pcb.sig_info_mut();
|
||||
// 计算“是否未阻塞且 handler=SIG_IGN”,必须使用已持有的 siginfo_guard,
|
||||
// 否则在持有写锁时再次调用 pcb.sig_info_irqsave() 会造成自锁死(PeriodicGroupDirectedSignal 复现)。
|
||||
let ignored_and_unblocked = {
|
||||
let mut blocked = *siginfo_guard.sig_blocked();
|
||||
if pcb.flags().contains(ProcessFlags::RESTORE_SIG_MASK) {
|
||||
blocked.insert(*siginfo_guard.saved_sigmask());
|
||||
}
|
||||
let is_blocked = blocked.contains(signo.into_sigset());
|
||||
if is_blocked {
|
||||
false
|
||||
} else {
|
||||
pcb.sighand()
|
||||
.handler(signo)
|
||||
.map(|x| x.is_ignore())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
};
|
||||
let pending = siginfo_guard.sig_pending_mut();
|
||||
|
||||
// 1) 若已有该 timer 的信号:在队列项上累加 overrun
|
||||
if pending.posix_timer_exists(signo, self.timerid) {
|
||||
let bump = 1i32.saturating_add(t.pending_overrun_acc);
|
||||
t.pending_overrun_acc = 0;
|
||||
pending.posix_timer_bump_overrun(signo, self.timerid, bump);
|
||||
} else {
|
||||
// 2) 若 signo 已有其他来源的 pending(如 tgkill 提前排队):本次无法入队,记为 overrun
|
||||
if pending.queue().find(signo).0.is_some() {
|
||||
t.pending_overrun_acc = t.pending_overrun_acc.saturating_add(1);
|
||||
} else if ignored_and_unblocked {
|
||||
// 3) 未阻塞且 handler=SIG_IGN:Linux 语义下会丢弃;tests 期望这也计入 overrun
|
||||
t.pending_overrun_acc = t.pending_overrun_acc.saturating_add(1);
|
||||
} else {
|
||||
// 4) 可以入队:构造 SI_TIMER siginfo(确保只入队一次)
|
||||
let overrun = t.pending_overrun_acc;
|
||||
t.pending_overrun_acc = 0;
|
||||
t.last_overrun = overrun;
|
||||
|
||||
drop(siginfo_guard); // 避免在 send_signal 路径中再次取 sig_info 锁导致死锁
|
||||
|
||||
let mut info = SigInfo::new(
|
||||
signo,
|
||||
0,
|
||||
SigCode::Timer,
|
||||
SigType::PosixTimer {
|
||||
timerid: self.timerid,
|
||||
overrun,
|
||||
sigval,
|
||||
},
|
||||
);
|
||||
|
||||
// 当前实现:target_tid 必须属于当前进程;否则在 create 时已拒绝
|
||||
let target = ProcessManager::find_task_by_vpid(target_tid)
|
||||
.unwrap_or_else(|| pcb.clone());
|
||||
let _ = signo.send_signal_info_to_pcb(Some(&mut info), target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_timespec(ts: &PosixTimeSpec) -> Result<(), SystemError> {
|
||||
if ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= 1_000_000_000 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn timespec_to_duration(ts: &PosixTimeSpec) -> Result<Duration, SystemError> {
|
||||
validate_timespec(ts)?;
|
||||
Ok(Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32))
|
||||
}
|
||||
|
||||
// 注意:不要在持有 pcb.sig_info_mut() 写锁时调用任何会再次获取 sig_info_* 锁的函数,
|
||||
// 否则会造成自锁死。相关判断请在持锁区内使用已拿到的 guard 直接计算。
|
||||
|
|
@ -12,6 +12,11 @@ mod sys_getitimer;
|
|||
mod sys_gettimeofday;
|
||||
mod sys_nanosleep;
|
||||
mod sys_setitimer;
|
||||
mod sys_timer_create;
|
||||
mod sys_timer_delete;
|
||||
mod sys_timer_getoverrun;
|
||||
mod sys_timer_gettime;
|
||||
mod sys_timer_settime;
|
||||
|
||||
pub type PosixTimeT = c_longlong;
|
||||
pub type PosixSusecondsT = c_int;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
use crate::{
|
||||
arch::{interrupt::TrapFrame, syscall::nr::SYS_TIMER_CREATE},
|
||||
process::posix_timer::PosixSigevent,
|
||||
process::ProcessManager,
|
||||
syscall::{
|
||||
table::{FormattedSyscallParam, Syscall},
|
||||
user_access::{UserBufferReader, UserBufferWriter},
|
||||
},
|
||||
time::syscall::PosixClockID,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use core::mem::size_of;
|
||||
use syscall_table_macros::declare_syscall;
|
||||
use system_error::SystemError;
|
||||
|
||||
pub struct SysTimerCreateHandle;
|
||||
|
||||
impl SysTimerCreateHandle {
|
||||
fn clockid(args: &[usize]) -> Result<PosixClockID, SystemError> {
|
||||
PosixClockID::try_from(args[0] as i32)
|
||||
}
|
||||
fn sevp(args: &[usize]) -> *const PosixSigevent {
|
||||
args[1] as *const PosixSigevent
|
||||
}
|
||||
fn timeridp(args: &[usize]) -> *mut i32 {
|
||||
args[2] as *mut i32
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall for SysTimerCreateHandle {
|
||||
fn num_args(&self) -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||
let clockid = Self::clockid(args)?;
|
||||
let sevp = Self::sevp(args);
|
||||
let timeridp = Self::timeridp(args);
|
||||
|
||||
if timeridp.is_null() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
|
||||
let sev = if sevp.is_null() {
|
||||
None
|
||||
} else {
|
||||
let reader = UserBufferReader::new(sevp, size_of::<PosixSigevent>(), true)?;
|
||||
// 用异常表保护版本读取
|
||||
Some(reader.buffer_protected(0)?.read_one::<PosixSigevent>(0)?)
|
||||
};
|
||||
|
||||
let id = pcb.posix_timers_irqsave().create(&pcb, clockid, sev)?;
|
||||
|
||||
let mut writer = UserBufferWriter::new(timeridp, size_of::<i32>(), true)?;
|
||||
// 用异常表保护版本写回
|
||||
writer.buffer_protected(0)?.write_one::<i32>(0, &id)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("clockid", format!("{}", args[0])),
|
||||
FormattedSyscallParam::new("sevp", format!("{:#x}", args[1])),
|
||||
FormattedSyscallParam::new("timerid", format!("{:#x}", args[2])),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
declare_syscall!(SYS_TIMER_CREATE, SysTimerCreateHandle);
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
use crate::{
|
||||
arch::{interrupt::TrapFrame, syscall::nr::SYS_TIMER_DELETE},
|
||||
process::ProcessManager,
|
||||
syscall::table::{FormattedSyscallParam, Syscall},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use syscall_table_macros::declare_syscall;
|
||||
use system_error::SystemError;
|
||||
|
||||
pub struct SysTimerDeleteHandle;
|
||||
|
||||
impl SysTimerDeleteHandle {
|
||||
fn timerid(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall for SysTimerDeleteHandle {
|
||||
fn num_args(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||
let timerid = Self::timerid(args);
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
pcb.posix_timers_irqsave().delete(&pcb, timerid)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![FormattedSyscallParam::new(
|
||||
"timerid",
|
||||
format!("{}", args[0]),
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
declare_syscall!(SYS_TIMER_DELETE, SysTimerDeleteHandle);
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
use crate::{
|
||||
arch::{interrupt::TrapFrame, syscall::nr::SYS_TIMER_GETOVERRUN},
|
||||
process::ProcessManager,
|
||||
syscall::table::{FormattedSyscallParam, Syscall},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use syscall_table_macros::declare_syscall;
|
||||
use system_error::SystemError;
|
||||
|
||||
pub struct SysTimerGetoverrunHandle;
|
||||
|
||||
impl SysTimerGetoverrunHandle {
|
||||
fn timerid(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall for SysTimerGetoverrunHandle {
|
||||
fn num_args(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||
let timerid = Self::timerid(args);
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let v = pcb.posix_timers_irqsave().getoverrun(timerid)?;
|
||||
Ok(v as isize as usize)
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![FormattedSyscallParam::new(
|
||||
"timerid",
|
||||
format!("{}", args[0]),
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
declare_syscall!(SYS_TIMER_GETOVERRUN, SysTimerGetoverrunHandle);
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
use crate::{
|
||||
arch::{interrupt::TrapFrame, syscall::nr::SYS_TIMER_GETTIME},
|
||||
process::posix_timer::PosixItimerspec,
|
||||
process::ProcessManager,
|
||||
syscall::{
|
||||
table::{FormattedSyscallParam, Syscall},
|
||||
user_access::UserBufferWriter,
|
||||
},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use core::mem::size_of;
|
||||
use syscall_table_macros::declare_syscall;
|
||||
use system_error::SystemError;
|
||||
|
||||
pub struct SysTimerGettimeHandle;
|
||||
|
||||
impl SysTimerGettimeHandle {
|
||||
fn timerid(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
fn curr_value(args: &[usize]) -> *mut PosixItimerspec {
|
||||
args[1] as *mut PosixItimerspec
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall for SysTimerGettimeHandle {
|
||||
fn num_args(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||
let timerid = Self::timerid(args);
|
||||
let curr_value_ptr = Self::curr_value(args);
|
||||
if curr_value_ptr.is_null() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let val = pcb.posix_timers_irqsave().gettime(timerid)?;
|
||||
let mut writer = UserBufferWriter::new(curr_value_ptr, size_of::<PosixItimerspec>(), true)?;
|
||||
// 用异常表保护版本写回,避免用户地址缺页/无效导致内核崩溃
|
||||
writer
|
||||
.buffer_protected(0)?
|
||||
.write_one::<PosixItimerspec>(0, &val)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("timerid", format!("{}", args[0])),
|
||||
FormattedSyscallParam::new("curr_value", format!("{:#x}", args[1])),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
declare_syscall!(SYS_TIMER_GETTIME, SysTimerGettimeHandle);
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
use crate::{
|
||||
arch::{interrupt::TrapFrame, syscall::nr::SYS_TIMER_SETTIME},
|
||||
process::posix_timer::PosixItimerspec,
|
||||
process::ProcessManager,
|
||||
syscall::{
|
||||
table::{FormattedSyscallParam, Syscall},
|
||||
user_access::{UserBufferReader, UserBufferWriter},
|
||||
},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use core::mem::size_of;
|
||||
use syscall_table_macros::declare_syscall;
|
||||
use system_error::SystemError;
|
||||
|
||||
pub struct SysTimerSettimeHandle;
|
||||
|
||||
impl SysTimerSettimeHandle {
|
||||
fn timerid(args: &[usize]) -> i32 {
|
||||
args[0] as i32
|
||||
}
|
||||
fn flags(args: &[usize]) -> i32 {
|
||||
args[1] as i32
|
||||
}
|
||||
fn new_value(args: &[usize]) -> *const PosixItimerspec {
|
||||
args[2] as *const PosixItimerspec
|
||||
}
|
||||
fn old_value(args: &[usize]) -> *mut PosixItimerspec {
|
||||
args[3] as *mut PosixItimerspec
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall for SysTimerSettimeHandle {
|
||||
fn num_args(&self) -> usize {
|
||||
4
|
||||
}
|
||||
|
||||
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||
let timerid = Self::timerid(args);
|
||||
let flags = Self::flags(args);
|
||||
let new_value_ptr = Self::new_value(args);
|
||||
let old_value_ptr = Self::old_value(args);
|
||||
|
||||
// 暂不支持 TIMER_ABSTIME 等 flag
|
||||
if flags != 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
if new_value_ptr.is_null() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let reader = UserBufferReader::new(new_value_ptr, size_of::<PosixItimerspec>(), true)?;
|
||||
// 用异常表保护版本读取,避免用户地址缺页/无效导致内核崩溃
|
||||
let new_value = reader.buffer_protected(0)?.read_one::<PosixItimerspec>(0)?;
|
||||
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let old = pcb
|
||||
.posix_timers_irqsave()
|
||||
.settime(&pcb, timerid, new_value)?;
|
||||
|
||||
if !old_value_ptr.is_null() {
|
||||
let mut writer =
|
||||
UserBufferWriter::new(old_value_ptr, size_of::<PosixItimerspec>(), true)?;
|
||||
// 用异常表保护版本写回
|
||||
writer
|
||||
.buffer_protected(0)?
|
||||
.write_one::<PosixItimerspec>(0, &old)?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("timerid", format!("{}", args[0])),
|
||||
FormattedSyscallParam::new("flags", format!("{:#x}", args[1])),
|
||||
FormattedSyscallParam::new("new_value", format!("{:#x}", args[2])),
|
||||
FormattedSyscallParam::new("old_value", format!("{:#x}", args[3])),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
declare_syscall!(SYS_TIMER_SETTIME, SysTimerSettimeHandle);
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
TimerTest.ProcessKilledOnCPUSoftLimit
|
||||
TimerTest.ProcessPingedRepeatedlyAfterCPUSoftLimit
|
||||
TimerTest.ProcessKilledOnCPUHardLimit
|
||||
TimerTest.RlimitCpuInheritedAcrossFork
|
||||
|
|
@ -84,3 +84,4 @@ fifo_test
|
|||
unshare_test
|
||||
pty_root_test
|
||||
time_test
|
||||
timers_test
|
||||
|
|
|
|||
Loading…
Reference in New Issue