SimpleKernel 1.17.0
Loading...
Searching...
No Matches
task_manager.cpp
Go to the documentation of this file.
1
5#include "task_manager.hpp"
6
7#include <cpu_io.h>
8#include <etl/vector.h>
9
10#include <algorithm>
11#include <cassert>
12#include <limits>
13#include <memory>
14#include <new>
15
16#include "basic_info.hpp"
17#include "fifo_scheduler.hpp"
18#include "idle_scheduler.hpp"
19#include "kernel_config.hpp"
20#include "kernel_elf.hpp"
21#include "kernel_log.hpp"
22#include "kstd_cstring"
23#include "rr_scheduler.hpp"
24#include "sk_stdlib.h"
25#include "task_messages.hpp"
26#include "virtual_memory.hpp"
27
28namespace {
29
31auto IdleThread(void*) -> void {
32 while (true) {
34 }
35}
36
37} // namespace
38
41 auto& cpu_sched = cpu_schedulers_[core_id];
42
43 LockGuard lock_guard{cpu_sched.lock};
44
45 if (!cpu_sched.schedulers[static_cast<uint8_t>(SchedPolicy::kNormal)]) {
46 cpu_sched.schedulers[static_cast<uint8_t>(SchedPolicy::kRealTime)] =
47 kstd::make_unique<FifoScheduler>();
48 cpu_sched.schedulers[static_cast<uint8_t>(SchedPolicy::kNormal)] =
49 kstd::make_unique<RoundRobinScheduler>();
50 cpu_sched.schedulers[static_cast<uint8_t>(SchedPolicy::kIdle)] =
51 kstd::make_unique<IdleScheduler>();
52 }
53
54 // 关联 PerCpu
55 auto& cpu_data = per_cpu::GetCurrentCore();
56 cpu_data.sched_data = &cpu_sched;
57
58 // 创建 boot 任务作为当前执行上下文的占位符
59 // 首次 Schedule():
60 // current(boot_task) != next(idle_task) -> switch_to -> idle_thread
61 auto boot_task_ptr = kstd::make_unique<TaskControlBlock>(
62 "Boot",
63 std::numeric_limits<
65 nullptr, nullptr);
66 auto* boot_task = boot_task_ptr.release();
67 // kUnInit -> kReady
68 boot_task->fsm.Receive(MsgSchedule{});
69 // kReady -> kRunning
70 boot_task->fsm.Receive(MsgSchedule{});
71 boot_task->policy = SchedPolicy::kIdle;
72 cpu_data.running_task = boot_task;
73
74 // 创建独立的 Idle 线程
75 auto idle_task_ptr = kstd::make_unique<TaskControlBlock>(
76 "Idle",
77 std::numeric_limits<
79 IdleThread, nullptr);
80 auto* idle_task = idle_task_ptr.release();
81 // kUnInit -> kReady
84
85 // 将 idle 任务加入 Idle 调度器
86 if (cpu_sched.schedulers[static_cast<uint8_t>(SchedPolicy::kIdle)]) {
87 cpu_sched.schedulers[static_cast<uint8_t>(SchedPolicy::kIdle)]->Enqueue(
88 idle_task);
89 }
90
91 cpu_data.idle_task = idle_task;
92}
93
94auto TaskManager::AddTask(etl::unique_ptr<TaskControlBlock> task) -> void {
95 assert(task.get() != nullptr && "AddTask: task must not be null");
96 assert(task->GetStatus() == TaskStatus::kUnInit &&
97 "AddTask: task status must be kUnInit");
98 // 分配 PID
99 if (task->pid == 0) {
100 task->pid = AllocatePid();
101 }
102
103 // 如果 tgid 未设置,则将其设为自己的 pid (单线程进程或线程组的主线程)
104 if (task->aux->tgid == 0) {
105 task->aux->tgid = task->pid;
106 }
107
108 auto* task_ptr = task.get();
109 Pid pid = task_ptr->pid;
110
111 // 加入全局任务表
112 {
113 LockGuard lock_guard{task_table_lock_};
114 if (task_table_.full()) {
115 klog::Err("AddTask: task_table_ full, cannot add task (pid={})", pid);
116 return;
117 }
118 task_table_[pid] = std::move(task);
119 }
120
121 // 设置任务状态为 kReady
122 // Transition: kUnInit -> kReady
123 task_ptr->fsm.Receive(MsgSchedule{});
124
125 // 简单的负载均衡:如果指定了亲和性,放入对应核心,否则放入当前核心
126 // 更复杂的逻辑可以是:寻找最空闲的核心
127 size_t target_core = cpu_io::GetCurrentCoreId();
128
129 if (task_ptr->aux->cpu_affinity.value() != UINT64_MAX) {
130 // 寻找第一个允许的核心
131 for (size_t core_id = 0; core_id < SIMPLEKERNEL_MAX_CORE_COUNT; ++core_id) {
132 if (task_ptr->aux->cpu_affinity.value() & (1UL << core_id)) {
133 target_core = core_id;
134 break;
135 }
136 }
137 }
138
139 auto& cpu_sched = cpu_schedulers_[target_core];
140
141 {
142 LockGuard<SpinLock> lock_guard(cpu_sched.lock);
143 if (task_ptr->policy < SchedPolicy::kPolicyCount) {
144 if (cpu_sched.schedulers[static_cast<uint8_t>(task_ptr->policy)]) {
145 cpu_sched.schedulers[static_cast<uint8_t>(task_ptr->policy)]->Enqueue(
146 task_ptr);
147 }
148 }
149 }
150
151 // 如果是当前核心,且添加了比当前任务优先级更高的任务,触发抢占
152 if (target_core == cpu_io::GetCurrentCoreId()) {
153 auto& cpu_data = per_cpu::GetCurrentCore();
154 TaskControlBlock* current = cpu_data.running_task;
155 // 如果当前是 idle 任务,或新任务的策略优先级更高,触发调度
156 if (current == cpu_data.idle_task ||
157 (current && task_ptr->policy < current->policy)) {
158 // 注意:这里不能直接调用 Schedule(),因为可能在中断上下文中
159 // 实际应该设置一个 need_resched 标志,在中断返回前检查
160 // 为简化,这里暂时不做抢占,只在时间片耗尽时调度
161 }
162 }
163}
164
165auto TaskManager::AllocatePid() -> size_t {
172 return pid_allocator_.fetch_add(1);
173}
174
176 LockGuard lock_guard{task_table_lock_};
177 auto it = task_table_.find(pid);
178 return (it != task_table_.end()) ? it->second.get() : nullptr;
179}
180
181auto TaskManager::Balance() -> void {
182 // 算法留空
183 // TODO: 检查其他核心的运行队列长度,如果比当前核心长,则窃取任务
184}
185
187 if (!task) {
188 return;
189 }
190
191 // 确保任务处于僵尸或退出状态
192 if (task->GetStatus() != TaskStatus::kZombie &&
193 task->GetStatus() != TaskStatus::kExited) {
194 klog::Warn("ReapTask: Task {} is not in zombie/exited state", task->pid);
195 return;
196 }
197
198 // Capture pid before erase (unique_ptr deletes on erase)
199 Pid pid = task->pid;
200
201 // 从全局任务表中移除 (unique_ptr auto-deletes TCB)
202 {
203 LockGuard lock_guard{task_table_lock_};
204 task_table_.erase(pid);
205 }
206
207 klog::Debug("ReapTask: Task {} resources freed", pid);
208}
209
211 if (!parent) {
212 return;
213 }
214
215 // init 进程的 PID 通常是 1
217 static constexpr Pid kInitPid = 1;
218
219 LockGuard lock_guard{task_table_lock_};
220
221 // 遍历所有任务,找到父进程是当前任务的子进程
222 for (auto& [pid, task] : task_table_) {
223 if (task && task->aux->parent_pid == parent->pid) {
224 // 将子进程过继给 init 进程
225 task->aux->parent_pid = kInitPid;
226 klog::Debug("ReparentChildren: Task {} reparented to init (PID {})",
227 task->pid, kInitPid);
228 // 如果子进程已经是僵尸状态,通知 init 进程回收
230 }
231 }
232}
233
235 -> etl::vector<TaskControlBlock*, kernel::config::kMaxReadyTasks> {
236 etl::vector<TaskControlBlock*, kernel::config::kMaxReadyTasks> result;
237
238 LockGuard lock_guard(task_table_lock_);
239
240 // 遍历任务表,找到所有 tgid 匹配的线程
241 for (auto& [pid, task] : task_table_) {
242 if (task && task->aux->tgid == tgid) {
243 result.push_back(task.get());
244 }
245 }
246
247 return result;
248}
249
250auto TaskManager::SignalThreadGroup(Pid tgid, int signal) -> void {
252 klog::Debug("SignalThreadGroup: tgid={}, signal={} (not implemented)", tgid,
253 signal);
254
255 // 预期实现:
256 // auto threads = GetThreadGroup(tgid);
257 // for (auto* thread : threads) {
258 // SendSignal(thread, signal);
259 // }
260}
261
263 // unique_ptr in cpu_schedulers_.schedulers[] auto-deletes on destruction
264}
RAII 风格的锁守卫模板类
Definition spinlock.hpp:131
auto Receive(const etl::imessage &msg) -> void
向 FSM 发送消息
Definition task_fsm.hpp:163
auto AddTask(etl::unique_ptr< TaskControlBlock > task) -> void
添加任务(接管所有权)
auto ReapTask(TaskControlBlock *task) -> void
回收僵尸进程资源
auto ReparentChildren(TaskControlBlock *parent) -> void
将孤儿进程过继给 init 进程
auto AllocatePid() -> size_t
分配新的 PID
auto InitCurrentCore() -> void
初始化 per cpu 的调度数据,创建 idle 线程
auto Balance() -> void
负载均衡 (空闲 core 窃取任务)
auto FindTask(Pid pid) -> TaskControlBlock *
按 PID 查找任务
auto SignalThreadGroup(Pid tgid, int signal) -> void
向线程组中的所有线程发送信号
auto GetThreadGroup(Pid tgid) -> etl::vector< TaskControlBlock *, kernel::config::kMaxReadyTasks >
获取线程组的所有线程
constexpr etl::fsm_state_id_t kExited
Definition task_fsm.hpp:19
constexpr etl::fsm_state_id_t kUnInit
Definition task_fsm.hpp:14
constexpr etl::fsm_state_id_t kZombie
Definition task_fsm.hpp:20
auto GetCurrentCoreId() -> size_t
Definition cpu_io.h:26
void Pause()
Definition cpu_io.h:20
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Debug(etl::format_string< Args... > fmt, Args &&... args) -> void
以 DEBUG 级别记录日志(SIMPLEKERNEL_MIN_LOG_LEVEL > 0 时编译期消除)
auto Warn(etl::format_string< Args... > fmt, Args &&... args) -> void
以 WARN 级别记录日志
static __always_inline auto GetCurrentCore() -> PerCpu &
获取当前核心的 PerCpu 数据
Definition per_cpu.hpp:55
TaskControlBlock * idle_task
空闲任务
Definition per_cpu.hpp:6
size_t core_id
核心 ID
Definition per_cpu.hpp:1
调度消息(无负载,用作事件)
int priority
优先级 (数字越小优先级越高)
任务控制块,管理进程/线程的核心数据结构
SchedPolicy policy
调度策略
TaskFsm fsm
任务状态机
@ kNormal
普通任务
@ kPolicyCount
策略数量
@ kRealTime
实时任务 (最高优先级)
@ kIdle
空闲任务 (最低优先级)
size_t Pid
进程 ID 类型