mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
添加completion模块+wait_queue_head模块+schedule_timeout (#70)
* 添加completion模块+wait_queue_head模块+schedule_timeout * 修复一些bug * 实现设置pcb名字和vsnprintf (#72) * 实现pcb设置名字 * 实现设置pcb名字,实现vsnprintf * 修改set_pcb_name和va_end * bugfix: 修正一些小问题 Co-authored-by: longjin <longjin@RinGoTek.cn> * new: FAT32删除文件的功能 (#73) * new: 将sys_rmdir更改为sys_unlink,.且完成删除文件操作的vfs部分 * new: fat32删除文件 *bugfix: 解决创建文件时的bug * new: 将可执行文件移动到bin目录下 * 完善completion和wait_queue_head文档,并确保测试ok。 Co-authored-by: longjin <longjin@RinGoTek.cn> Co-authored-by: houmkh <100781004+houmkh@users.noreply.github.com>
This commit is contained in:
parent
c811947dd0
commit
09f8d6f577
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -148,6 +148,11 @@
|
||||
"timer.h": "c",
|
||||
"hid.h": "c",
|
||||
"cfs.h": "c",
|
||||
"rtc.h": "c",
|
||||
"wait_queue_head.h": "c",
|
||||
"list.h": "c",
|
||||
"compiler.h": "c",
|
||||
"completion.h": "c",
|
||||
"fat32.h": "c"
|
||||
},
|
||||
"C_Cpp.errorSquiggles": "Enabled",
|
||||
|
@ -2,12 +2,22 @@
|
||||
|
||||
  如果几个进程需要等待某个事件发生,才能被运行,那么就需要一种“等待”的机制,以实现进程同步。
|
||||
|
||||
## wait_queue等待队列
|
||||
## 一. wait_queue等待队列
|
||||
|
||||
  wait_queue是一种进程同步机制,中文名为“等待队列”。它可以将当前进程挂起,并在时机成熟时,由另一个进程唤醒他们。
|
||||
|
||||
  当您需要等待一个事件完成时,使用wait_queue机制能减少进程同步的开销。相比于滥用自旋锁以及信号量,或者是循环使用usleep(1000)这样的函数来完成同步,wait_queue是一个高效的解决方案。
|
||||
|
||||
:::{warning}
|
||||
`wait_queue.h`中的等待队列的实现并没有把队列头独立出来,同时没有考虑为等待队列加锁。所以在后来的开发中加入了`wait_queue_head.h`的队列头实现,实质上就是链表+自选锁。它与`wait_queue.h`中的队列是兼容的,当你使用`struct wait_queue_head`作为队列头时,你同样可以使用等待队列添加节点的函数。
|
||||
|
||||
但是在之后的版本中可能会把两者合并,目前仍然没有进行,且存在头文件相互引用的问题:
|
||||
- "spin_lock.h" 引用了 "wait_queue.h"
|
||||
- "wait_queue_head.h" 引用了 "spin_lock.h";
|
||||
|
||||
所以在合并之前必须解决这个问题。
|
||||
:::
|
||||
|
||||
### 简单用法
|
||||
|
||||
  等待队列的使用方法主要分为以下几部分:
|
||||
@ -57,3 +67,136 @@ wait_queue_node_t wq_keyboard_interrupt_received;
|
||||
  您可以使用`void wait_queue_wakeup(wait_queue_node_t * wait_queue_head, int64_t state);`函数,从指定的等待队列中,唤醒第一个挂起时的状态与指定的`state`相同的进程。
|
||||
|
||||
  当没有符合条件的进程时,将不会唤醒任何进程,仿佛无事发生。
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
  
|
||||
  
|
||||
  
|
||||
|
||||
|
||||
## 二. wait_queue_head等待队列头
|
||||
|
||||
   数据结构定义如下:
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
struct List wait_list;
|
||||
spinlock_t lock; // 队列需要有一个自旋锁,虽然目前内部并没有使用,但是以后可能会用.
|
||||
} wait_queue_head_t;
|
||||
```
|
||||
|
||||
   等待队列头的使用逻辑与等待队列实际是一样的,因为他同样也是等待队列的节点(仅仅多了一把锁)。且wait_queue_head的函数基本上与wait_queue一致,只不过多了\*\*\*\_with\_node\_\*\*\*的字符串。
|
||||
|
||||
   同时,wait_queue_head.h文件中提供了很多的宏,可以方便您的工作。
|
||||
|
||||
### 提供的宏
|
||||
| 宏 | 解释 |
|
||||
| ----------------------------------- | ----------------------------------------------------------- |
|
||||
| DECLARE_WAIT_ON_STACK(name, pcb) | 在栈上声明一个wait_queue节点,同时把pcb所代表的进程与该节点绑定 |
|
||||
| DECLARE_WAIT_ON_STACK_SELF(name) | 传在栈上声明一个wait_queue节点,同时当前进程(即自身进程)与该节点绑定 |
|
||||
| DECLARE_WAIT_ALLOC(name, pcb) | 使用`kzalloc`声明一个wait_queue节点,同时把pcb所代表的进程与该节点绑定,请记得使用kfree释放空间 |
|
||||
| DECLARE_WAIT_ALLOC_SELF(name) | 使用`kzalloc`声明一个wait_queue节点,同时当前进程(即自身进程)与该节点绑定,请记得使用kfree释放空间 |
|
||||
|
||||
|
||||
|
||||
### 创建等待队列头
|
||||
   您可以直接调用宏
|
||||
```c
|
||||
DECLARE_WAIT_QUEUE_HEAD(m_wait_queue_head); // 在栈上声明一个队列头变量
|
||||
```
|
||||
   也可以手动声明
|
||||
```c
|
||||
struct wait_queue_head_t m_wait_queue_head = {0};
|
||||
wait_queue_head_init(&m_wait_queue_head);
|
||||
```
|
||||
|
||||
|
||||
### 将结点插入等待队列
|
||||
|
||||
| 函数名 | 解释 |
|
||||
| ----------------------------------- | ----------------------------------------------------------- |
|
||||
| wait_queue_sleep_with_node(wait_queue_head_t *head, wait_queue_node_t *wait_node) | 传入一个等待队列节点,并设置该节点的挂起状态为PROC_UNINTERRUPTIBLE |
|
||||
| wait_queue_sleep_with_node_unlock(wait_queue_head_t *q, wait_queue_node_t *wait, void *lock) | 传入一个等待队列节点,将该节点的pcb指向的进程挂起,并设置挂起状态为PROC_UNINTERRUPTIBLE。待当前进程被插入等待队列后,解锁给定的自旋锁 |
|
||||
| wait_queue_sleep_with_node_interriptible(wait_queue_head_t *q, wait_queue_node_t *wait) | 传入一个等待队列节点,将该节点的pcb指向的进程挂起,并设置挂起状态为PROC_INTERRUPTIBLE |
|
||||
|
||||
|
||||
|
||||
### 从等待队列唤醒一个进程
|
||||
   在`wait_queue.h`中的`wait_queue_wakeup`函数直接kfree掉了wait_node节点。对于在栈上的wait_node,您可以选择`wait_queue_wakeup_on_stack(wait_queue_head_t *q, int64_t state)`来唤醒队列里面的队列头节点。
|
||||
|
||||
------------------------------------------------------------
|
||||
  
|
||||
  
|
||||
  
|
||||
|
||||
## 三. completion完成量
|
||||
|
||||
|
||||
### 简单用法
|
||||
  完成量的使用方法主要分为以下几部分:
|
||||
|
||||
- 声明一个完成量(可以在栈中/使用kmalloc/使用数组)
|
||||
- 使用wait_for_completion等待事件完成
|
||||
- 使用complete唤醒等待的进程
|
||||
|
||||
   等待操作
|
||||
```c
|
||||
void wait_fun() {
|
||||
DECLARE_COMPLETION_ON_STACK(comp); // 声明一个completion
|
||||
|
||||
// .... do somethind here
|
||||
// 大部分情况是你使用kthread_run()创建了另一个线程
|
||||
// 你需要把comp变量传给这个线程, 然后当前线程就会等待他的完成
|
||||
|
||||
if (!try_wait_for_completion(&comp)) // 进入等待
|
||||
wait_for_completion(&comp);
|
||||
}
|
||||
```
|
||||
|
||||
   完成操作
|
||||
```c
|
||||
void kthread_fun(struct completion *comp) {
|
||||
// ...... 做一些事 .......
|
||||
// 这里你确定你完成了目标事件
|
||||
|
||||
complete(&comp);
|
||||
// 或者你使用complete_all
|
||||
complete_all(&comp);
|
||||
}
|
||||
```
|
||||
|
||||
### 更多用法
|
||||
   kernel/sched/completion.c文件夹中,你可以看到 __test 开头的几个函数,他们是completion模块的测试代码,基本覆盖了completion的大部分函数.你可以在这里查询函数使用方法.
|
||||
|
||||
### 初始化完成量
|
||||
   函数`completion_init(struct completion *x)`提供了初始化completion的功能。当你使用`DECLARE_COMPLETION_ON_STACK`来创建(在栈上创建)的时候,会自动初始化.
|
||||
|
||||
### 关于完成量的wait系列函数
|
||||
|
||||
| 函数名 | 解释 |
|
||||
| ----------------------------------- | ----------------------------------------------------------- |
|
||||
| wait_for_completion(struct completion *x) | 将当前进程挂起,并设置挂起状态为PROC_UNINTERRUPTIBLE。 |
|
||||
| wait_for_completion_timeout(struct completion *x, long timeout) | 将当前进程挂起,并设置挂起状态为PROC_UNINTERRUPTIBLE。当等待timeout时间(jiffies时间片)之后,自动唤醒进程。 |
|
||||
| wait_for_completion_interruptible(struct completion *x) | 将当前进程挂起,并设置挂起状态为PROC_INTERRUPTIBLE。 |
|
||||
| wait_for_completion_interruptible_timeout(struct completion *x, long timeout) | 将当前进程挂起,并设置挂起状态为PROC_INTERRUPTIBLE。当等待timeout时间(jiffies时间片)之后,自动唤醒进程。 |
|
||||
| wait_for_multicompletion(struct completion x[], int n)| 将当前进程挂起,并设置挂起状态为PROC_UNINTERRUPTIBLE。(等待数组里面的completion的完成) |
|
||||
|
||||
|
||||
|
||||
### 关于完成量的complete系列函数
|
||||
|
||||
| 函数名 | 解释 |
|
||||
| ----------------------------------- | ----------------------------------------------------------- |
|
||||
| complete(struct completion *x) | 表明一个事件被完成,从等待队列中唤醒一个进程 |
|
||||
| complete_all(struct completion *x) | 表明与该completion有关的事件被标记为永久完成,并唤醒等待队列中的所有进程 |
|
||||
|
||||
|
||||
### 其他用于查询信息的函数
|
||||
| 函数名 | 解释 |
|
||||
| ----------------------------------- | ----------------------------------------------------------- |
|
||||
| completion_done(struct completion *x) | 查询completion的done变量是不是大于0,如果大于0,返回true;否则返回false。在等待前加上这个函数有可能加速?(暂未经过实验测试,有待证明) |
|
||||
| try_wait_for_completion(struct completion *x) | 查询completion的done变量是不是大于0,如果大于0,返回true(同时令done-=1);否则返回false。在等待前加上这个函数有可能加速?(该函数和`completion_done`代码逻辑基本一致,但是会主动令completion的done变量减1) |
|
||||
|
||||
|
||||
|
47
kernel/common/completion.h
Normal file
47
kernel/common/completion.h
Normal file
@ -0,0 +1,47 @@
|
||||
#include <common/spinlock.h>
|
||||
#include <common/wait_queue_head.h>
|
||||
#include <process/process.h>
|
||||
#include <time/sleep.h>
|
||||
#include <time/timer.h>
|
||||
|
||||
// 永久地设置该completion已经被完成,不会再有进程等待
|
||||
#define COMPLETE_ALL UINT32_MAX
|
||||
|
||||
struct completion
|
||||
{
|
||||
unsigned int done;
|
||||
wait_queue_head_t wait_queue;
|
||||
};
|
||||
|
||||
#define DECLARE_COMPLETION_ON_STACK(name) \
|
||||
struct completion name = {0}; \
|
||||
completion_init(&name);
|
||||
|
||||
/**
|
||||
* 对外函数声明
|
||||
*/
|
||||
void completion_init(struct completion *x);
|
||||
void complete(struct completion *x);
|
||||
void complete_all(struct completion *x);
|
||||
void wait_for_completion(struct completion *x);
|
||||
long wait_for_completion_timeout(struct completion *x, long timeout);
|
||||
void wait_for_completion_interruptible(struct completion *x);
|
||||
long wait_for_completion_interruptible_timeout(struct completion *x, long timeout);
|
||||
void wait_for_multicompletion(struct completion x[], int n);
|
||||
bool try_wait_for_completion(struct completion *x);
|
||||
bool completion_done(struct completion *x);
|
||||
|
||||
/**
|
||||
* 测试函数声明 (测试代码辅助函数)
|
||||
*/
|
||||
struct __test_data
|
||||
{
|
||||
int id;
|
||||
struct completion *one_to_one;
|
||||
struct completion *one_to_many;
|
||||
struct completion *many_to_one;
|
||||
};
|
||||
|
||||
int __test_completion_waiter(void *data); // 等待者
|
||||
int __test_completion_worker(void *data); // 执行者
|
||||
void __test_completion();
|
@ -21,29 +21,29 @@ void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待
|
||||
*
|
||||
*
|
||||
* @param wait_queue_head 队列头指针
|
||||
*/
|
||||
void wait_queue_sleep_on(wait_queue_node_t * wait_queue_head);
|
||||
void wait_queue_sleep_on(wait_queue_node_t *wait_queue_head);
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待,同时释放自旋锁
|
||||
*
|
||||
*
|
||||
* @param wait_queue_head 队列头指针
|
||||
*/
|
||||
void wait_queue_sleep_on_unlock(wait_queue_node_t *wait_queue_head,
|
||||
void *lock);
|
||||
/**
|
||||
* @brief 在等待队列上进行等待(允许中断)
|
||||
*
|
||||
*
|
||||
* @param wait_queue_head 队列头指针
|
||||
*/
|
||||
void wait_queue_sleep_on_interriptible(wait_queue_node_t * wait_queue_head);
|
||||
void wait_queue_sleep_on_interriptible(wait_queue_node_t *wait_queue_head);
|
||||
|
||||
/**
|
||||
* @brief 唤醒在等待队列的头部的进程
|
||||
*
|
||||
*
|
||||
* @param wait_queue_head 队列头
|
||||
* @param state 要唤醒的进程的状态
|
||||
*/
|
||||
void wait_queue_wakeup(wait_queue_node_t * wait_queue_head, int64_t state);
|
||||
void wait_queue_wakeup(wait_queue_node_t *wait_queue_head, int64_t state);
|
68
kernel/common/wait_queue_head.h
Normal file
68
kernel/common/wait_queue_head.h
Normal file
@ -0,0 +1,68 @@
|
||||
#include <common/spinlock.h>
|
||||
#include <common/wait_queue.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct List wait_list;
|
||||
spinlock_t lock; // 队列需要有一个自旋锁,虽然目前内部并没有使用,但是以后可能会用.[在completion内部使用]
|
||||
} wait_queue_head_t;
|
||||
|
||||
#define DECLARE_WAIT_ON_STACK(name, pcb) \
|
||||
wait_queue_node_t name = {0}; \
|
||||
wait_queue_init(&(name), pcb);
|
||||
|
||||
#define DECLARE_WAIT_ON_STACK_SELF(name) \
|
||||
wait_queue_node_t name = {0}; \
|
||||
wait_queue_init(&(name), current_pcb);
|
||||
|
||||
#define DECLARE_WAIT_ALLOC(name, pcb) \
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0); \
|
||||
wait_queue_init(&(name), pcb);
|
||||
|
||||
#define DECLARE_WAIT_ALLOC_SELF(name) \
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0); \
|
||||
wait_queue_init(&(name), current_pcb);
|
||||
|
||||
#define DECLARE_WAIT_QUEUE_HEAD(name) \
|
||||
struct wait_queue_head_t name = {0}; \
|
||||
wait_queue_head_init(&name);
|
||||
|
||||
/**
|
||||
* @brief 初始化wait_queue队列头
|
||||
*
|
||||
* @param wait_queue
|
||||
*/
|
||||
void wait_queue_head_init(wait_queue_head_t *wait_queue);
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
|
||||
*
|
||||
* @param q 队列头指针
|
||||
* @param wait wait节点
|
||||
*/
|
||||
void wait_queue_sleep_with_node(wait_queue_head_t *q, wait_queue_node_t *wait);
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待,同时释放自旋锁, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
|
||||
*
|
||||
* @param q 队列头指针
|
||||
* @param wait wait节点
|
||||
* @param lock
|
||||
*/
|
||||
void wait_queue_sleep_with_node_unlock(wait_queue_head_t *q, wait_queue_node_t *wait, void *lock);
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待(允许中断), 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
|
||||
*
|
||||
* @param wait_queue_head 队列头指针
|
||||
* @param wait wait节点
|
||||
*/
|
||||
void wait_queue_sleep_with_node_interriptible(wait_queue_head_t *q, wait_queue_node_t *wait);
|
||||
|
||||
/**
|
||||
* @brief 唤醒在等待队列的头部的进程, 但是不会free掉这个节点的空间(默认这个节点在栈上创建)
|
||||
*
|
||||
* @param wait_queue_head_t q: 队列头
|
||||
* @param state 要唤醒的进程的状态
|
||||
*/
|
||||
void wait_queue_wakeup_on_stack(wait_queue_head_t *q, int64_t state);
|
@ -54,12 +54,11 @@ int video_refresh_daemon(void *unused)
|
||||
{
|
||||
// 初始化锁, 这个锁只会在daemon中使用
|
||||
spin_init(&daemon_refresh_lock);
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (clock() >= video_refresh_expire_jiffies)
|
||||
{
|
||||
video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1);
|
||||
|
||||
if (likely(video_refresh_target != NULL))
|
||||
{
|
||||
@ -68,6 +67,7 @@ int video_refresh_daemon(void *unused)
|
||||
video_refresh_target->size);
|
||||
spin_unlock(&daemon_refresh_lock);
|
||||
}
|
||||
video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1);
|
||||
}
|
||||
video_daemon_pcb->flags &= ~PROC_RUNNING;
|
||||
sched();
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <common/wait_queue.h>
|
||||
#include <sched/sched.h>
|
||||
#include <process/process.h>
|
||||
#include <mm/slab.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <common/wait_queue.h>
|
||||
#include <mm/slab.h>
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
|
||||
/**
|
||||
* @brief 初始化等待队列
|
||||
@ -23,7 +23,7 @@ void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block
|
||||
*/
|
||||
void wait_queue_sleep_on(wait_queue_node_t *wait_queue_head)
|
||||
{
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kmalloc(sizeof(wait_queue_node_t), 0);
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0);
|
||||
wait_queue_init(wait, current_pcb);
|
||||
current_pcb->state = PROC_UNINTERRUPTIBLE;
|
||||
list_append(&wait_queue_head->wait_list, &wait->wait_list);
|
||||
@ -39,7 +39,7 @@ void wait_queue_sleep_on(wait_queue_node_t *wait_queue_head)
|
||||
void wait_queue_sleep_on_unlock(wait_queue_node_t *wait_queue_head,
|
||||
void *lock)
|
||||
{
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kmalloc(sizeof(wait_queue_node_t), 0);
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0);
|
||||
wait_queue_init(wait, current_pcb);
|
||||
current_pcb->state = PROC_UNINTERRUPTIBLE;
|
||||
list_append(&wait_queue_head->wait_list, &wait->wait_list);
|
||||
@ -54,7 +54,7 @@ void wait_queue_sleep_on_unlock(wait_queue_node_t *wait_queue_head,
|
||||
*/
|
||||
void wait_queue_sleep_on_interriptible(wait_queue_node_t *wait_queue_head)
|
||||
{
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kmalloc(sizeof(wait_queue_node_t), 0);
|
||||
wait_queue_node_t *wait = (wait_queue_node_t *)kzalloc(sizeof(wait_queue_node_t), 0);
|
||||
wait_queue_init(wait, current_pcb);
|
||||
current_pcb->state = PROC_INTERRUPTIBLE;
|
||||
list_append(&wait_queue_head->wait_list, &wait->wait_list);
|
||||
|
82
kernel/lib/wait_queue_head.c
Normal file
82
kernel/lib/wait_queue_head.c
Normal file
@ -0,0 +1,82 @@
|
||||
#include <common/wait_queue_head.h>
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
|
||||
/**
|
||||
* @brief 初始化等待队列
|
||||
*
|
||||
* @param wait_queue 等待队列
|
||||
* @param pcb pcb
|
||||
*/
|
||||
void wait_queue_head_init(wait_queue_head_t *wait_queue)
|
||||
{
|
||||
list_init(&wait_queue->wait_list);
|
||||
spin_init(&wait_queue->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
|
||||
*
|
||||
* @param wait_queue_head 队列头指针
|
||||
*/
|
||||
void wait_queue_sleep_with_node(wait_queue_head_t *q, wait_queue_node_t *wait)
|
||||
{
|
||||
BUG_ON(wait->pcb == NULL);
|
||||
|
||||
wait->pcb->state = PROC_UNINTERRUPTIBLE;
|
||||
list_append(&q->wait_list, &wait->wait_list);
|
||||
|
||||
sched();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待,同时释放自旋锁, 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
|
||||
*
|
||||
* @param wait_queue_head 队列头指针
|
||||
*/
|
||||
void wait_queue_sleep_with_node_unlock(wait_queue_head_t *q, wait_queue_node_t *wait, void *lock)
|
||||
{
|
||||
BUG_ON(wait->pcb == NULL);
|
||||
|
||||
wait->pcb->state = PROC_UNINTERRUPTIBLE;
|
||||
list_append(&q->wait_list, &wait->wait_list);
|
||||
spin_unlock((spinlock_t *)lock);
|
||||
|
||||
sched();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在等待队列上进行等待(允许中断), 但是你需要确保wait已经被init, 同时wakeup只能使用wake_up_on_stack函数。
|
||||
*
|
||||
* @param wait_queue_head 队列头指针
|
||||
*/
|
||||
void wait_queue_sleep_with_node_interriptible(wait_queue_head_t *q, wait_queue_node_t *wait)
|
||||
{
|
||||
BUG_ON(wait->pcb == NULL);
|
||||
|
||||
wait->pcb->state = PROC_INTERRUPTIBLE;
|
||||
list_append(&q->wait_list, &wait->wait_list);
|
||||
|
||||
sched();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 唤醒在等待队列的头部的进程, 但是不会free掉这个节点的空间(默认这个节点在栈上创建)
|
||||
*
|
||||
* @param wait_queue_head
|
||||
* @param state
|
||||
*/
|
||||
void wait_queue_wakeup_on_stack(wait_queue_head_t *q, int64_t state)
|
||||
{
|
||||
if (list_empty(&q->wait_list))
|
||||
return;
|
||||
|
||||
wait_queue_node_t *wait = container_of(list_next(&q->wait_list), wait_queue_node_t, wait_list);
|
||||
|
||||
// 符合唤醒条件
|
||||
if (wait->pcb->state & state)
|
||||
{
|
||||
list_del_init(&wait->wait_list);
|
||||
process_wakeup(wait->pcb);
|
||||
}
|
||||
}
|
@ -3,40 +3,40 @@
|
||||
//
|
||||
|
||||
#include "common/glib.h"
|
||||
#include "common/printk.h"
|
||||
#include "common/kprint.h"
|
||||
#include "common/printk.h"
|
||||
#include "exception/gate.h"
|
||||
#include "exception/trap.h"
|
||||
#include "exception/irq.h"
|
||||
#include <exception/softirq.h>
|
||||
#include <lib/libUI/screen_manager.h>
|
||||
#include <lib/libUI/textui.h>
|
||||
#include "exception/trap.h"
|
||||
#include "mm/mm.h"
|
||||
#include "mm/slab.h"
|
||||
#include "process/process.h"
|
||||
#include "syscall/syscall.h"
|
||||
#include "smp/smp.h"
|
||||
#include <smp/ipi.h>
|
||||
#include "syscall/syscall.h"
|
||||
#include <exception/softirq.h>
|
||||
#include <lib/libUI/screen_manager.h>
|
||||
#include <lib/libUI/textui.h>
|
||||
#include <sched/sched.h>
|
||||
#include <smp/ipi.h>
|
||||
|
||||
#include <filesystem/fat32/fat32.h>
|
||||
#include <filesystem/VFS/VFS.h>
|
||||
#include <filesystem/devfs/devfs.h>
|
||||
#include <filesystem/fat32/fat32.h>
|
||||
|
||||
#include "driver/multiboot2/multiboot2.h"
|
||||
#include "driver/acpi/acpi.h"
|
||||
#include "driver/keyboard/ps2_keyboard.h"
|
||||
#include "driver/tty/tty.h"
|
||||
#include "driver/mouse/ps2_mouse.h"
|
||||
#include "driver/disk/ata.h"
|
||||
#include "driver/pci/pci.h"
|
||||
#include <driver/usb/usb.h>
|
||||
#include "driver/disk/ahci/ahci.h"
|
||||
#include <driver/timers/rtc/rtc.h>
|
||||
#include "driver/disk/ata.h"
|
||||
#include "driver/keyboard/ps2_keyboard.h"
|
||||
#include "driver/mouse/ps2_mouse.h"
|
||||
#include "driver/multiboot2/multiboot2.h"
|
||||
#include "driver/pci/pci.h"
|
||||
#include "driver/tty/tty.h"
|
||||
#include <driver/timers/HPET/HPET.h>
|
||||
#include <time/timer.h>
|
||||
#include <driver/timers/rtc/rtc.h>
|
||||
#include <driver/uart/uart.h>
|
||||
#include <driver/usb/usb.h>
|
||||
#include <driver/video/video.h>
|
||||
#include <time/timer.h>
|
||||
|
||||
#include <driver/interrupt/apic/apic_timer.h>
|
||||
|
||||
@ -52,8 +52,7 @@ void reload_gdt()
|
||||
gdtp.size = bsp_gdt_size - 1;
|
||||
gdtp.gdt_vaddr = (ul)phys_2_virt((ul)&GDT_Table);
|
||||
|
||||
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp)
|
||||
: "memory");
|
||||
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp) : "memory");
|
||||
}
|
||||
|
||||
void reload_idt()
|
||||
@ -64,8 +63,7 @@ void reload_idt()
|
||||
// kdebug("gdtvaddr=%#018lx", p.gdt_vaddr);
|
||||
// kdebug("gdt size=%d", p.size);
|
||||
|
||||
asm volatile("lidt (%0) \n\t" ::"r"(&idtp)
|
||||
: "memory");
|
||||
asm volatile("lidt (%0) \n\t" ::"r"(&idtp) : "memory");
|
||||
}
|
||||
|
||||
// 初始化系统各模块
|
||||
@ -86,8 +84,8 @@ void system_initialize()
|
||||
kdebug("_stack_start=%#018lx", _stack_start);
|
||||
|
||||
load_TR(10); // 加载TR寄存器
|
||||
set_tss64((uint *)&initial_tss[0], _stack_start, _stack_start, _stack_start, tss_item_addr,
|
||||
tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr);
|
||||
set_tss64((uint *)&initial_tss[0], _stack_start, _stack_start, _stack_start, tss_item_addr, tss_item_addr,
|
||||
tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr);
|
||||
|
||||
cpu_core_info[0].stack_start = _stack_start;
|
||||
cpu_core_info[0].tss_vaddr = (uint64_t)&initial_tss[0];
|
||||
@ -206,7 +204,20 @@ void Start_Kernel(void)
|
||||
system_initialize();
|
||||
io_mfence();
|
||||
|
||||
// idle
|
||||
while (1)
|
||||
pause();
|
||||
{
|
||||
// 如果调用的时候,启用了中断,则hlt。否则认为是bug
|
||||
if (get_rflags() & 0x200)
|
||||
{
|
||||
kdebug("hlt");
|
||||
hlt();
|
||||
}
|
||||
else
|
||||
{
|
||||
BUG_ON(1);
|
||||
pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma GCC pop_options
|
@ -65,7 +65,7 @@ static struct process_control_block *__kthread_create_on_node(int (*thread_fn)(v
|
||||
spin_lock(&__kthread_create_lock);
|
||||
list_append(&kthread_create_list, &create->list);
|
||||
spin_unlock(&__kthread_create_lock);
|
||||
kdebug("to wakeup kthread daemon..., current preempt=%d, rflags=%#018lx", current_pcb->preempt_count, get_rflags());
|
||||
// kdebug("to wakeup kthread daemon..., current preempt=%d, rflags=%#018lx", current_pcb->preempt_count, get_rflags());
|
||||
while (kthreadd_pcb == NULL) // 若kthreadd未初始化,则等待kthreadd启动
|
||||
;
|
||||
// 唤醒kthreadd守护进程
|
||||
@ -170,7 +170,9 @@ static int kthread(void *_create)
|
||||
// 将当前pcb返回给创建者
|
||||
create->result = current_pcb;
|
||||
|
||||
current_pcb->state &= ~PROC_RUNNING; // 设置当前进程不是RUNNING态
|
||||
current_pcb->state &= ~PROC_RUNNING; // 设置当前进程不是RUNNING态
|
||||
io_mfence();
|
||||
|
||||
// 发起调度,使得当前内核线程休眠。直到创建者通过process_wakeup将当前内核线程唤醒
|
||||
sched();
|
||||
|
||||
@ -186,6 +188,7 @@ static int kthread(void *_create)
|
||||
static void __create_kthread(struct kthread_create_info_t *create)
|
||||
{
|
||||
pid_t pid = kernel_thread(kthread, create, CLONE_FS | CLONE_SIGNAL);
|
||||
io_mfence();
|
||||
if (IS_ERR((void *)pid))
|
||||
{
|
||||
// todo: 使用complete机制完善这里
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "process.h"
|
||||
|
||||
#include <common/compiler.h>
|
||||
#include <common/completion.h>
|
||||
#include <common/elf.h>
|
||||
#include <common/kprint.h>
|
||||
#include <common/kthread.h>
|
||||
@ -501,6 +502,9 @@ ul initial_kernel_thread(ul arg)
|
||||
|
||||
kinfo("LZ4 lib Version=%s", LZ4_versionString());
|
||||
|
||||
// 对completion完成量进行测试
|
||||
__test_completion();
|
||||
|
||||
// 对一些组件进行单元测试
|
||||
uint64_t tpid[] = {
|
||||
ktest_start(ktest_test_bitree, 0), ktest_start(ktest_test_kfifo, 0), ktest_start(ktest_test_mutex, 0),
|
||||
@ -1204,9 +1208,9 @@ int process_fd_alloc(struct vfs_file_t *file)
|
||||
*/
|
||||
static void __set_pcb_name(struct process_control_block *pcb, const char *pcb_name)
|
||||
{
|
||||
//todo:给pcb加锁
|
||||
// spin_lock(&pcb->alloc_lock);
|
||||
strncpy(pcb->name,pcb_name,PCB_NAME_LEN);
|
||||
// todo:给pcb加锁
|
||||
// spin_lock(&pcb->alloc_lock);
|
||||
strncpy(pcb->name, pcb_name, PCB_NAME_LEN);
|
||||
// spin_unlock(&pcb->alloc_lock);
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,17 @@
|
||||
CFLAGS += -I .
|
||||
|
||||
|
||||
all: sched.o cfs.o
|
||||
kernel_sched_objs:= $(shell find ./*.c)
|
||||
|
||||
ECHO:
|
||||
@echo "$@"
|
||||
|
||||
|
||||
$(kernel_sched_objs): ECHO
|
||||
$(CC) $(CFLAGS) -c $@ -o $@.o
|
||||
|
||||
all: $(kernel_sched_objs)
|
||||
|
||||
cfs.o: cfs.c
|
||||
$(CC) $(CFLAGS) -c cfs.c -o cfs.o
|
||||
|
||||
sched.o: sched.c
|
||||
$(CC) $(CFLAGS) -c sched.c -o sched.o
|
||||
clean:
|
||||
echo "Done."
|
328
kernel/sched/completion.c
Normal file
328
kernel/sched/completion.c
Normal file
@ -0,0 +1,328 @@
|
||||
#include "common/completion.h"
|
||||
#include "common/kthread.h"
|
||||
|
||||
/**
|
||||
* @brief 初始化一个completion变量
|
||||
*
|
||||
* @param x completion
|
||||
*/
|
||||
void completion_init(struct completion *x)
|
||||
{
|
||||
x->done = 0;
|
||||
wait_queue_head_init(&x->wait_queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 唤醒一个wait_queue中的节点
|
||||
*
|
||||
* @param x completion
|
||||
*/
|
||||
void complete(struct completion *x)
|
||||
{
|
||||
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
|
||||
if (x->done != COMPLETE_ALL)
|
||||
++(x->done);
|
||||
wait_queue_wakeup_on_stack(&x->wait_queue, -1UL); // -1UL代表所有节点都满足条件,暂时这么写
|
||||
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 永久标记done为Complete_All, 并从wait_queue中删除所有节点
|
||||
*
|
||||
* @param x completion
|
||||
*/
|
||||
void complete_all(struct completion *x)
|
||||
{
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
|
||||
x->done = COMPLETE_ALL; // 永久赋值
|
||||
while (!list_empty(&x->wait_queue.wait_list))
|
||||
wait_queue_wakeup_on_stack(&x->wait_queue, -1UL); // -1UL代表所有节点都满足条件,暂时这么写
|
||||
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 辅助函数:通用的处理wait命令的函数(即所有wait_for_completion函数最核心部分在这里)
|
||||
*
|
||||
* @param x completion
|
||||
* @param action 函数指针
|
||||
* @param timeout 一个非负整数
|
||||
* @param state 你要设置进程的状态为state
|
||||
* @return long - 返回剩余的timeout
|
||||
*/
|
||||
static long __wait_for_common(struct completion *x, long (*action)(long), long timeout, int state)
|
||||
{
|
||||
if (!x->done)
|
||||
{
|
||||
DECLARE_WAIT_ON_STACK_SELF(wait);
|
||||
|
||||
while (!x->done && timeout > 0)
|
||||
{
|
||||
// 加入等待队列, 但是不会调度走
|
||||
if (list_empty(&wait.wait_list))
|
||||
list_append(&x->wait_queue.wait_list, &wait.wait_list);
|
||||
wait.pcb->state = state; // 清除运行位, 并设置为interuptible/uninteruptible
|
||||
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
|
||||
timeout = action(timeout);
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
}
|
||||
if (!x->done)
|
||||
return timeout; // 仍然没有complete, 但是被其他进程唤醒
|
||||
|
||||
wait.pcb->state = PROC_RUNNING; // 设置为运行, 并清空state, 所以使用等号赋值
|
||||
if (!list_empty(&wait.wait_list))
|
||||
list_del_init(&wait.wait_list); // 必须使用del_init
|
||||
}
|
||||
if (x->done != COMPLETE_ALL)
|
||||
--(x->done);
|
||||
return timeout ? timeout : 1; // 这里linux返回1,不知道为啥
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待completion命令唤醒进程, 同时设置pcb->state为uninteruptible.
|
||||
*
|
||||
* @param x completion
|
||||
*/
|
||||
void wait_for_completion(struct completion *x)
|
||||
{
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
__wait_for_common(x, &schedule_timeout_ms, MAX_TIMEOUT, PROC_UNINTERRUPTIBLE);
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待指定时间,超时后就返回, 同时设置pcb->state为uninteruptible.
|
||||
*
|
||||
* @param x completion
|
||||
* @param timeout 非负整数,等待指定时间,超时后就返回/ 或者提前done,则返回剩余timeout时间
|
||||
* @return long - 返回剩余的timeout
|
||||
*/
|
||||
long wait_for_completion_timeout(struct completion *x, long timeout)
|
||||
{
|
||||
BUG_ON(timeout < 0);
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
timeout = __wait_for_common(x, &schedule_timeout_ms, timeout, PROC_UNINTERRUPTIBLE);
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待completion的完成,但是可以被中断(我也不太懂可以被中断是什么意思,就是pcb->state=interuptible)
|
||||
*
|
||||
* @param x completion
|
||||
*/
|
||||
void wait_for_completion_interruptible(struct completion *x)
|
||||
{
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
__wait_for_common(x, &schedule_timeout_ms, MAX_TIMEOUT, PROC_INTERRUPTIBLE);
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待指定时间,超时后就返回, 等待completion的完成,但是可以被中断.
|
||||
*
|
||||
* @param x completion
|
||||
* @param timeout 非负整数,等待指定时间,超时后就返回/ 或者提前done,则返回剩余timeout时间
|
||||
* @return long - 返回剩余的timeout
|
||||
*/
|
||||
long wait_for_completion_interruptible_timeout(struct completion *x, long timeout)
|
||||
{
|
||||
BUG_ON(timeout < 0);
|
||||
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
timeout = __wait_for_common(x, &schedule_timeout_ms, timeout, PROC_INTERRUPTIBLE);
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 尝试获取completion的一个done!如果您在wait之前加上这个函数作为判断,说不定会加快运行速度。
|
||||
*
|
||||
* @param x completion
|
||||
* @return true - 表示不需要wait_for_completion,并且已经获取到了一个completion(即返回true意味着done已经被 减1 ) \
|
||||
* @return false - 表示当前done=0,您需要进入等待,即wait_for_completion
|
||||
*/
|
||||
bool try_wait_for_completion(struct completion *x)
|
||||
{
|
||||
if (!READ_ONCE(x->done))
|
||||
return false;
|
||||
|
||||
bool ret = true;
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
|
||||
if (!x->done)
|
||||
ret = false;
|
||||
else if (x->done != COMPLETE_ALL)
|
||||
--(x->done);
|
||||
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试一个completion是否有waiter。(即done是不是等于0)
|
||||
*
|
||||
* @param x completion
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool completion_done(struct completion *x)
|
||||
{
|
||||
|
||||
if (!READ_ONCE(x->done))
|
||||
return false;
|
||||
|
||||
// 这里的意义是: 如果是多线程的情况下,您有可能需要等待另一个进程的complete操作, 才算真正意义上的completed!
|
||||
spin_lock(&x->wait_queue.lock);
|
||||
|
||||
if (!READ_ONCE(x->done))
|
||||
{
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
return false;
|
||||
}
|
||||
spin_unlock(&x->wait_queue.lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对completion数组进行wait操作
|
||||
*
|
||||
* @param x completion array
|
||||
* @param n len of the array
|
||||
*/
|
||||
void wait_for_multicompletion(struct completion x[], int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) // 对每一个completion都等一遍
|
||||
{
|
||||
if (!completion_done(&x[i])) // 如果没有done,直接wait
|
||||
{
|
||||
wait_for_completion(&x[i]);
|
||||
}
|
||||
else if (!try_wait_for_completion(&x[i])) //上面测试过done>0,那么这里尝试去获取一个done,如果失败了,就继续wait
|
||||
{
|
||||
wait_for_completion(&x[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待者, 等待wait_for_completion
|
||||
*
|
||||
* @param one_to_one
|
||||
* @param one_to_many
|
||||
* @param many_to_one
|
||||
*/
|
||||
int __test_completion_waiter(void *input_data)
|
||||
{
|
||||
struct __test_data *data = (struct __test_data *)input_data;
|
||||
// kdebug("THE %d WAITER BEGIN", -data->id);
|
||||
// 测试一对多能不能实现等待 - 由外部统一放闸一起跑
|
||||
if (!try_wait_for_completion(data->one_to_many))
|
||||
{
|
||||
wait_for_completion(data->one_to_many);
|
||||
}
|
||||
|
||||
// 测试一对一能不能实现等待
|
||||
if (!try_wait_for_completion(data->one_to_many))
|
||||
{
|
||||
wait_for_completion(data->one_to_many);
|
||||
}
|
||||
|
||||
// 完成上面两个等待, 执行complete声明自己已经完成
|
||||
complete(data->many_to_one);
|
||||
// kdebug("THE %d WAITER SOLVED", -data->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行者,执行complete
|
||||
*
|
||||
* @param one_to_one
|
||||
* @param one_to_many
|
||||
* @param many_to_one
|
||||
*/
|
||||
int __test_completion_worker(void *input_data)
|
||||
{
|
||||
struct __test_data *data = (struct __test_data *)input_data;
|
||||
// kdebug("THE %d WORKER BEGIN", data->id);
|
||||
// 测试一对多能不能实现等待 - 由外部统一放闸一起跑
|
||||
if (!try_wait_for_completion(data->one_to_many))
|
||||
{
|
||||
wait_for_completion(data->one_to_many);
|
||||
}
|
||||
|
||||
schedule_timeout_ms(50);
|
||||
// for(uint64_t i=0;i<1e7;++i)
|
||||
// pause();
|
||||
complete(data->one_to_one);
|
||||
|
||||
// 完成上面两个等待, 执行complete声明自己已经完成
|
||||
complete(data->many_to_one);
|
||||
// kdebug("THE %d WORKER SOLVED", data->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试函数
|
||||
*
|
||||
*/
|
||||
void __test_completion()
|
||||
{
|
||||
// kdebug("BEGIN COMPLETION TEST");
|
||||
const int N = 100;
|
||||
struct completion *one_to_one = kzalloc(sizeof(struct completion) * N, 0);
|
||||
struct completion *one_to_many = kzalloc(sizeof(struct completion), 0);
|
||||
struct completion *waiter_many_to_one = kzalloc(sizeof(struct completion) * N, 0);
|
||||
struct completion *worker_many_to_one = kzalloc(sizeof(struct completion) * N, 0);
|
||||
struct __test_data *waiter_data = kzalloc(sizeof(struct __test_data) * N, 0);
|
||||
struct __test_data *worker_data = kzalloc(sizeof(struct __test_data) * N, 0);
|
||||
|
||||
completion_init(one_to_many);
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
completion_init(&one_to_one[i]);
|
||||
completion_init(&waiter_many_to_one[i]);
|
||||
completion_init(&worker_many_to_one[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
waiter_data[i].id = -i; // waiter
|
||||
waiter_data[i].many_to_one = &waiter_many_to_one[i];
|
||||
waiter_data[i].one_to_one = &one_to_one[i];
|
||||
waiter_data[i].one_to_many = one_to_many;
|
||||
kthread_run(__test_completion_waiter, &waiter_data[i], "the %dth waiter", i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
worker_data[i].id = i; // worker
|
||||
worker_data[i].many_to_one = &worker_many_to_one[i];
|
||||
worker_data[i].one_to_one = &one_to_one[i];
|
||||
worker_data[i].one_to_many = one_to_many;
|
||||
kthread_run(__test_completion_worker, &worker_data[i], "the %dth worker", i);
|
||||
}
|
||||
|
||||
complete_all(one_to_many);
|
||||
// kdebug("all of the waiters and workers begin running");
|
||||
|
||||
// kdebug("BEGIN COUNTING");
|
||||
|
||||
wait_for_multicompletion(waiter_many_to_one, N);
|
||||
wait_for_multicompletion(worker_many_to_one, N);
|
||||
// kdebug("all of the waiters and workers complete");
|
||||
|
||||
kfree(one_to_one);
|
||||
kfree(one_to_many);
|
||||
kfree(waiter_many_to_one);
|
||||
kfree(worker_many_to_one);
|
||||
kfree(waiter_data);
|
||||
kfree(worker_data);
|
||||
// kdebug("completion test done.");
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
#include "timer.h"
|
||||
#include <common/kprint.h>
|
||||
#include <driver/timers/HPET/HPET.h>
|
||||
#include <exception/softirq.h>
|
||||
#include <mm/slab.h>
|
||||
#include <driver/timers/HPET/HPET.h>
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
|
||||
struct timer_func_list_t timer_func_head;
|
||||
static spinlock_t sched_lock;
|
||||
|
||||
// 定时器循环阈值,每次最大执行10个定时器任务
|
||||
#define TIMER_RUN_CYCLE_THRESHOLD 10
|
||||
// 定时器循环阈值,每次最大执行20个定时器任务
|
||||
#define TIMER_RUN_CYCLE_THRESHOLD 20
|
||||
|
||||
void test_timer()
|
||||
{
|
||||
@ -17,6 +19,8 @@ void test_timer()
|
||||
|
||||
void timer_init()
|
||||
{
|
||||
spin_init(&sched_lock);
|
||||
|
||||
timer_jiffies = 0;
|
||||
timer_func_init(&timer_func_head, NULL, NULL, -1UL);
|
||||
register_softirq(TIMER_SIRQ, &do_timer_softirq, NULL);
|
||||
@ -28,19 +32,31 @@ void timer_init()
|
||||
kdebug("timer func initialized.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理时间软中断
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
void do_timer_softirq(void *data)
|
||||
{
|
||||
// todo: 修改这里以及softirq的部分,使得timer具有并行性
|
||||
// todo: 修改这里以及 softirq 的部分,使得 timer 具有并行性
|
||||
struct timer_func_list_t *tmp = container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list);
|
||||
int cycle_count = 0;
|
||||
while ((!list_empty(&timer_func_head.list)) && (tmp->expire_jiffies <= timer_jiffies))
|
||||
{
|
||||
spin_lock(&sched_lock);
|
||||
|
||||
timer_func_del(tmp);
|
||||
tmp->func(tmp->data);
|
||||
kfree(tmp);
|
||||
|
||||
spin_unlock(&sched_lock);
|
||||
|
||||
++cycle_count;
|
||||
|
||||
|
||||
// kdebug("SOLVE SOFT IRQ %d", cycle_count);
|
||||
|
||||
// 当前定时器达到阈值
|
||||
if (cycle_count == TIMER_RUN_CYCLE_THRESHOLD)
|
||||
break;
|
||||
@ -116,3 +132,47 @@ uint64_t clock()
|
||||
{
|
||||
return timer_jiffies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 辅助函数:传进schedule_timeout函数中, 然后时间一到就唤醒 pcb 指向的进程(即自身)
|
||||
*
|
||||
* @param pcb process_control_block
|
||||
*/
|
||||
static void __wake_up_helper(void *pcb)
|
||||
{
|
||||
BUG_ON(pcb == NULL);
|
||||
|
||||
BUG_ON(process_wakeup((struct process_control_block *)pcb) != 0); // 正常唤醒,返回值为0
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 睡眠timeout的时间之后唤醒进程/线程
|
||||
*
|
||||
* @param timeout
|
||||
* @return long
|
||||
*/
|
||||
long schedule_timeout_ms(long timeout)
|
||||
{
|
||||
if (timeout == MAX_TIMEOUT) // 无期停止, 意味着不会调用func
|
||||
{
|
||||
sched();
|
||||
return MAX_TIMEOUT;
|
||||
}
|
||||
else if (timeout < 0)
|
||||
{
|
||||
BUG_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&sched_lock);
|
||||
struct timer_func_list_t timer={0};
|
||||
timer_func_init(&timer, &__wake_up_helper, current_pcb, timeout);
|
||||
timer_func_add(&timer);
|
||||
current_pcb->state &= ~(PROC_RUNNING);
|
||||
spin_unlock(&sched_lock);
|
||||
sched();
|
||||
|
||||
timeout -= timer_jiffies;
|
||||
|
||||
return timeout < 0 ? 0 : timeout;
|
||||
}
|
@ -4,6 +4,9 @@
|
||||
#include <driver/timers/HPET/HPET.h>
|
||||
#include <driver/timers/rtc/rtc.h>
|
||||
|
||||
// 定义LONG_MAX为最大超时时间 - 允许负数
|
||||
#define MAX_TIMEOUT (int64_t)((1ul << 63) - 1)
|
||||
|
||||
uint64_t volatile timer_jiffies = 0; // 系统时钟计数
|
||||
|
||||
// 计算接下来n毫秒对应的系统时间片
|
||||
@ -63,3 +66,11 @@ void timer_func_add(struct timer_func_list_t *timer_func);
|
||||
void timer_func_del(struct timer_func_list_t *timer_func);
|
||||
|
||||
uint64_t clock();
|
||||
|
||||
/**
|
||||
* @brief 睡眠timeout的时间之后唤醒进程/线程
|
||||
*
|
||||
* @param timeout
|
||||
* @return long
|
||||
*/
|
||||
long schedule_timeout_ms(long timeout);
|
Loading…
x
Reference in New Issue
Block a user