10.9让进程能够延时运行
增加一个延时队列(C语言里面sleep()函数的底层原理)
让CPU定时扫描延时队列,然后task结构体在多加一个字段,用来表示延时队列的延时时间,然后CPU定时扫描这些字段,看定时的字段有没有自减到0,自减到0了就看延时队列里面有没有task,然后将延完时的task加到就绪队列的末尾
//task.h
typedef struct _task_t {
```
int sleep_ticks; // 睡眠时间,单位ms
```
}task_t;
void task_set_sleep(task_t *task, uint32_t ticks); //插入的是那个进程,想睡眠多久
void task_set_wakeup (task_t *task); //从休眠队列移出去
void sys_msleep (uint32_t ms); //延时多少毫秒
//task.c
/**
* @brief 将任务加入睡眠状态
*/
void task_set_sleep(task_t *task, uint32_t ticks) {
if (ticks <= 0) {
return;
}
task->sleep_ticks = ticks;
task->state = TASK_SLEEP;
list_insert_last(&task_manager.sleep_list, &task->run_node); //将run_node插入sleep_list表项的末尾
}
/**
* @brief 将任务从延时队列移除
*/
void task_set_wakeup (task_t *task) {
list_remove(&task_manager.sleep_list, &task->run_node); //移出指定链表中的特定表项
}
/**
* @brief 任务进入睡眠状态
*
* @param ms
*/
void sys_msleep (uint32_t ms) {
// 至少延时1个tick
if (ms < OS_TICK_MS) { //不能少于10ms,10ms/单位
ms = OS_TICK_MS;
}
irq_state_t state = irq_enter_protection();
// 从就绪队列移除,加入睡眠队列
task_set_block(task_manager.curr_task);
task_set_sleep(task_manager.curr_task, (ms + (OS_TICK_MS - 1))/ OS_TICK_MS); //向上取整的操作
// 进行一次调度
task_dispatch();
irq_leave_protection(state);
}
//前面准备工作都搞好了,现在是具体怎么定时
/**
* @brief 时间处理
* 该函数在中断处理函数中调用
*/
void task_time_tick (void) { //定时中断处理
task_t * curr_task = task_current();
// 时间片的处理
irq_state_t state = irq_enter_protection();
if (--curr_task->slice_ticks == 0)
// 时间片用完,重新加载时间片
// 对于空闲任务,此处减未用
curr_task->slice_ticks = 10;
// 调整队列的位置到尾部,不用直接操作队列
task_set_block(curr_task);
task_set_ready(curr_task);
}
// 睡眠处理
list_node_t * curr = list_first(&task_manager.sleep_list);
while (curr) {
list_node_t * next = list_node_next(curr); //先将后继节点取出来,这里的顺序很重要
task_t * task = list_node_parent(curr, task_t, run_node);
if (--task->sleep_ticks == 0) {
// 延时时间到达,从睡眠队列中移除,送至就绪队列
task_set_wakeup(task);
task_set_ready(task);
}
curr = next;
}
task_dispatch();
irq_leave_protection(state);
}