فهرست منبع

feat: alarm系统调用实现 (#710)

* alarm系统调用实现
SMALLC 10 ماه پیش
والد
کامیت
fbd63a301c

+ 1 - 0
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,

+ 10 - 0
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<ThreadInfo>,
 
+    ///闹钟定时器
+    alarm_timer: SpinLock<Option<AlarmTimer>>,
+
     /// 进程的robust lock列表
     robust_list: RwLock<Option<RobustListHead>>,
 }
@@ -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<RobustListHead>) {
         *self.robust_list.write_irqsave() = new_robust_list;
     }
+
+    pub fn alarm_timer_irqsave(&self) -> SpinLockGuard<Option<AlarmTimer>> {
+        return self.alarm_timer.lock_irqsave();
+    }
 }
 
 impl Drop for ProcessControlBlock {

+ 144 - 0
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<Timer>,
+    /// 闹钟触发时间
+    expired_second: u64,
+}
+
+impl AlarmTimer {
+    /// # 创建闹钟结构体
+    ///  
+    /// 自定义定时器触发函数和截止时间来创建闹钟结构体
+    ///
+    /// ## 函数参数
+    ///
+    /// timer_func:定时器触发函数
+    ///
+    /// second:设置alarm触发的秒数
+    ///
+    /// ### 函数返回值
+    ///
+    /// Self
+    pub fn new(timer_func: Box<dyn TimerFunction>, second: u64) -> Self {
+        let expired_jiffies =
+            <Jiffies as From<Duration>>::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 =
+                <Jiffies as From<Duration>>::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<AlarmTimerFunc> {
+        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(())
+    }
+}

+ 5 - 0
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];

+ 1 - 1
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

+ 46 - 1
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<usize, SystemError> {
+        //初始化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);
+    }
 }

+ 46 - 0
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<Jiffies> 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<Duration> 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函数对应的结构体

+ 2 - 0
user/apps/test_alarm/.cargo/config.toml

@@ -0,0 +1,2 @@
+[build]
+target = "x86_64-unknown-linux-musl"

+ 3 - 0
user/apps/test_alarm/.gitignore

@@ -0,0 +1,3 @@
+/target
+Cargo.lock
+/install/

+ 12 - 0
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 <[email protected]>" ]
+
+# 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"

+ 56 - 0
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

+ 4 - 0
user/apps/test_alarm/README.md

@@ -0,0 +1,4 @@
+# sysalarm调用测试
+## 测试流程
+首先测试能否正常启用sysalarm系统调用,然后测试在上一个alarm未结束时调用alarm能否取消上一个,返回剩余时间,启动下一个alarm
+

+ 42 - 0
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");
+}

+ 26 - 0
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
+}