增加定时器和软中断文档,修改了softirq面向c的接口 (#245)

* 增加定时器和软中断文档

* 修改softirq对c的接口和文档

* 修改文档格式
This commit is contained in:
houmkh 2023-04-17 17:17:06 +08:00 committed by GitHub
parent 77c928f6ce
commit 8fd71f2772
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 350 additions and 4 deletions

View File

@ -12,6 +12,7 @@
atomic atomic
data_structures data_structures
casting casting
softirq
内存管理 内存管理
=================== ===================

View File

@ -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<dyn SoftirqVec>,
) -> Result<i32, SystemError>
```
- 参数:
- 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);
```

View File

@ -12,3 +12,4 @@ DragonOS调度
core core
cfs cfs
rt rt
kernel_timer

View File

@ -0,0 +1,169 @@
# 内核定时器
## 1. 简介
&emsp;&emsp;内核定时器是内核中的一种定时器,内核定时器的工作方式是:添加定时器到队列,为每个定时器设置到期时间。当定时器到期时,会执行定时器对应的函数。
## 2. 设计思路
&emsp;&emsp;定时器类型为`Timer`结构体,而`Timer``SpinLock<InnerTimer>`组成。全局中使用元素类型为`Arc<Timer>`的队列`TIMER_LIST`存储系统创建的定时器。创建定时器时,应调用`Timer::new(timer_func,expire_jiffies)`timer_func为定时器要执行的操作expire_jiffies为定时器的结束时间`timer_func`参数的类型是实现了`TimerFunction`特性的结构体。在创建定时器后,应使用`Timer::activate()`将定时器插入到`TIMER_LIST`中。
&emsp;&emsp;**如果只是希望当前pcb休眠一段时间应调用`schedule_timeout(timeout)`timeout指定pcb休眠的时间长度。**
## 3. 定时器应实现的特性
&emsp;&emsp;定时器要执行的函数应实现`TimerFunction`特性,其定义如下:
```rust
/// 定时器要执行的函数的特征
pub trait TimerFunction: Send + Sync {
fn run(&mut self);
}
```
&emsp;&emsp;一种典型的实现方式是:新建一个零长的结构体,实现`TimerFunction`特性,然后在`run`函数中实现定时器要执行的操作。
## 4. 定时器API
### 4.1. Timer的API
#### 4.1.1. 创建一个定时器
```rust
pub fn new(timer_func: Box<dyn TimerFunction>, expire_jiffies: u64) -> Arc<Self>
```
**参数**
- timer_func定时器需要执行的函数对应的结构体其实现了`TimerFunction`特性
- expire_jiffies定时器结束时刻单位**jiffies**
**返回**
- 定时器结构体指针
#### 4.1.2. 将定时器插入到定时器链表中
```rust
pub fn activate(&self)
```
### 4.2. 其余API
&emsp;&emsp;**若想要在.c的模块中使用以下函数请在函数名之前加上rs_**
#### 4.2.1. 让进程休眠一段时间
```rust
pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError>
```
**功能**
&emsp;&emsp;让进程休眠timeout个jiffies
**参数**
- timeout需要休眠的时间 (单位:**jiffies**
**返回值**
- Ok(i64):剩余需要休眠的时间 (单位:**jiffies**
- Err(SystemError):错误码
#### 4.2.2. 获取队列中第一个定时器的结束时间
```rust
pub fn timer_get_first_expire() -> Result<u64, SystemError>
```
**功能**
&emsp;&emsp;获取队列中第一个定时器的结束时间,即最早结束的定时器的结束时间
**返回值**
- Ok(i64):最早结束的定时器的结束时间 (单位:**jiffies**
- Err(SystemError):错误码
#### 4.2.3. 获取当前系统时间
```rust
pub fn clock() -> u64
```
**功能**
&emsp;&emsp;获取当前系统时间(单位:**jiffies**
#### 4.2.4. 计算接下来n毫秒或者微秒对应的定时器时间片
##### 4.2.4.1. 毫秒
```rust
pub fn next_n_ms_timer_jiffies(expire_ms: u64) -> u64
```
**功能**
&emsp;&emsp;计算接下来n**毫秒**对应的定时器时间片
**参数**
- expire_msn毫秒
**返回值**
&emsp;&emsp;对应的定时器时间片(单位:**毫秒**
##### 4.2.4.2. 微秒
```rust
pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64
```
**功能**
&emsp;&emsp;计算接下来n**微秒**对应的定时器时间片
**参数**
- expire_msn微秒
**返回值**
&emsp;&emsp;对应的定时器时间片(单位:**微秒**
## 5. 创建定时器实例
```rust
struct TimerExample {
/// 结构体的成员对应函数的形参
example_parameter: i32,
}
impl TimerExample {
pub fn new(para: i32) -> Box<TimerExample> {
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> = TimerExample::new(1);
// 创建一个定时器
let timer: Arc<Timer> = Timer::new(timer_example, 1);
// 将定时器插入队列
timer.activate();
}
```

View File

@ -15,9 +15,9 @@
// ==================implementation with rust=================== // ==================implementation with rust===================
extern void rs_softirq_init(); extern void rs_softirq_init();
extern void rs_raise_softirq(uint32_t sirq_num); 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 void rs_unregister_softirq(uint32_t sirq_num);
extern int unregister_softirq(uint32_t irq_num);
extern void rs_do_softirq(); extern void rs_do_softirq();
extern void rs_clear_softirq_pending(uint32_t softirq_num);
// for temporary // for temporary
#define MAX_SOFTIRQ_NUM 64 #define MAX_SOFTIRQ_NUM 64

View File

@ -236,7 +236,7 @@ impl Softirq {
local_irq_restore(&flags); local_irq_restore(&flags);
// kdebug!("raise_softirq exited"); // 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); compiler_fence(Ordering::SeqCst);
cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num)); cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num));
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
@ -261,5 +261,7 @@ pub extern "C" fn rs_do_softirq() {
#[no_mangle] #[no_mangle]
pub extern "C" fn rs_clear_softirq_pending(softirq_num: u32) { 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));
}
} }