os/kernel/task/task_struct.rs
1//! 任务结构体定义
2//!
3//! 包含任务的核心信息,如上下文、状态、内存空间等
4#![allow(dead_code)]
5use core::sync::atomic::{AtomicPtr, Ordering};
6
7use alloc::{sync::Arc, vec::Vec};
8
9use crate::{
10 arch::{
11 kernel::{context::Context, task::setup_stack_layout},
12 trap::TrapFrame,
13 },
14 ipc::{SignalHandlerTable, SignalPending},
15 kernel::{
16 WaitQueue,
17 task::{forkret, task_state::TaskState},
18 },
19 mm::{
20 address::{ConvertablePaddr, PageNum, UsizeConvert},
21 frame_allocator::{FrameRangeTracker, FrameTracker},
22 memory_space::MemorySpace,
23 },
24 pr_debug,
25 sync::SpinLock,
26 uapi::{
27 resource::RlimitStruct,
28 signal::{SignalFlags, SignalStack},
29 uts_namespace::UtsNamespace,
30 },
31 vfs::{Dentry, FDTable},
32};
33
34/// 共享任务句柄
35/// 用于在多个地方引用同一个任务实例
36pub type SharedTask = Arc<SpinLock<Task>>;
37
38/// 任务
39/// 存放任务的核心信息
40/// 其中的信息可以分为几大类:
41/// 1. 调度运行相关的信息,如上下文、状态、优先级等
42/// 2. 任务标识信息,如 tid、pid、ppid、子任务等
43/// 3. 任务资源信息,如内核栈、TrapFrame、内存空间等
44/// 表示进程的任务与表示线程的任务由本结构体统一表征
45/// 其区别仅在于:
46/// 1. 进程的 pid 等于 tid,线程的 pid 不等于 tid
47/// 2. 进程的返回值通过 exit_code 字段传递,线程的返回值通过 return_value 字段传递
48/// 3. 对于所有3.类信息,均通过引用计数共享。创建时任务,进程需传入新的`Arc<T>`,而线程则共享父任务的资源。
49/// 注意:线程拥有自己独立的运行栈,和一套寄存器上下文。
50/// TrapFrame,Context结构可以保证所有线程切换时保存和恢复寄存器状态。
51/// 每个任务的内核栈独立分配,互不干扰。内核线程只使用内核栈。
52/// 但是上层必须自己保证创建的用户线程在用户态运行时拥有独立的用户栈空间。
53/// OPTIMIZE: 简单起见目前的设计中,Task 结构体包含了所有信息,包括调度相关的信息和资源管理相关的信息。
54/// 未来可以考虑将其拆分为 TaskInfo 和 TaskStruct 两个部分,以提高访问效率和模块化程度。
55#[derive(Debug)]
56pub struct Task {
57 /// 任务的上下文信息,用于任务切换
58 pub context: Context,
59 /// 任务的抢占计数器,表示当前任务被禁止抢占的次数
60 /// 当该值大于0时,表示任务处于不可抢占状态。暂未使用
61 pub preempt_count: usize,
62 /// 任务的优先级,数值越小优先级越高。暂未使用
63 pub priority: u8,
64 /// 任务所在的处理器id。暂未使用
65 pub processor_id: usize,
66 /// 任务当前的状态
67 pub state: TaskState,
68 /// 任务的id
69 pub tid: u32,
70 /// 任务的所属进程id
71 /// NOTE: 由于采用了统一的任务模型,一个任务组内任务的 pid 是相同的,等于父任务的 pid 而父任务的 pid 等于自己的 tid
72 pub pid: u32,
73 /// 父任务的id
74 pub ppid: u32,
75 /// 任务的进程组id
76 pub pgid: u32,
77 /// 任务的子任务列表
78 pub children: Arc<SpinLock<Vec<SharedTask>>>,
79 /// 任务的等待队列
80 pub wait_child: Arc<SpinLock<WaitQueue>>,
81 /// 内核栈基址
82 pub kstack_base: usize,
83 /// 中断上下文。指向当前任务内核栈上的 TrapFrame,仅在任务被中断时有效。
84 pub trap_frame_ptr: AtomicPtr<TrapFrame>,
85 /// 任务的内存空间
86 /// 对于内核任务,该字段为 None
87 pub memory_space: Option<Arc<SpinLock<MemorySpace>>>,
88 /// 退出码
89 /// 存储任务退出时的状态码,通常用于表示任务的执行结果
90 /// 由 exit 接口设置
91 /// 对应于 waitpid 的 exit_status
92 pub exit_code: Option<i32>,
93 /// 内核栈跟踪器
94 kstack_tracker: FrameRangeTracker,
95 /// 任务的 TrapFrame 跟踪器
96 trap_frame_tracker: FrameTracker,
97 /// 信号屏蔽字
98 pub blocked: SignalFlags,
99 /// 私有待处理信号集合
100 pub pending: SignalPending,
101 /// 待处理信号队列
102 pub shared_pending: Arc<SpinLock<SignalPending>>,
103 /// 信号处理动作表
104 pub signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
105 /// 备用信号栈信息
106 pub signal_stack: Arc<SpinLock<SignalStack>>,
107 /// 退出信号, 当任务退出时发送给父任务的信号
108 pub exit_signal: u8,
109 /// UTS 命名空间
110 pub uts_namespace: Arc<SpinLock<UtsNamespace>>,
111 /// 资源限制结构体
112 pub rlimit: Arc<SpinLock<RlimitStruct>>,
113 /// 健壮列表头地址及其大小
114 pub robust_list: Option<usize>,
115 /// 线程ID地址
116 pub set_child_tid: usize,
117 /// 线程退出时清除的线程ID地址
118 pub clear_child_tid: usize,
119
120 // === 权限和凭证 ===
121 /// 任务凭证(用户、组、能力)
122 pub credential: super::Credential,
123 /// 文件创建掩码
124 pub umask: u32,
125
126 // === 文件系统 ===
127 /// 文件描述符表
128 pub fd_table: Arc<FDTable>,
129 /// 文件系统信息
130 pub fs: Arc<SpinLock<FsStruct>>,
131}
132
133/// 文件系统信息相关结构体
134#[derive(Debug, Clone)]
135pub struct FsStruct {
136 /// 当前工作目录
137 pub cwd: Option<Arc<Dentry>>,
138 /// 根目录
139 pub root: Option<Arc<Dentry>>,
140}
141
142impl FsStruct {
143 pub fn new(cwd: Option<Arc<Dentry>>, root: Option<Arc<Dentry>>) -> Self {
144 Self { cwd, root }
145 }
146}
147
148impl Task {
149 /// 为内核线程初始化任务上下文
150 /// # 参数
151 /// * `tid`: 任务ID
152 /// * `pid`: 进程ID
153 /// * `ppid`: 父任务ID
154 /// * `kstack_tracker`: 内核栈的帧跟踪器
155 /// * `trap_frame_tracker`: TrapFrame 的帧跟踪器
156 /// * `entry`: 任务的入口地址
157 /// # 返回值
158 /// 新创建的任务
159 /// 注意:调用者必须自己初始化TrapFrame内容
160 pub fn ktask_create(
161 tid: u32,
162 pid: u32,
163 ppid: u32,
164 children: Arc<SpinLock<Vec<Arc<SpinLock<Task>>>>>,
165 kstack_tracker: FrameRangeTracker,
166 trap_frame_tracker: FrameTracker,
167 signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
168 blocked: SignalFlags,
169 signal: Arc<SpinLock<SignalPending>>,
170 uts_namespace: Arc<SpinLock<UtsNamespace>>,
171 rlimit: Arc<SpinLock<RlimitStruct>>,
172 fd_table: Arc<FDTable>,
173 fs: Arc<SpinLock<FsStruct>>,
174 ) -> Self {
175 let mut task = Self::new(
176 tid,
177 pid,
178 ppid,
179 tid, // 内核线程不属于常规意义的进程组
180 children,
181 kstack_tracker,
182 trap_frame_tracker,
183 None,
184 signal_handlers,
185 blocked,
186 signal,
187 Arc::new(SpinLock::new(SignalStack::default())), // 内核线程通常不使用备用信号栈
188 0, // 内核线程退出不通过IPC发送信号
189 uts_namespace,
190 rlimit,
191 fd_table,
192 fs,
193 );
194 task.context
195 .set_init_context(forkret as usize, task.kstack_base);
196 task
197 }
198
199 /// 创建一个新的用户任务
200 /// # 参数
201 /// * `ppid`: 父任务ID
202 /// * `memory_space`: 任务的内存空间
203 /// # 返回值
204 /// 新创建的任务
205 /// 注意:调用者必须自己初始化TrapFrame内容
206 pub fn utask_create(
207 tid: u32,
208 pid: u32,
209 ppid: u32,
210 pgid: u32,
211 children: Arc<SpinLock<Vec<Arc<SpinLock<Task>>>>>,
212 kstack_tracker: FrameRangeTracker,
213 trap_frame_tracker: FrameTracker,
214 memory_space: Arc<SpinLock<MemorySpace>>,
215 signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
216 blocked: SignalFlags,
217 signal: Arc<SpinLock<SignalPending>>,
218 signal_stack: Arc<SpinLock<SignalStack>>,
219 exit_signal: u8,
220 uts_namespace: Arc<SpinLock<UtsNamespace>>,
221 rlimit: Arc<SpinLock<RlimitStruct>>,
222 fd_table: Arc<FDTable>,
223 fs: Arc<SpinLock<FsStruct>>,
224 ) -> Self {
225 let mut task = Self::new(
226 tid,
227 pid,
228 ppid,
229 pgid,
230 children,
231 kstack_tracker,
232 trap_frame_tracker,
233 Some(memory_space),
234 signal_handlers,
235 blocked,
236 signal,
237 signal_stack,
238 exit_signal,
239 uts_namespace,
240 rlimit,
241 fd_table,
242 fs,
243 );
244 task.context
245 .set_init_context(forkret as usize, task.kstack_base);
246 task
247 }
248
249 /// 执行 execve 操作,替换当前任务的内存空间和上下文
250 /// # 参数
251 /// * `new_memory_space`: 新的内存空间
252 /// * `entry_point`: 新程序的入口地址
253 /// * `sp`: 新程序的栈指针
254 /// * `argv`: 传递给新程序的参数列表
255 /// * `envp`: 传递给新程序的环境变量列表
256 pub fn execve(
257 &mut self,
258 new_memory_space: Arc<SpinLock<MemorySpace>>,
259 entry_point: usize,
260 sp_high: usize,
261 argv: &[&str],
262 envp: &[&str],
263 phdr_addr: usize,
264 phnum: usize,
265 phent: usize,
266 ) {
267 // 1. 切换任务的地址空间对象
268 self.memory_space = Some(new_memory_space);
269
270 // 2. 处理文件描述符:取消共享并关闭 CLOEXEC 文件
271 // execve 应该让当前进程拥有独立的 FD 表(如果之前是共享的)
272 // 并且关闭所有标记为 FD_CLOEXEC 的文件
273 let new_fd_table = self.fd_table.clone_table();
274 new_fd_table.close_exec();
275 self.fd_table = Arc::new(new_fd_table);
276
277 let tf_ptr = self.trap_frame_ptr.load(Ordering::SeqCst);
278
279 // 注意:以下拷贝时对sp进行的操作均要求已经可以访问用户栈空间
280 // 也就是说,new_memory_space 已经被激活(切换 satp)
281 // 否则必须实现类似 copy_to_user 的函数来完成拷贝,不然会引发页错误
282 // 3. 设置用户栈布局,包含命令行参数和环境变量
283 let (new_sp, argc, argv_vec_ptr, envp_vec_ptr) =
284 setup_stack_layout(sp_high, argv, envp, phdr_addr, phnum, phent, entry_point);
285
286 // 4. 配置 TrapFrame (新的上下文)
287 // SAFETY: tfptr 指向的内存已经被分配且可写,并由 task 拥有
288 unsafe {
289 // 清零整个 TrapFrame,避免旧值泄漏到用户态
290 core::ptr::write_bytes(tf_ptr, 0, 1);
291 (*tf_ptr).set_exec_trap_frame(
292 entry_point,
293 new_sp,
294 self.kstack_base,
295 argc,
296 argv_vec_ptr,
297 envp_vec_ptr,
298 );
299 }
300 }
301
302 /// 检查是否有满足条件的子任务
303 /// # 参数
304 /// * `cond`: 用于检查子任务的条件闭包
305 /// * `remove`: 是否在找到后从子任务列表中移除该僵尸子任务(如果是)
306 /// # 返回值
307 /// 如果有,返回该子任务的共享句柄. 如果没有,返回 None
308 /// 注意:此函数不阻塞,调用者需持有锁
309 pub fn check_child(
310 &mut self,
311 cond: impl FnMut(&SharedTask) -> bool,
312 remove: bool,
313 ) -> Option<SharedTask> {
314 let mut children_guard = self.children.lock();
315 if let Some(idx) = children_guard.iter().position(cond) {
316 let child = children_guard[idx].clone();
317 if remove && child.lock().state == TaskState::Zombie {
318 children_guard.remove(idx);
319 }
320 return Some(child);
321 }
322 None
323 }
324
325 pub fn notify_child_exit(&mut self) {
326 self.wait_child.lock().wake_up_one();
327 }
328
329 /// 判断该任务是否为内核线程
330 pub fn is_kernel_thread(&self) -> bool {
331 self.memory_space.is_none()
332 }
333
334 /// 判断该任务是否为进程 / 主线程
335 /// 对于进程,其 pid 等于 tid
336 pub fn is_process(&self) -> bool {
337 self.pid == self.tid
338 }
339
340 /// 把已初始化的 TaskStruct 包装为共享任务句柄
341 /// 返回值: 包装后的 SharedTask
342 pub fn into_shared(self) -> SharedTask {
343 Arc::new(SpinLock::new(self))
344 }
345
346 /// 返回一个空的子任务列表
347 /// 用于创建新任务时初始化 children 字段
348 pub fn empty_children() -> Arc<SpinLock<Vec<SharedTask>>> {
349 Arc::new(SpinLock::new(Vec::new()))
350 }
351
352 fn new(
353 tid: u32,
354 pid: u32,
355 ppid: u32,
356 pgid: u32,
357 children: Arc<SpinLock<Vec<SharedTask>>>,
358 kstack_tracker: FrameRangeTracker,
359 trap_frame_tracker: FrameTracker,
360 memory_space: Option<Arc<SpinLock<MemorySpace>>>,
361 signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
362 blocked: SignalFlags,
363 shared_pending: Arc<SpinLock<SignalPending>>,
364 signal_stack: Arc<SpinLock<SignalStack>>,
365 exit_signal: u8,
366 uts_namespace: Arc<SpinLock<UtsNamespace>>,
367 rlimit: Arc<SpinLock<RlimitStruct>>,
368 fd_table: Arc<FDTable>,
369 fs: Arc<SpinLock<FsStruct>>,
370 ) -> Self {
371 let trap_frame_ptr = trap_frame_tracker.ppn().start_addr().to_vaddr().as_usize();
372 let kstack_base = kstack_tracker.end_ppn().start_addr().to_vaddr().as_usize();
373
374 Task {
375 context: Context::zero_init(),
376 preempt_count: 0,
377 priority: 0,
378 processor_id: 0,
379 state: TaskState::Running,
380 tid,
381 pid,
382 ppid,
383 pgid,
384 children,
385 wait_child: Arc::new(SpinLock::new(WaitQueue::new())),
386 kstack_base,
387 kstack_tracker,
388 trap_frame_tracker,
389 trap_frame_ptr: AtomicPtr::new(trap_frame_ptr as *mut TrapFrame),
390 memory_space,
391 exit_code: None,
392 signal_handlers,
393 signal_stack,
394 exit_signal,
395 uts_namespace,
396 rlimit,
397 blocked,
398 pending: SignalPending::empty(),
399 shared_pending,
400 robust_list: None,
401 set_child_tid: 0,
402 clear_child_tid: 0,
403 credential: super::Credential::root(),
404 umask: 0o022,
405 fd_table,
406 fs,
407 }
408 }
409
410 #[cfg(test)]
411 pub fn new_dummy_task(tid: u32) -> Self {
412 use crate::{
413 mm::frame_allocator::{alloc_contig_frames, alloc_frame},
414 uapi::resource::INIT_RLIMITS,
415 };
416 let kstack_tracker =
417 alloc_contig_frames(1).expect("new_dummy_task: failed to alloc kstack");
418 let trap_frame_tracker = alloc_frame().expect("new_dummy_task: failed to alloc trap_frame");
419 Self::new(
420 tid,
421 tid,
422 0,
423 0,
424 Task::empty_children(),
425 kstack_tracker,
426 trap_frame_tracker,
427 None,
428 Arc::new(SpinLock::new(SignalHandlerTable::new())),
429 SignalFlags::empty(),
430 Arc::new(SpinLock::new(SignalPending::empty())),
431 Arc::new(SpinLock::new(SignalStack::default())),
432 0,
433 Arc::new(SpinLock::new(UtsNamespace::default())),
434 Arc::new(SpinLock::new(RlimitStruct::new(INIT_RLIMITS))),
435 Arc::new(FDTable::new()),
436 Arc::new(SpinLock::new(FsStruct::new(None, None))),
437 )
438 }
439}
440
441impl Drop for Task {
442 fn drop(&mut self) {
443 pr_debug!("Dropping Task {}", self.tid);
444 }
445}
446// /// 关于任务的管理信息
447// /// 存放与调度器、任务状态、队列相关的、需要高频访问和修改的数据。
448// /// 主要由调度器子系统使用。
449// pub struct TaskInfo {}
450
451// /// 关于任务的资源信息
452// /// 存放与进程资源、内存管理、I/O 权限、用户 ID 等相关的、相对稳定或低频访问的数据。
453// /// 主要由内存管理子系统和权限管理子系统使用。
454// #[allow(dead_code)]
455// pub struct TaskStruct {}
456
457#[cfg(test)]
458mod tests {
459 use super::*;
460 use crate::{kassert, test_case};
461
462 // // 创建内核任务的基本属性检查
463 // test_case!(test_ktask_create, {
464 // let kstack_tracker = alloc_contig_frames(4).expect("kthread_spawn: failed to alloc kstack");
465 // let trap_frame_tracker = alloc_frame().expect("kthread_spawn: failed to alloc trap_frame");
466 // let t = Task::ktask_create(
467 // 1,
468 // 1,
469 // 0,
470 // Task::empty_children(),
471 // kstack_tracker,
472 // trap_frame_tracker,
473 // Arc::new(SpinLock::new(SignalHandlerTable::new())),
474 // SignalFlags::empty(),
475 // Arc::new(SpinLock::new(UtsNamespace::default())),
476 // Arc::new(SpinLock::new(RlimitStruct::new(INIT_RLIMITS))),
477 // Arc::new(FDTable::new()),
478 // );
479 // kassert!(t.tid == 1);
480 // kassert!(t.pid == t.tid);
481 // kassert!(t.is_kernel_thread());
482 // kassert!(t.is_process());
483 // kassert!(t.kstack_base != 0);
484 // kassert!(t.trap_frame_ptr.load(Ordering::SeqCst) as usize != 0);
485 // });
486
487 // new_dummy_task:应为内核线程,pid=tid,初始状态为 Running
488 test_case!(test_dummy_task_basic, {
489 let t = Task::new_dummy_task(7);
490 kassert!(t.tid == 7);
491 kassert!(t.pid == 7);
492 kassert!(t.is_kernel_thread());
493 kassert!(t.is_process());
494 kassert!(matches!(t.state, TaskState::Running));
495 });
496
497 // // is_process 与 is_kernel_thread 区分:人为创建一个“线程” pid!=tid
498 // test_case!(test_is_process_vs_thread, {
499 // let kstack_tracker = alloc_contig_frames(2).expect("alloc kstack");
500 // let trap_frame_tracker = alloc_frame().expect("alloc trap_frame");
501 // // 传入 pid 与 tid 不同模拟同进程内的线程
502 // let t = Task::ktask_create(
503 // 10,
504 // 5,
505 // 5,
506 // Task::empty_children(),
507 // kstack_tracker,
508 // trap_frame_tracker,
509 // Arc::new(SpinLock::new(SignalHandlerTable::new())),
510 // SignalFlags::empty(),
511 // Arc::new(SpinLock::new(UtsNamespace::default())),
512 // Arc::new(SpinLock::new(RlimitStruct::new(INIT_RLIMITS))),
513 // );
514 // kassert!(t.tid == 10);
515 // kassert!(t.pid == 5);
516 // kassert!(!t.is_process());
517 // kassert!(t.is_kernel_thread()); // 仍是内核线程(没有用户地址空间)
518 // });
519
520 // // init_user_trapframe_and_context:验证重新定位 trap_frame 指针与入口设置
521 // test_case!(test_init_user_trapframe_and_context, {
522 // let mut t = Task::new_dummy_task(3);
523 // let original_tf_ptr = t.trap_frame_ptr.load(Ordering::SeqCst) as usize;
524 // let user_entry = 0x5555_8888usize;
525 // let trampoline = 0xFFFF_FFC0_8020_9000usize;
526 // unsafe {
527 // t.init_user_trapframe_and_context(user_entry, trampoline);
528 // }
529 // let new_tf_ptr = t.trap_frame_ptr.load(Ordering::SeqCst) as usize;
530 // // 新 trap_frame 应位于内核栈顶下方 size_of::<TrapFrame>()
531 // let expect_ptr = t.kstack_base - size_of::<TrapFrame>();
532 // kassert!(new_tf_ptr == expect_ptr);
533 // kassert!(new_tf_ptr != original_tf_ptr);
534 // // 校验写入的 sepc
535 // let tf = unsafe { &*t.trap_frame_ptr.load(Ordering::SeqCst) };
536 // kassert!(tf.sepc == user_entry);
537 // // Context 设置
538 // kassert!(t.context.sp == t.kstack_base);
539 // kassert!(t.context.ra == trampoline);
540 // });
541
542 // // execve 前后的 TrapFrame 基本字段(不访问用户空间,只验证写入逻辑)
543 // test_case!(test_execve_basic_trapframe_setup, {
544 // // 构造内核任务再模拟成为用户任务:直接插入一个空的 MemorySpace(若出现 API 变化需调整)
545 // // 使用 zeroed MemorySpace 仅用于测试 trap_frame 字段写入,不触发实际页表操作
546 // let mut t = Task::new_dummy_task(11);
547 // // 伪造用户地址空间(测试目的:Some 即视为用户进程)
548 // // SAFETY: 仅在测试中使用,MemorySpace 零值不会被真正激活
549 // let dummy_space: Arc<MemorySpace> = unsafe { core::mem::zeroed() };
550 // t.memory_space = Some(dummy_space);
551
552 // let tf_ptr = t.trap_frame_ptr.load(Ordering::SeqCst);
553 // let entry = 0x1234_5678usize;
554 // let user_sp_high = t.kstack_base & !0xFF; // 构造一个“高地址”作为栈顶
555 // let argv = ["prog", "arg1"];
556 // let envp = ["KEY=VALUE"];
557 // // 调用 execve(由于 dummy_space 不会映射,不能访问用户页,仅验证不崩溃及字段设置)
558 // // 为避免实际用户页访问,这里将字符串数组长度设小,且不真正触发用户空间写(dummy 空页表会使 SUM 写失败时 panic,若失败则跳过此测试)
559 // // 如果出现页错误,可根据真实 MemorySpace API 替换为可映射测试空间。
560 // t.execve(unsafe { core::mem::zeroed() }, entry, user_sp_high, &argv, &envp);
561 // let tf_after = unsafe { &*tf_ptr };
562 // kassert!(tf_after.sepc == entry);
563 // kassert!(tf_after.x10_a0 == argv.len());
564 // kassert!(tf_after.x1_ra == 0);
565 // });
566}