SimpleKernel 1.17.0
Loading...
Searching...
No Matches
wait.cpp
Go to the documentation of this file.
1
5#include <cassert>
6
7#include "expected.hpp"
8#include "kernel_log.hpp"
9#include "resource_id.hpp"
10#include "task_manager.hpp"
11#include "task_messages.hpp"
12
13auto TaskManager::Wait(Pid pid, int* status, bool no_hang, bool untraced)
14 -> Expected<Pid> {
15 auto* current = GetCurrentTask();
16 assert(current != nullptr && "Wait: No current task");
17 assert(current->GetStatus() == TaskStatus::kRunning &&
18 "Wait: current task status must be kRunning");
19
20 while (true) {
21 TaskControlBlock* target = nullptr;
22
23 {
24 LockGuard lock_guard(task_table_lock_);
25
26 // 遍历任务表寻找符合条件的子进程
27 for (auto& [task_pid, task] : task_table_) {
28 // 检查是否是当前进程的子进程
29 bool is_child = (task->aux->parent_pid == current->pid);
30
31 // 检查 PID 匹配条件
32 bool pid_match = false;
33 if (pid == static_cast<Pid>(-1)) {
34 // 等待任意子进程
35 pid_match = is_child;
36 } else if (pid == 0) {
37 // 等待同进程组的任意子进程
38 pid_match = is_child && (task->aux->pgid == current->aux->pgid);
39 } else if (pid > 0) {
40 // 等待指定 PID 的子进程
41 pid_match = is_child && (task->pid == pid);
42 } else {
43 // pid < -1: 等待进程组 ID 为 |pid| 的任意子进程
44 pid_match = is_child && (task->aux->pgid == static_cast<Pid>(-pid));
45 }
46
47 if (!pid_match) {
48 continue;
49 }
50
51 // 检查任务状态
52 if (task->GetStatus() == TaskStatus::kZombie ||
53 task->GetStatus() == TaskStatus::kExited) {
54 target = task.get();
55 break;
56 }
57
58 // untraced: 报告已停止的子进程
59 if (untraced && task->GetStatus() == TaskStatus::kBlocked) {
60 if (status) {
61 // 表示停止状态
62 *status = 0;
63 }
64 return task->pid;
65 }
66 }
67 }
68
69 // 找到了退出的子进程
70 if (target) {
71 assert((target->GetStatus() == TaskStatus::kZombie ||
72 target->GetStatus() == TaskStatus::kExited) &&
73 "Wait: target task must be kZombie or kExited");
74 assert(target->aux->parent_pid == current->pid &&
75 "Wait: target parent_pid must match current pid");
76
77 Pid result_pid = target->pid;
78
79 // 返回退出状态
80 if (status) {
81 *status = target->aux->exit_code;
82 }
83
84 // 清理僵尸进程
85 {
86 LockGuard lock_guard(task_table_lock_);
87 auto it = task_table_.find(target->pid);
88 assert(it != task_table_.end() &&
89 "Wait: target must exist in task_table");
90 task_table_.erase(it->first);
91 }
92
93 klog::Debug("Wait: pid={} reaped child={}", current->pid, result_pid);
94 return result_pid;
95 }
96
97 // 如果设置了 no_hang,立即返回
98 if (no_hang) {
99 return 0;
100 }
101
102 // 没有找到符合条件的子进程,阻塞等待
103 // 使用 ChildExit 类型的资源 ID,数据部分是当前进程的 PID
104 auto wait_resource_id = ResourceId(ResourceType::kChildExit, current->pid);
105
106 Block(wait_resource_id);
107
108 klog::Debug("Wait: pid={} blocked on resource={}, data={}", current->pid,
109 wait_resource_id.GetTypeName(),
110 static_cast<uint64_t>(wait_resource_id.GetData()));
111 // 被唤醒后重新检查
112 }
113}
RAII 风格的锁守卫模板类
Definition spinlock.hpp:131
资源 ID
auto Wait(Pid pid, int *status, bool no_hang=false, bool untraced=false) -> Expected< Pid >
等待子进程退出
Definition wait.cpp:13
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
constexpr etl::fsm_state_id_t kExited
Definition task_fsm.hpp:19
constexpr etl::fsm_state_id_t kZombie
Definition task_fsm.hpp:20
constexpr etl::fsm_state_id_t kBlocked
Definition task_fsm.hpp:18
constexpr etl::fsm_state_id_t kRunning
Definition task_fsm.hpp:16
auto Debug(etl::format_string< Args... > fmt, Args &&... args) -> void
以 DEBUG 级别记录日志(SIMPLEKERNEL_MIN_LOG_LEVEL > 0 时编译期消除)
@ kChildExit
等待子进程退出
Pid parent_pid
父线程 ID
int exit_code
退出码
任务控制块,管理进程/线程的核心数据结构
auto GetStatus() const -> etl::fsm_state_id_t
获取当前任务状态
Pid pid
线程 ID (Task ID)
TaskAuxData * aux
非调度热路径的辅助数据
size_t Pid
进程 ID 类型