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

* alarm系统调用实现
This commit is contained in:
SMALLC 2024-04-16 21:34:36 +08:00 committed by GitHub
parent d623e90231
commit fbd63a301c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 398 additions and 2 deletions

View File

@ -333,6 +333,7 @@ impl SigInfo {
#[derive(Copy, Clone, Debug)]
pub enum SigType {
Kill(Pid),
Alarm(Pid),
// 后续完善下列中的具体字段
// Timer,
// Rt,

View File

@ -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
kernel/src/process/timer.rs Normal file
View File

@ -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(())
}
}

View File

@ -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];

View File

@ -28,7 +28,7 @@
#define SYS_DUP2 33
#define SYS_NANOSLEEP 35
#define SYS_ALARM 37
#define SYS_GETPID 39
#define SYS_SOCKET 41

View File

@ -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);
}
}

View File

@ -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函数对应的结构体

View File

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

3
user/apps/test_alarm/.gitignore vendored Normal file
View File

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

View File

@ -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"

View File

@ -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

View File

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

View File

@ -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");
}

View File

@ -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
}