From 8fd71f277271ae68e648f290c67f187b030feae0 Mon Sep 17 00:00:00 2001 From: houmkh <1119644616@qq.com> Date: Mon, 17 Apr 2023 17:17:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=9A=E6=97=B6=E5=99=A8?= =?UTF-8?q?=E5=92=8C=E8=BD=AF=E4=B8=AD=E6=96=AD=E6=96=87=E6=A1=A3=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86softirq=E9=9D=A2=E5=90=91c=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20(#245)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 增加定时器和软中断文档 * 修改softirq对c的接口和文档 * 修改文档格式 --- docs/kernel/core_api/index.rst | 1 + docs/kernel/core_api/softirq.md | 173 ++++++++++++++++++++++++++++++ docs/kernel/sched/index.rst | 1 + docs/kernel/sched/kernel_timer.md | 169 +++++++++++++++++++++++++++++ kernel/src/exception/softirq.h | 4 +- kernel/src/exception/softirq.rs | 6 +- 6 files changed, 350 insertions(+), 4 deletions(-) create mode 100644 docs/kernel/core_api/softirq.md create mode 100644 docs/kernel/sched/kernel_timer.md diff --git a/docs/kernel/core_api/index.rst b/docs/kernel/core_api/index.rst index 71a9f0b8..8152fcbb 100644 --- a/docs/kernel/core_api/index.rst +++ b/docs/kernel/core_api/index.rst @@ -12,6 +12,7 @@ atomic data_structures casting + softirq 内存管理 =================== diff --git a/docs/kernel/core_api/softirq.md b/docs/kernel/core_api/softirq.md new file mode 100644 index 00000000..8765299e --- /dev/null +++ b/docs/kernel/core_api/softirq.md @@ -0,0 +1,173 @@ +# 软中断 + +  软件中断,也可以被称为中断的下半部,用于延迟处理硬中断(中断上半部)未完成的工作。将中断分为两个阶段可以有效解决中断处理时间过长和中断丢失的问题。 + +## 1. 设计思路 + +  每个cpu都有自己的pending,软中断是“哪个cpu发起,就哪个cpu执行”,每个cpu的pending不共享。同一个软中断向量可以在多核上同时运行。 + +  当我们需要注册一个新的软中断时,需要为软中断处理程序实现`SoftirqVec`特征,然后调用`register_softirq`函数,将软中断处理程序注册到软中断机制内。 + +  请注意,由于软中断的可重入、可并发性,所以软中断处理程序需要自己保证线程安全。 + +## 2. 软中断向量号 + +```rust +pub enum SoftirqNumber { + /// 时钟软中断信号 + TIMER = 0, + /// 帧缓冲区刷新软中断 + VideoRefresh = 1, +} +``` + +## 3. 软中断API + +### 3.1. SoftirqVec特征 + +```rust +pub trait SoftirqVec: Send + Sync + Debug { + fn run(&self); +} +``` + +  软中断处理程序需要实现的特征,需要实现`run`函数,用于处理软中断。当软中断被执行时,会调用`run`函数。 + +### 3.2. Softirq的API + +#### 3.2.1. 注册软中断向量 +```rust +pub fn register_softirq(&self, + softirq_num: SoftirqNumber, + handler: Arc, + ) -> Result +``` + +- 参数: + + - softirq_num:中断向量号 + + - hanlder:中断函数对应的结构体,需要指向实现了`SoftirqVec`特征的结构体变量 + +- 返回: + + - Ok(i32):0 + + - Err(SystemError):错误码 + +#### 3.2.2. 解注册软中断向量 + +```rust +pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) +``` + +- 参数: + + - softirq_num:中断向量号 + + +#### 3.2.3. 软中断执行 + +```rust +pub fn do_softirq(&self) +``` + +- 作用:执行软中断函数(**只在硬中断执行后调用**) + +#### 3.2.4. 清除软中断的pending标志 + +```rust +pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) +``` + +- 作用:清除当前CPU上,指定软中断的pending标志。请注意,这个函数是unsafe的,因为它会直接修改pending标志,而没有加锁。 + +- 参数: + + - softirq_num:中断向量号 + +#### 3.2.5. 标志软中断需要执行 + +```rust +pub fn raise_softirq(&self, softirq_num: SoftirqNumber) +``` + +- 作用:标志当前CPU上,指定的软中断需要执行 + +- 参数: + + - softirq_num:中断向量号 + +### 3.3. 使用实例 + +```rust +#[derive(Debug)] +/// SoftirqExample中断结构体 +pub struct SoftirqExample { + running: AtomicBool, +} +/// SoftirqExample中断需要处理的逻辑 +fn softirq_example_func() { + println!("addressed SoftirqExample"); +} +impl SoftirqVec for SoftirqExample { + fn run(&self) { + if self.set_run() == false { + return; + } + + softirq_example_func(); + + self.clear_run(); + } +} +impl SoftirqExample { + pub fn new() -> SoftirqExample { + SoftirqExample { + running: AtomicBool::new(false), + } + } + + fn set_run(&self) -> bool { + let x = self + .running + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed); + if x.is_ok() { + return true; + } else { + return false; + } + } + + fn clear_run(&self) { + self.running.store(false, Ordering::Release); + } +} +fn main() { + let softirq_example = Arc::new(SoftirqExample::new()); + let softirq_num = 2; + // 注册SoftirqExample中断 + softirq_vectors() + .register_softirq(SoftirqNumber::from(softirq_num as u64), softirq_example) + .expect("failed to register SoftirqExample"); + + // 标志SoftirqExample中断需要执行 + softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64)); + + // 标志SoftirqExample中断不需要执行 + softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64)); + + // 解注册SoftirqExample中断 + softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64)); +} +``` + +### 3.4. 为C提供的接口 + +```c +extern void rs_softirq_init(); +extern void rs_raise_softirq(uint32_t sirq_num); +extern void rs_unregister_softirq(uint32_t sirq_num); +extern void rs_do_softirq(); +extern void rs_clear_softirq_pending(uint32_t softirq_num); +``` diff --git a/docs/kernel/sched/index.rst b/docs/kernel/sched/index.rst index 015c9268..559af3b6 100644 --- a/docs/kernel/sched/index.rst +++ b/docs/kernel/sched/index.rst @@ -12,3 +12,4 @@ DragonOS调度 core cfs rt + kernel_timer diff --git a/docs/kernel/sched/kernel_timer.md b/docs/kernel/sched/kernel_timer.md new file mode 100644 index 00000000..2750fc2a --- /dev/null +++ b/docs/kernel/sched/kernel_timer.md @@ -0,0 +1,169 @@ +# 内核定时器 + +## 1. 简介 + +  内核定时器是内核中的一种定时器,内核定时器的工作方式是:添加定时器到队列,为每个定时器设置到期时间。当定时器到期时,会执行定时器对应的函数。 + +## 2. 设计思路 + +  定时器类型为`Timer`结构体,而`Timer`由`SpinLock`组成。全局中使用元素类型为`Arc`的队列`TIMER_LIST`存储系统创建的定时器。创建定时器时,应调用`Timer::new(timer_func,expire_jiffies)`,timer_func为定时器要执行的操作,expire_jiffies为定时器的结束时间,`timer_func`参数的类型是实现了`TimerFunction`特性的结构体。在创建定时器后,应使用`Timer::activate()`将定时器插入到`TIMER_LIST`中。 + +  **如果只是希望当前pcb休眠一段时间,应调用`schedule_timeout(timeout)`,timeout指定pcb休眠的时间长度。** + +## 3. 定时器应实现的特性 + +  定时器要执行的函数应实现`TimerFunction`特性,其定义如下: + +```rust +/// 定时器要执行的函数的特征 +pub trait TimerFunction: Send + Sync { + fn run(&mut self); +} +``` + +  一种典型的实现方式是:新建一个零长的结构体,实现`TimerFunction`特性,然后在`run`函数中实现定时器要执行的操作。 + +## 4. 定时器API + +### 4.1. Timer的API + +#### 4.1.1. 创建一个定时器 +```rust +pub fn new(timer_func: Box, expire_jiffies: u64) -> Arc +``` + +**参数** + +- timer_func:定时器需要执行的函数对应的结构体,其实现了`TimerFunction`特性 + +- expire_jiffies:定时器结束时刻(单位:**jiffies**) + +**返回** + +- 定时器结构体指针 + +#### 4.1.2. 将定时器插入到定时器链表中 + +```rust +pub fn activate(&self) +``` + +### 4.2. 其余API + +  **若想要在.c的模块中使用以下函数,请在函数名之前加上rs_** + +#### 4.2.1. 让进程休眠一段时间 + +```rust +pub fn schedule_timeout(mut timeout: i64) -> Result +``` + +**功能** + +  让进程休眠timeout个jiffies + +**参数** + +- timeout:需要休眠的时间 (单位:**jiffies**) + +**返回值** + +- Ok(i64):剩余需要休眠的时间 (单位:**jiffies**) +- Err(SystemError):错误码 + +#### 4.2.2. 获取队列中第一个定时器的结束时间 + +```rust +pub fn timer_get_first_expire() -> Result +``` + +**功能** + +  获取队列中第一个定时器的结束时间,即最早结束的定时器的结束时间 + +**返回值** + +- Ok(i64):最早结束的定时器的结束时间 (单位:**jiffies**) +- Err(SystemError):错误码 + +#### 4.2.3. 获取当前系统时间 + +```rust +pub fn clock() -> u64 +``` + +**功能** + +  获取当前系统时间(单位:**jiffies**) + +#### 4.2.4. 计算接下来n毫秒或者微秒对应的定时器时间片 + +##### 4.2.4.1. 毫秒 + +```rust +pub fn next_n_ms_timer_jiffies(expire_ms: u64) -> u64 +``` + +**功能** + +  计算接下来n**毫秒**对应的定时器时间片 + +**参数** + +- expire_ms:n毫秒 + +**返回值** + +  对应的定时器时间片(单位:**毫秒**) + +##### 4.2.4.2. 微秒 + +```rust +pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64 +``` + +**功能** + +  计算接下来n**微秒**对应的定时器时间片 + +**参数** + +- expire_ms:n微秒 + +**返回值** + +  对应的定时器时间片(单位:**微秒**) + +## 5. 创建定时器实例 + +```rust +struct TimerExample { + /// 结构体的成员对应函数的形参 + example_parameter: i32, +} +impl TimerExample { + pub fn new(para: i32) -> Box { + return Box::new(TimerExample { + example_parameter: para, + }); + } +} +/// 为结构体实现TimerFunction特性 +impl TimerFunction for TimerExample { + /// TimerFunction特性中的函数run + fn run(&mut self) { + // 定时器需要执行的操作 + example_func(self.example_parameter); + } +} +fn example_func(para: i32) { + println!("para is {:?}", para); +} +fn main() { + let timer_example: Box = TimerExample::new(1); + // 创建一个定时器 + let timer: Arc = Timer::new(timer_example, 1); + // 将定时器插入队列 + timer.activate(); +} +``` diff --git a/kernel/src/exception/softirq.h b/kernel/src/exception/softirq.h index 8d6ed33d..dc61e862 100644 --- a/kernel/src/exception/softirq.h +++ b/kernel/src/exception/softirq.h @@ -15,9 +15,9 @@ // ==================implementation with rust=================== extern void rs_softirq_init(); extern void rs_raise_softirq(uint32_t sirq_num); -extern int rs_register_softirq(uint32_t irq_num, void (*action)(void *data), void *data); -extern int unregister_softirq(uint32_t irq_num); +extern void rs_unregister_softirq(uint32_t sirq_num); extern void rs_do_softirq(); +extern void rs_clear_softirq_pending(uint32_t softirq_num); // for temporary #define MAX_SOFTIRQ_NUM 64 diff --git a/kernel/src/exception/softirq.rs b/kernel/src/exception/softirq.rs index 8edb3627..0538677e 100644 --- a/kernel/src/exception/softirq.rs +++ b/kernel/src/exception/softirq.rs @@ -236,7 +236,7 @@ impl Softirq { local_irq_restore(&flags); // kdebug!("raise_softirq exited"); } - pub fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) { + pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) { compiler_fence(Ordering::SeqCst); cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num)); compiler_fence(Ordering::SeqCst); @@ -261,5 +261,7 @@ pub extern "C" fn rs_do_softirq() { #[no_mangle] pub extern "C" fn rs_clear_softirq_pending(softirq_num: u32) { - softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64)); + unsafe { + softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64)); + } }