diff --git a/kernel/src/ipc/signal_types.rs b/kernel/src/ipc/signal_types.rs index 33f1ec5e..1ed08547 100644 --- a/kernel/src/ipc/signal_types.rs +++ b/kernel/src/ipc/signal_types.rs @@ -333,6 +333,7 @@ impl SigInfo { #[derive(Copy, Clone, Debug)] pub enum SigType { Kill(Pid), + Alarm(Pid), // 后续完善下列中的具体字段 // Timer, // Rt, diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 4df0216c..c22c17dd 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -60,6 +60,7 @@ use crate::{ }, syscall::{user_access::clear_user, Syscall}, }; +use timer::AlarmTimer; use self::kthread::WorkerPrivate; @@ -74,6 +75,7 @@ pub mod pid; pub mod resource; pub mod stdio; pub mod syscall; +pub mod timer; pub mod utils; /// 系统中所有进程的pcb @@ -639,6 +641,9 @@ pub struct ProcessControlBlock { /// 线程信息 thread: RwLock, + ///闹钟定时器 + alarm_timer: SpinLock>, + /// 进程的robust lock列表 robust_list: RwLock>, } @@ -706,6 +711,7 @@ impl ProcessControlBlock { children: RwLock::new(Vec::new()), wait_queue: WaitQueue::default(), thread: RwLock::new(ThreadInfo::new()), + alarm_timer: SpinLock::new(None), robust_list: RwLock::new(None), }; @@ -967,6 +973,10 @@ impl ProcessControlBlock { pub fn set_robust_list(&self, new_robust_list: Option) { *self.robust_list.write_irqsave() = new_robust_list; } + + pub fn alarm_timer_irqsave(&self) -> SpinLockGuard> { + return self.alarm_timer.lock_irqsave(); + } } impl Drop for ProcessControlBlock { diff --git a/kernel/src/process/timer.rs b/kernel/src/process/timer.rs new file mode 100644 index 00000000..7099d074 --- /dev/null +++ b/kernel/src/process/timer.rs @@ -0,0 +1,144 @@ +use crate::arch::ipc::signal::{SigCode, Signal}; +use crate::exception::InterruptArch; +use crate::ipc::signal_types::SigType; +use crate::process::CurrentIrqArch; +use crate::process::Pid; +use crate::process::SigInfo; +use crate::time::timer::{clock, Jiffies, Timer, TimerFunction}; +use alloc::{boxed::Box, sync::Arc}; +use core::sync::atomic::compiler_fence; +use core::time::Duration; +use system_error::SystemError; + +/// 闹钟结构体 +#[derive(Debug)] +pub struct AlarmTimer { + /// 闹钟内置定时器 + pub timer: Arc, + /// 闹钟触发时间 + expired_second: u64, +} + +impl AlarmTimer { + /// # 创建闹钟结构体 + /// + /// 自定义定时器触发函数和截止时间来创建闹钟结构体 + /// + /// ## 函数参数 + /// + /// timer_func:定时器触发函数 + /// + /// second:设置alarm触发的秒数 + /// + /// ### 函数返回值 + /// + /// Self + pub fn new(timer_func: Box, second: u64) -> Self { + let expired_jiffies = + >::from(Duration::from_secs(second)).timer_jiffies(); + let result = AlarmTimer { + timer: Timer::new(timer_func, expired_jiffies), + expired_second: second, + }; + result + } + /// # 启动闹钟 + pub fn activate(&self) { + let timer = self.timer.clone(); + timer.activate(); + } + + /// # 初始化目标进程的alarm定时器 + /// + /// 创建一个闹钟结构体并启动闹钟 + /// + /// ## 函数参数 + /// + /// pid:发送消息的目标进程的pid + /// + /// second:设置alarm触发的秒数 + /// + /// ### 函数返回值 + /// + /// AlarmTimer结构体 + pub fn alarm_timer_init(pid: Pid, second: u64) -> AlarmTimer { + //初始化Timerfunc + let timerfunc = AlarmTimerFunc::new(pid); + let alarmtimer = AlarmTimer::new(timerfunc, second); + alarmtimer.activate(); + alarmtimer + } + + /// # 查看闹钟是否触发 + pub fn timeout(&self) -> bool { + self.timer.timeout() + } + + /// # 返回闹钟定时器剩余时间 + pub fn remain(&self) -> Duration { + if self.timer.timeout() { + Duration::ZERO + } else { + let now_jiffies = clock(); + let end_jiffies = + >::from(Duration::from_secs(self.expired_second)) + .timer_jiffies(); + let remain_second = Duration::from(Jiffies::new(end_jiffies - now_jiffies)); + // kdebug!( + // "end: {} - now: {} = remain: {}", + // end_jiffies, + // now_jiffies, + // end_jiffies - now_jiffies + // ); + remain_second + } + } + /// # 取消闹钟 + pub fn cancel(&self) { + self.timer.cancel(); + } +} + +/// # 闹钟TimerFuntion结构体 +/// +/// ## 结构成员 +/// +/// pid:发送消息的目标进程的pid +#[derive(Debug)] +pub struct AlarmTimerFunc { + pid: Pid, +} + +impl AlarmTimerFunc { + pub fn new(pid: Pid) -> Box { + return Box::new(AlarmTimerFunc { pid }); + } +} + +impl TimerFunction for AlarmTimerFunc { + /// # 闹钟触发函数 + /// + /// 闹钟触发时,向目标进程发送一个SIGALRM信号 + /// + /// ## 函数参数 + /// + /// expired_second:设置alarm触发的秒数 + /// + /// ### 函数返回值 + /// + /// Ok(()): 发送成功 + fn run(&mut self) -> Result<(), SystemError> { + let sig = Signal::SIGALRM; + // 初始化signal info + let mut info = SigInfo::new(sig, 0, SigCode::Timer, SigType::Alarm(self.pid)); + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + let _retval = sig + .send_signal_info(Some(&mut info), self.pid) + .map(|x| x as usize)?; + compiler_fence(core::sync::atomic::Ordering::SeqCst); + drop(irq_guard); + Ok(()) + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c8cb7648..ab4a9d9a 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1055,6 +1055,11 @@ impl Syscall { Err(SystemError::EINVAL) } + SYS_ALARM => { + let second = args[0] as u32; + Self::alarm(second) + } + SYS_SHMGET => { let key = ShmKey::new(args[0]); let size = args[1]; diff --git a/kernel/src/syscall/syscall_num.h b/kernel/src/syscall/syscall_num.h index 184a5722..07dabe38 100644 --- a/kernel/src/syscall/syscall_num.h +++ b/kernel/src/syscall/syscall_num.h @@ -28,7 +28,7 @@ #define SYS_DUP2 33 #define SYS_NANOSLEEP 35 - +#define SYS_ALARM 37 #define SYS_GETPID 39 #define SYS_SOCKET 41 diff --git a/kernel/src/time/syscall.rs b/kernel/src/time/syscall.rs index b936e6ba..77fd1334 100644 --- a/kernel/src/time/syscall.rs +++ b/kernel/src/time/syscall.rs @@ -1,9 +1,13 @@ -use core::ffi::{c_int, c_longlong}; +use core::{ + ffi::{c_int, c_longlong}, + time::Duration, +}; use num_traits::FromPrimitive; use system_error::SystemError; use crate::{ + process::{timer::AlarmTimer, ProcessManager}, syscall::{user_access::UserBufferWriter, Syscall}, time::{sleep::nanosleep, PosixTimeSpec}, }; @@ -151,4 +155,45 @@ impl Syscall { return Ok(0); } + /// # alarm函数功能 + /// + /// 设置alarm(单位:秒) + /// + /// ## 函数参数 + /// + /// expired_second:设置alarm触发的秒数 + /// + /// ### 函数返回值 + /// + /// Ok(usize): 上一个alarm的剩余秒数 + pub fn alarm(expired_second: u32) -> Result { + //初始化second + let second = Duration::from_secs(expired_second as u64); + let pcb = ProcessManager::current_pcb(); + let mut pcb_alarm = pcb.alarm_timer_irqsave(); + let alarm = pcb_alarm.as_ref(); + //alarm第一次调用 + if alarm.is_none() { + //注册alarm定时器 + let pid = ProcessManager::current_pid(); + let new_alarm = Some(AlarmTimer::alarm_timer_init(pid, 0)); + *pcb_alarm = new_alarm; + drop(pcb_alarm); + return Ok(0); + } + //查询上一个alarm的剩余时间和重新注册alarm + let alarmtimer = alarm.unwrap(); + let remain = alarmtimer.remain(); + if second.is_zero() { + alarmtimer.cancel(); + } + if !alarmtimer.timeout() { + alarmtimer.cancel(); + } + let pid = ProcessManager::current_pid(); + let new_alarm = Some(AlarmTimer::alarm_timer_init(pid, second.as_secs())); + *pcb_alarm = new_alarm; + drop(pcb_alarm); + return Ok(remain.as_secs() as usize); + } } diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 8c2b029b..81f4ca05 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -2,6 +2,7 @@ use core::{ fmt::Debug, intrinsics::unlikely, sync::atomic::{compiler_fence, AtomicBool, AtomicU64, Ordering}, + time::Duration, }; use alloc::{ @@ -37,6 +38,51 @@ lazy_static! { pub trait TimerFunction: Send + Sync + Debug { fn run(&mut self) -> Result<(), SystemError>; } +// # Jiffies结构体(注意这是一段时间的jiffies数而不是某一时刻的定时器时间片) + +int_like!(Jiffies, u64); + +impl Jiffies { + /// ## 返回接下来的n_jiffies对应的定时器时间片 + pub fn timer_jiffies(&self) -> u64 { + let result = TIMER_JIFFIES.load(Ordering::SeqCst) + self.data(); + result + } +} + +impl From for Duration { + /// # Jiffies转Duration + /// + /// ## 参数 + /// + /// jiffies: 一段时间的jiffies数 + /// + /// ### 返回值 + /// + /// Duration: 这段时间的Duration形式 + fn from(jiffies: Jiffies) -> Self { + let ms = jiffies.data() / 1_000_000 * NSEC_PER_JIFFY as u64; + let result = Duration::from_millis(ms); + result + } +} + +impl From for Jiffies { + /// # Duration 转 Jiffies + /// + /// ## 参数 + /// + /// ms: 表示一段时间的Duration类型 + /// + /// ### 返回值 + /// + /// Jiffies结构体: 这段时间的Jiffies数 + fn from(ms: Duration) -> Self { + let jiffies = ms.as_millis() as u64 * 1_000_000 / NSEC_PER_JIFFY as u64; + let result = Jiffies::new(jiffies); + result + } +} #[derive(Debug)] /// WakeUpHelper函数对应的结构体 diff --git a/user/apps/test_alarm/.cargo/config.toml b/user/apps/test_alarm/.cargo/config.toml new file mode 100644 index 00000000..c1ca86b1 --- /dev/null +++ b/user/apps/test_alarm/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "x86_64-unknown-linux-musl" \ No newline at end of file diff --git a/user/apps/test_alarm/.gitignore b/user/apps/test_alarm/.gitignore new file mode 100644 index 00000000..1ac35461 --- /dev/null +++ b/user/apps/test_alarm/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +/install/ \ No newline at end of file diff --git a/user/apps/test_alarm/Cargo.toml b/user/apps/test_alarm/Cargo.toml new file mode 100644 index 00000000..e428e6ea --- /dev/null +++ b/user/apps/test_alarm/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "test_alarm" +version = "0.1.0" +edition = "2021" +description = "test for alarm" +authors = [ "smallc <2628035541@qq.com>" ] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libc = "0.2.0" +nix = "0.23.0" \ No newline at end of file diff --git a/user/apps/test_alarm/Makefile b/user/apps/test_alarm/Makefile new file mode 100644 index 00000000..1b0274d2 --- /dev/null +++ b/user/apps/test_alarm/Makefile @@ -0,0 +1,56 @@ +TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux-gnu" +RUSTFLAGS+="" + +ifdef DADK_CURRENT_BUILD_DIR +# 如果是在dadk中编译,那么安装到dadk的安装目录中 + INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR) +else +# 如果是在本地编译,那么安装到当前目录下的install目录中 + INSTALL_DIR = ./install +endif + +ifeq ($(ARCH), x86_64) + export RUST_TARGET=x86_64-unknown-linux-musl +else ifeq ($(ARCH), riscv64) + export RUST_TARGET=riscv64gc-unknown-linux-gnu +else +# 默认为x86_86,用于本地编译 + export RUST_TARGET=x86_64-unknown-linux-musl +endif + +run: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) + +build: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) + +clean: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) + +test: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) + +doc: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET) + +fmt: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt + +fmt-check: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check + +run-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release + +build-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release + +clean-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release + +test-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release + +.PHONY: install +install: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force diff --git a/user/apps/test_alarm/README.md b/user/apps/test_alarm/README.md new file mode 100644 index 00000000..589979a8 --- /dev/null +++ b/user/apps/test_alarm/README.md @@ -0,0 +1,4 @@ +# sysalarm调用测试 +## 测试流程 +首先测试能否正常启用sysalarm系统调用,然后测试在上一个alarm未结束时调用alarm能否取消上一个,返回剩余时间,启动下一个alarm + diff --git a/user/apps/test_alarm/src/main.rs b/user/apps/test_alarm/src/main.rs new file mode 100644 index 00000000..465bb429 --- /dev/null +++ b/user/apps/test_alarm/src/main.rs @@ -0,0 +1,42 @@ +extern crate libc; +use libc::{signal, sleep, syscall, SYS_alarm, SIGALRM}; + +extern "C" fn handle_alarm(_: i32) { + println!("Alarm ring!"); +} + +fn main() { + // 设置信号处理函数 + unsafe { + signal(SIGALRM, handle_alarm as usize); + } + + //test1: alarm系统调用能否正常运行 + unsafe { + syscall(SYS_alarm, 5); + } + println!("Alarm set for 5 seconds"); + unsafe { + sleep(6); + } + println!("Test 1 complete"); + + //test2:在上一个alarm定时器未完成时重新调用alarm,查看返回值是否为上一个alarm的剩余秒数, + //并test第三个alarm定时器能否正常运行 + + unsafe { + let remaining = syscall(SYS_alarm, 5); + println!("Remaining time for previous alarm: {}", remaining); + } + println!("Alarm set for 5 seconds"); + unsafe { + let remaining = syscall(SYS_alarm, 3); + println!("Remaining time for previous alarm: {}", remaining); + } + unsafe { + sleep(4); + } + println!("Alarm set for 3 seconds"); + + println!("Test 2 complete"); +} diff --git a/user/dadk/config/test_alarm_0_1_0.dadk b/user/dadk/config/test_alarm_0_1_0.dadk new file mode 100644 index 00000000..d3df7607 --- /dev/null +++ b/user/dadk/config/test_alarm_0_1_0.dadk @@ -0,0 +1,26 @@ +{ + "name": "test_alarm", + "version": "0.1.0", + "description": "test for alarm", + "rust_target": null, + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/test_alarm" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "install": { + "in_dragonos_path": "/" + }, + "clean": { + "clean_command": "make clean" + }, + "envs": [], + "build_once": false, + "install_once": false +} \ No newline at end of file