SimpleKernel 1.17.0
Loading...
Searching...
No Matches
schedule.cpp
Go to the documentation of this file.
1
5#include <cpu_io.h>
6
7#include <algorithm>
8#include <cassert>
9#include <memory>
10#include <new>
11
12#include "arch.h"
13#include "basic_info.hpp"
14#include "fifo_scheduler.hpp"
15#include "interrupt_base.h"
16#include "kernel_elf.hpp"
17#include "kernel_log.hpp"
18#include "kstd_cstring"
19#include "per_cpu.hpp"
20#include "sk_stdlib.h"
21#include "spinlock.hpp"
22#include "task_manager.hpp"
23#include "task_messages.hpp"
24#include "virtual_memory.hpp"
25
26auto TaskManager::Schedule() -> void {
27 auto& cpu_sched = GetCurrentCpuSched();
28 cpu_sched.scheduler_started = true;
29 cpu_sched.lock.Lock().or_else([](auto&& err) {
30 klog::Err("Schedule: Failed to acquire lock: {}", err.message());
31 while (true) {
33 }
34 return Expected<void>{};
35 });
36
37 auto* current = GetCurrentTask();
38 assert(current != nullptr && "Schedule: No current task to schedule");
39
40 // 处理当前任务状态
41 if (current->GetStatus() == TaskStatus::kRunning) {
42 // 将当前任务标记为就绪并重新入队(如果它还能运行)
43 current->fsm.Receive(MsgYield{});
44 auto* scheduler =
45 cpu_sched.schedulers[static_cast<uint8_t>(current->policy)].get();
46
47 if (scheduler) {
48 scheduler->OnPreempted(current);
49 // 调度器决定如何处理被抢占的任务
50 // 大多数情况下需要重新入队,除非是特殊策略
51 if (scheduler->OnTimeSliceExpired(current)) {
52 scheduler->Enqueue(current);
53 }
54 }
55 }
56
57 // 选择下一个任务 (按策略优先级: RealTime > Normal > Idle)
58 TaskControlBlock* next = nullptr;
59 for (auto& scheduler : cpu_sched.schedulers) {
60 if (scheduler && !scheduler->IsEmpty()) {
61 next = scheduler->PickNext();
62 if (next) {
63 break;
64 }
65 }
66 }
67
68 // 如果没有任务可运行
69 if (!next) {
70 // 如果当前任务仍然可以运行,继续运行它
71 if (current->GetStatus() == TaskStatus::kReady) {
72 next = current;
73 } else {
74 // 否则统计空闲时间并返回
75 cpu_sched.idle_time++;
76 cpu_sched.lock.UnLock().or_else([](auto&& err) {
77 klog::Err("Schedule: Failed to release lock: {}", err.message());
78 while (true) {
80 }
81 return Expected<void>{};
82 });
83 return;
84 }
85 }
86
87 // 切换到下一个任务
88 assert(next != nullptr && "Schedule: next task must not be null");
89 assert((next->GetStatus() == TaskStatus::kReady ||
90 next->policy == SchedPolicy::kIdle) &&
91 "Schedule: next task must be kReady or kIdle policy");
92
93 next->fsm.Receive(MsgSchedule{});
94 // 重置时间片(对于 RR 和 FIFO 有效,CFS 使用 vruntime 不依赖此字段)
97 cpu_sched.total_schedules++;
98
99 // 调用调度器钩子
100 auto* scheduler =
101 cpu_sched.schedulers[static_cast<uint8_t>(next->policy)].get();
102 if (scheduler) {
103 scheduler->OnScheduled(next);
104 }
105
106 // 更新 per-CPU running_task
107 per_cpu::GetCurrentCore().running_task = next;
108
109 cpu_sched.lock.UnLock().or_else([](auto&& err) {
110 klog::Err("Schedule: Failed to release lock: {}", err.message());
111 while (true) {
113 }
114 return Expected<void>{};
115 });
116
117 // 上下文切换
118 if (current != next) {
119 switch_to(&current->task_context, &next->task_context);
120 }
121}
auto switch_to(cpu_io::CalleeSavedContext *prev, cpu_io::CalleeSavedContext *next) -> void
Definition arch.cpp:15
auto Receive(const etl::imessage &msg) -> void
向 FSM 发送消息
Definition task_fsm.hpp:163
auto Schedule() -> void
调度函数 选择下一个任务并切换上下文
Definition schedule.cpp:26
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
constexpr etl::fsm_state_id_t kReady
Definition task_fsm.hpp:15
constexpr etl::fsm_state_id_t kRunning
Definition task_fsm.hpp:16
void Pause()
Definition cpu_io.h:20
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
static __always_inline auto GetCurrentCore() -> PerCpu &
获取当前核心的 PerCpu 数据
Definition per_cpu.hpp:55
调度消息(无负载,用作事件)
让出消息(无负载,用作事件)
uint64_t time_slice_default
默认时间片
uint64_t context_switches
上下文切换次数
uint64_t time_slice_remaining
剩余时间片
任务控制块,管理进程/线程的核心数据结构
SchedPolicy policy
调度策略
struct TaskControlBlock::SchedInfo sched_info
TaskFsm fsm
任务状态机
auto GetStatus() const -> etl::fsm_state_id_t
获取当前任务状态
cpu_io::CalleeSavedContext task_context
任务上下文
@ kIdle
空闲任务 (最低优先级)